Hypergraph is a data structure library to generate directed hypergraphs.
A hypergraph is a generalization of a graph in which a hyperedge can join any number of vertices.
This library aims at providing the necessary methods for modeling complex, multiway (non-pairwise) relational data found in complex networks. One of the main advantages of using a hypergraph model over a graph one is to provide a more flexible and natural framework to represent entities and their relationships (e.g. Alice uses some social network, shares some data to Bob, who shares it to Carol, etc).
This library enables you to represent:
- non-simple hypergraphs with two or more hyperedges containing the exact same set of vertices
- self-loops — i.e., hyperedges containing vertices directed to themselves one or more times
- unaries — i.e., hyperedges containing a unique vertex
And to compute:
- Graph traversal: BFS, DFS, reachability, topological sort, random walks
- Shortest paths: Dijkstra point-to-point and single-source
- Structural analysis: strongly connected components, weakly connected components, all simple paths, subgraph extraction, cycle detection, connectivity, transitive closure
- Filtered views:
retain_vertices,retain_hyperedges - Graph projections: incidence matrix (dense and COO sparse), Laplacian, line graph, dual hypergraph
- Analytics: PageRank, centrality scores (degree, closeness, betweenness), nestedness profile
- Generic query interface:
HypergraphQuerytrait works over bothHypergraphandPersistentHypergraph
Available on both Hypergraph and PersistentHypergraph via the HypergraphQuery trait.
| Method | Description |
|---|---|
count_vertices() / count_hyperedges() |
Number of elements |
is_empty() |
Whether the graph has any vertices |
vertex_indices() / hyperedge_indices() |
All stable indices |
get_vertex_weight(idx) / get_hyperedge_weight(idx) |
Weight lookup by index |
get_vertex_hyperedges(idx) |
Hyperedge indices that include a vertex |
get_hyperedge_vertices(idx) |
Ordered vertex list of a hyperedge |
| Method | Description |
|---|---|
contains_vertex(weight) |
Whether any vertex has the given weight |
get_vertex_index(weight) |
Indices of all vertices with the given weight |
find_hyperedges_by_weight(weight) |
Indices of all hyperedges with the given weight |
get_adjacent_vertices_from(v) |
Vertices directly reachable from v |
get_adjacent_vertices_to(v) |
Vertices with a direct edge into v |
get_full_adjacent_vertices_from(v) |
Neighbours from v paired with their connecting hyperedges |
get_full_adjacent_vertices_to(v) |
Predecessors of v paired with their connecting hyperedges |
get_full_vertex_hyperedges(v) |
Vertex lists of every hyperedge containing v |
get_vertex_degree_in(v) / get_vertex_degree_out(v) |
In/out degree |
get_hyperedges_intersections(edges) |
Shared vertices across multiple hyperedges |
get_hyperedges_connecting(from, to) |
Hyperedges that contain a directed from→to pair |
get_vertex_neighborhood(v) |
All co-members of v across every hyperedge it belongs to |
| Method | Description |
|---|---|
get_bfs(from) |
Breadth-first traversal order from a vertex |
get_dfs(from) |
Depth-first traversal order from a vertex |
is_reachable(from, to) |
Whether to is reachable from from |
get_all_paths(from, to) |
All simple paths between two vertices |
topological_sort() |
Kahn's algorithm; returns an error on cycles |
random_walk(from, steps, seed) |
Random walk of steps hops from a vertex |
| Method | Description |
|---|---|
get_dijkstra_connections(from, to) |
Cheapest path with hyperedge trace |
get_dijkstra_connections_with_cost(from, to) |
Same, plus the total cost |
get_dijkstra_from(from) |
Cheapest cost to every reachable vertex |
| Method | Description |
|---|---|
strongly_connected_components() |
Kosaraju's algorithm |
connected_components() |
Weakly connected components |
is_acyclic() |
Cycle detection |
find_cut_vertices() |
Articulation points via iterative Tarjan DFS |
subgraph(vertices) |
Induced subgraph over a vertex set |
is_connected() |
Whether the hypergraph is connected (clique-expansion BFS) |
get_transitive_closure() |
All directed reachability pairs (from, to) |
| Method | Description |
|---|---|
get_orphan_vertices() |
Vertices belonging to no hyperedge |
get_orphan_hyperedges() |
Hyperedges with an empty vertex list |
get_endpoints() |
(sources, sinks) — in-degree 0 / out-degree 0 |
get_inclusions() |
All proper subset/superset pairs of hyperedges |
is_k_uniform(k) |
Whether every hyperedge has exactly k vertices |
get_core(min_degree, min_size) |
k-core decomposition via iterative peeling |
get_nestedness_profile() |
Per-size inclusion statistics as Vec<NestednessEntry> |
| Method | Description |
|---|---|
expand_to_graph() |
Directed graph from consecutive vertex pairs |
expand_to_star() |
Bipartite vertex–hyperedge membership pairs |
to_incidence_matrix() |
Dense vertex × hyperedge incidence matrix |
to_incidence_matrix_coo() |
Sparse COO (row, col) pairs for the incidence matrix |
to_laplacian(normalized) |
Clique-expansion Laplacian (raw or normalized) |
get_line_graph() |
Pairs of hyperedges sharing at least one vertex |
get_dual() |
Dual hypergraph: per-vertex sorted list of incident hyperedges |
| Method | Description |
|---|---|
compute_page_rank(damping, iterations) |
Iterative PageRank power method |
compute_centrality(v) |
Degree, closeness, and betweenness centrality for a vertex |
| Method | Description |
|---|---|
new() / with_capacity(n) |
Create an empty graph |
add_vertex(weight) |
Add a vertex; returns its stable VertexIndex |
add_hyperedge(vertices, weight) |
Add a hyperedge; returns its stable HyperedgeIndex |
remove_vertex(idx) |
Remove a vertex and all hyperedges that contain it |
remove_hyperedge(idx) |
Remove a hyperedge |
update_vertex_weight(idx, weight) |
Replace a vertex's weight |
update_hyperedge_weight(idx, weight) |
Replace a hyperedge's weight |
update_hyperedge_vertices(idx, vertices) |
Replace a hyperedge's vertex list |
retain_vertices(predicate) |
Remove vertices that fail the predicate |
retain_hyperedges(predicate) |
Remove hyperedges that fail the predicate |
contract_hyperedge_vertices(edge, merge, into) |
Contract a set of vertices to one |
join_hyperedges(edges) |
Merge hyperedges into their union |
reverse_hyperedge(edge) |
Reverse the vertex ordering of a hyperedge |
clear_hyperedges() |
Remove all hyperedges, keeping vertices |
clear() |
Remove everything |
append_vertex_to_hyperedge(edge, vertex) |
Append a vertex to the end of a hyperedge |
prepend_vertex_to_hyperedge(edge, vertex) |
Prepend a vertex to the start of a hyperedge |
insert_vertex_into_hyperedge(edge, vertex, pos) |
Insert a vertex at a given position |
delete_vertex_from_hyperedge(edge, vertex) |
Remove the first occurrence of a vertex from a hyperedge |
split_hyperedge(edge, at, weight) |
Split a hyperedge at an index into two new hyperedges |
split_vertex(vertex, edges, weight) |
Create a new vertex replacing vertex in specified hyperedges |
merge_vertices(primary, secondaries, weight) |
Merge multiple vertices into one |
get_k_skeleton(k) |
Subhypergraph of all hyperedges with at most k vertices (stable indices) |
get_edge_induced_subhypergraph(edges) |
Subhypergraph induced by specified hyperedges (reassigned indices) |
| Method | Description |
|---|---|
iter() |
Borrowing iterator over (&HE, Vec<&V>) tuples |
vertices_iter() |
Iterator over (VertexIndex, &V) pairs |
hyperedges_iter() |
Iterator over (HyperedgeIndex, &HE) pairs |
into_iter() |
Consuming iterator over (HE, Vec<V>) tuples |
- 100% safe Rust
- Proper error handling
- Stable indexes for each hyperedge and each vertex — identity is the index, not the weight; duplicate weights are allowed on both sides
- Parallelism (with Rayon)
HypergraphQuery<V, HE>trait — implement 9 primitives to get all graph algorithms for free; use it for generic functions and trait objects that work with either backend- Optional
serdesupport (features = ["serde"]inCargo.toml) - Optional
persistencesupport (features = ["persistence"]inCargo.toml)
Add this to your Cargo.toml (replace current_version with the latest version of the library):
[dependencies]
hypergraph = "current_version"To enable disk-backed persistent graphs:
[dependencies]
hypergraph = { version = "current_version", features = ["persistence"] }The persistence feature unlocks PersistentHypergraph, a disk-backed variant built on an LSM-tree (via fjall) with an in-memory hot-data cache. It supports graphs that exceed available RAM and survives process restarts without any manual serialization step.
use std::sync::Arc;
use hypergraph::PersistentHypergraph;
// Opens the database directory, or creates it if it doesn't exist.
let g = Arc::new(PersistentHypergraph::<MyVertex, MyEdge>::open("/var/data/my-graph")?);
// All write methods take &self — share freely across threads.
let g2 = Arc::clone(&g);
std::thread::spawn(move || {
g2.add_vertex(my_vertex)?;
Ok(())
});Vertex and hyperedge types must implement serde::Serialize + serde::DeserializeOwned in addition to the usual trait bounds.
A bounded LRU cache (via quick-cache) sits in front of the disk store, keeping hot vertex weights and hyperedges in memory. The default capacity is 10 000 entries per layer; use PersistentHypergraph::open_with_capacity to tune it for your workload.
Please read the documentation to get started.