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:
| Lesson | Rust | C program prints |
|---|---|---|
| 1. Compiling programs using igraph | example_1 → RandomGraphStats | Diameter of a random graph with average degree 2: 23 |
| 2. Creating your first graphs | example_2 → LatticePathLengths | Average path length (lattice): 15.0167, then 11.8142 once randomized |
| 3. Calculating various properties of graphs | example_3 → KarateCentralities | maximum 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_tfor integers andigraph_real_tfor reals: these arei64andf64in Rust. Vertex and edge ids areVertexIdandEdgeId(bothi64), counts areusize. - Graphs are
igraph_tobjects, which is exactly whatGraphis (a type alias enriched with methods). Generators such asGraph::erdos_renyi_game_gnmcreate them; where C callsigraph_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
- the degree of every vertex (
Graph::degree), - the closeness centrality (
Graph::closeness), - the betweenness centrality (
Graph::betweenness),
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§
- Karate
Centralities - The centrality maxima computed by lesson 3 (see
example_3). - Lattice
Path Lengths - 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(). - Random
Graph Stats - 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, ...].