Skip to main content

Module adjlist

Module adjlist 

Source
Expand description

Adjacency and incidence lists (igraph_adjlist.h).

Many algorithms visit the neighbors of every vertex over and over again (shortest paths from all sources, closeness, triangle counting, rewiring, …). For them it pays off to extract the graph once into a list of vectors, one per vertex, and work on that. igraph offers four such structures, all wrapped here as owned Rust types that free their memory on Drop:

Rust typeC typecontents of list vbuilt
AdjListigraph_adjlist_tneighbor vertex ids of veagerly, all vertices
IncListigraph_inclist_tincident edge ids of veagerly, all vertices
LazyAdjListigraph_lazy_adjlist_tneighbor vertex ids of von first access of v
LazyIncListigraph_lazy_inclist_tincident edge ids of von first access of v

AdjList and IncList are independent of the graph after creation: the graph may be modified or dropped, and the lists may be freely edited (each entry is a VectorInt, so it can grow and shrink) without affecting the graph. This makes them the ideal scratch representation for heavy structural edits: extract with Graph::adjlist_init, edit the lists in O(1) or O(d) per operation, then rebuild a graph with AdjList::to_graph (igraph_adjlist), paying O(|V|+|E|) only once.

The lazy variants instead borrow the graph (the borrow checker enforces that the graph outlives them and is not mutated meanwhile) and query the neighbors of a vertex only the first time it is asked for, caching the result. They are handy for algorithms that may visit only a small part of a large graph.

§Rusty access

  • al[v] gives the neighbors of vertex v as a &[i64] slice (Index), al[v][i] = x edits in place (IndexMut);
  • AdjList::get_mut gives the underlying VectorInt to push, pop, sort or resize a list;
  • AdjList::iter / for list in &al iterate over the lists;
  • AdjList::to_vecs and Vec::<Vec<i64>>::from(al) convert to nested vectors, and AdjList::from(vec![...]) / .collect() build one from Rust data;
  • Display prints one line per vertex, exactly like igraph’s igraph_adjlist_print.

§Collapsing multi-edges

With multiple = false, Graph::adjlist_init and Graph::lazy_adjlist_init list each neighbor once. In igraph 1.0.0 and 1.0.1 this is buggy when neighbors are gathered in both directions (mode All, or undirected graphs): mutual pairs u -> w, w -> u and single self-loops are mistaken for multi-edges, which corrupts the graph’s cached Graph::has_multiple answer, and the lists themselves depend on that cache. These wrappers collapse such lists on the Rust side instead, so the result always matches Graph::neighbors_with and the cache stays correct.

§Example

use igraph::prelude::*;
use igraph::adjlist::AdjList;

// A directed triangle 0 -> 1 -> 2 -> 0 with an extra edge 0 -> 2.
let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 0), (0, 2)], 3, true).unwrap();

let out = g.adjlist_init(NeighborMode::Out, Loops::Twice, true).unwrap();
assert_eq!(out.len(), 3);
assert_eq!(&out[0], &[1, 2]);
assert_eq!(out.to_vecs(), vec![vec![1, 2], vec![2], vec![0]]);

// Incoming neighbors, then the edge ids incident to each vertex.
let inc = g.adjlist_init(NeighborMode::In, Loops::Twice, true).unwrap();
assert_eq!(&inc[2], &[0, 1]);
let il = g.inclist_init(NeighborMode::Out, Loops::Twice).unwrap();
assert_eq!(&il[0], &[0, 3]);

// Edit the adjacency list and turn it back into a graph: drop 2 -> 0.
let mut al: AdjList = out.clone();
al.get_mut(2).unwrap().clear();
al.get_mut(0).unwrap().push(0); // and add a self-loop on 0
let h = al.to_graph(NeighborMode::Out, false).unwrap();
assert_eq!(h.ecount(), 4);
assert_eq!(h.neighbors(0, NeighborMode::Out).unwrap(), vec![0, 1, 2]);

// Lazy lists query the graph only when asked to.
let mut lazy = g.lazy_adjlist_init(NeighborMode::All, Loops::Twice, false).unwrap();
assert!(!lazy.has(0));
assert_eq!(lazy.get(0).unwrap(), &[1, 2]);
assert!(lazy.has(0));

// Zachary's karate club: the handshake lemma, and the two hubs.
let karate = Graph::famous("Zachary").unwrap();
let al = karate.adjlist_init(NeighborMode::All, Loops::Twice, true).unwrap();
assert_eq!(al.total_len(), 2 * karate.ecount());
assert_eq!((al[0].len(), al[33].len()), (16, 17));

§Functions of igraph_adjlist.h

C functionRust
igraph_adjlist_initGraph::adjlist_init, AdjList::new
igraph_adjlist_init_emptyAdjList::init_empty
igraph_adjlist_init_complementerGraph::adjlist_init_complementer, AdjList::complementer
igraph_adjlist_init_from_inclistGraph::adjlist_init_from_inclist, AdjList::from_inclist
igraph_adjlist_destroyDrop
igraph_adjlist_sizeAdjList::len
igraph_adjlist_clearAdjList::clear
igraph_adjlist_sortAdjList::sort
igraph_adjlist_simplifyAdjList::simplify
igraph_adjlist_print / _fprintAdjList::print, AdjList::fprint, Display
igraph_adjlist_has_edgeAdjList::has_edge
igraph_adjlist_replace_edgeAdjList::replace_edge
igraph_adjlist_get (macro)Index, AdjList::get, AdjList::get_mut
igraph_adjlistGraph::adjlist, AdjList::to_graph
igraph_inclist_initGraph::inclist_init, IncList::new
igraph_inclist_init_emptyIncList::init_empty
igraph_inclist_destroyDrop
igraph_inclist_sizeIncList::len
igraph_inclist_clearIncList::clear
igraph_inclist_print / _fprintIncList::print, IncList::fprint, Display
igraph_inclist_get (macro)Index, IncList::get, IncList::get_mut
igraph_lazy_adjlist_initGraph::lazy_adjlist_init, LazyAdjList::new
igraph_lazy_adjlist_destroyDrop
igraph_lazy_adjlist_clearLazyAdjList::clear
igraph_lazy_adjlist_sizeLazyAdjList::len
igraph_lazy_adjlist_has (macro)LazyAdjList::has
igraph_lazy_adjlist_get (macro)LazyAdjList::get, LazyAdjList::get_mut
igraph_lazy_inclist_initGraph::lazy_inclist_init, LazyIncList::new
igraph_lazy_inclist_destroyDrop
igraph_lazy_inclist_clearLazyIncList::clear
igraph_lazy_inclist_sizeLazyIncList::len
igraph_lazy_inclist_has (macro)LazyIncList::has
igraph_lazy_inclist_get (macro)LazyIncList::get, LazyIncList::get_mut

§See also

The igraph C documentation of adjacency lists describes the underlying structures.

Structs§

Iter
Iterator over the per-vertex lists of an AdjList or IncList, yielding each list as a slice (returned by AdjList::iter and IncList::iter).
LazyAdjList
Lazy adjacency list (igraph_lazy_adjlist_t) borrowing a graph: the neighbors of each vertex are queried on first access and cached.
LazyIncList
Lazy incidence list (igraph_lazy_inclist_t) borrowing a graph: the incident edges of each vertex are queried on first access and cached.

Type Aliases§

AdjList
Owned adjacency list (igraph_adjlist_t): for each vertex, a vector of its neighbor vertex ids. See the module docs.
IncList
Owned incidence list (igraph_inclist_t): for each vertex, a vector of the ids of its incident edges. See the module docs.