Skip to main content

Module tutorial

Module tutorial 

Source
Expand description

Translations of the igraph C tutorial into Rust.

The igraph C reference manual opens with a tutorial made of three short lessons, whose programs live in examples/tutorial/tutorial{1,2,3}.c of the igraph sources. This module translates each of them, one public function per lesson, keeping the same steps in the same order (and hence the same pseudo-random draws), so that the Rust versions compute exactly the numbers printed by the C programs with igraph 1.0.1:

LessonRustC program prints
1. Compiling programs using igraphexample_1 → RandomGraphStatsDiameter of a random graph with average degree 2: 23
2. Creating your first graphsexample_2 → LatticePathLengthsAverage path length (lattice): 15.0167, then 11.8142 once randomized
3. Calculating various properties of graphsexample_3 → KarateCentralitiesmaximum degree 17, closeness 0.0172414, betweenness 231.071

Every result struct implements Display reproducing, character by character, the lines printed by the corresponding C program (including C’s %g number formatting), so the translation can be checked against the original at a glance:

use igraph::tutorial;

println!("{}", tutorial::example_1()?);
println!("{}", tutorial::example_2()?);
println!("{}", tutorial::example_3()?);
assert_eq!(
    tutorial::example_1()?.to_string(),
    "Diameter of a random graph with average degree 2: 23"
);

§Lesson 1: compiling programs using igraph

The first program generates a random graph and prints its diameter and mean degree. The C tutorial uses it to illustrate a few points, and each of them has a Rust counterpart:

  • C programs include igraph.h; in Rust, use igraph::prelude::*; brings the graph type, the containers and the enums into scope.
  • C programs must call igraph_setup() before anything else. The Rust bindings do it for you: every call into igraph first makes sure the library (and the calling thread’s error handler and random number generator) is initialized.
  • igraph uses igraph_int_t for integers and igraph_real_t for reals: these are i64 and f64 in Rust. Vertex and edge ids are VertexId and EdgeId (both i64), counts are usize.
  • Graphs are igraph_t objects, which is exactly what Graph is (a type alias enriched with methods). Generators such as Graph::erdos_renyi_game_gnm create them; where C calls igraph_destroy(), Rust frees the graph automatically when it goes out of scope.
  • C functions return an error code; the Rust methods return a Result, propagated with ?.

The igraph tutorial then explains how to compile the program with CMake or pkg-config; here cargo build takes care of it (the build script finds the installed igraph library and generates the raw bindings).

§Lesson 2: creating your first graphs

Functions creating graphs are called generators; randomized ones are called games. Deterministic regular structures include stars (Graph::star), cycles (Graph::cycle_graph), lattices (Graph::square_lattice) and trees (Graph::kary_tree). Most generators, and most other functions, handle both directed and undirected graphs.

The second program builds a 30 × 30 periodic square lattice (a torus), computes the average shortest path length, adds ten random edges and computes it again: a handful of random “shortcuts” shrinks the average distance a lot (from about 15 to about 11.8), the essence of the small-world effect.

In C, igraph uses its own vector types (igraph_vector_t, igraph_vector_int_t, igraph_vector_bool_t, …) instead of plain arrays, initialized with igraph_vector_init() and destroyed with igraph_vector_destroy(). The Rust bindings accept slices as inputs and return Vecs as outputs (the owned igraph vectors, such as VectorInt, exist too and free themselves on drop). Vertices are identified by ids 0..n, where n is Graph::vcount. Graph::add_edges takes (from, to) pairs, whereas the C igraph_add_edges() takes a flat vector of endpoints (Graph::add_edges_from_vector is its literal counterpart).

As the tutorial warns, drawing random endpoints may create loop edges (from a vertex to itself) and multi-edges (several edges between the same pair of vertices). igraph graphs can represent them, but some functions expect simple graphs: Graph::simplify removes them. (With seed 42 the ten edges drawn by lesson 2, see LatticePathLengths::random_edges, happen to keep the lattice simple, although vertex 885 is drawn twice in a row, as the endpoint of two different edges.)

§Lesson 3: calculating various properties of graphs

The third program computes three centrality measures on the friendship network of Zachary’s karate club: how central the position of every member is. It builds the graph from a plain array of endpoints (ZACHARY_KARATE_EDGES, with Graph::from_flat_edges; C creates a non-owning view of the array with igraph_vector_int_view(), which the Rust bindings do internally), then computes

and prints the largest value of each, with the vertex attaining it. The instructor (vertex 0) and the administrator (vertex 33) stand out.

In C, the argument igraph_vss_all() is a vertex selector asking for the property of every vertex; in Rust it is VertexSelector::All, or simply the full range .. (see crate::selector for the other selectors).

Structs§

KarateCentralities
The centrality maxima computed by lesson 3 (see example_3).
LatticePathLengths
The numbers computed by lesson 2 (see example_2).
Maximum
The maximum of a per-vertex measure and the vertex attaining it, the Rust counterpart of the C pair igraph_vector_max() / igraph_vector_which_max().
RandomGraphStats
The numbers computed by lesson 1 (see example_1).

Constants§

ZACHARY_KARATE_EDGES
The friendship network of Zachary’s karate club as the flat endpoint array of the C tutorial (lesson 3): 78 undirected edges among 34 members, [from0, to0, from1, to1, ...].

Functions§

example_1
Lesson 1: the diameter and mean degree of a random graph.
example_2
Lesson 2: average path length of a lattice, before and after adding a few random edges.
example_3
Lesson 3: degree, closeness and betweenness centrality in Zachary’s karate club.