Thanks to visit codestin.com
Credit goes to github.com

Skip to content

yamafaktory/hypergraphz

Repository files navigation

HypergraphZ

GitHub Actions Workflow Status PyPI

A fast, directed hypergraph library written in Zig, with Python bindings included.

In a regular graph an edge connects exactly two nodes. A hyperedge connects any number of vertices at once — making hypergraphs a natural fit wherever relationships involve more than two parties:

Domain Vertices Hyperedges
Academia researchers papers (all co-authors at once)
Biology proteins complexes, metabolic pathways
Chemistry molecules reactions (multiple reactants → products)
Finance accounts transactions (split payments, settlements)
Software packages commits, dependency sets
Networks devices multicast groups, subnets
Social people group chats, events, committees
Knowledge concepts ontology relations, semantic clusters
Logistics locations routes, shared shipments
ML / AI features co-occurrence sets, hypergraph neural nets

HypergraphZ adds directed semantics on top: consecutive vertex pairs within a hyperedge define a direction, enabling shortest-path queries, topological sort, and reachability over the same structure.

Highlights

  • Hyperedges can span zero, one, or many vertices — including self-loops and duplicates
  • Full algorithm suite: BFS/DFS, shortest path, PageRank, centrality, cut vertices, connected components, topological sort, transitive closure
  • Structural operations: dual, k-skeleton, line graph, star/clique expansion, incidence matrix, Laplacian
  • Python wheels ship a precompiled Zig core — no compiler needed at install time
  • Bulk insertion API (create_vertices, create_hyperedges) cuts Python FFI overhead ~10×

For Python users

How it works

The Python package is a thin binding over the same Zig core used by the native library — there is no Python reimplementation of the graph logic.

┌─────────────────────────────┐
│  Python (hypergraphz)       │  high-level API — Hypergraph, VertexQuery, …
├─────────────────────────────┤
│  ctypes                     │  FFI bridge — no C extension, no compilation step for users
├─────────────────────────────┤
│  C ABI (hgz_c_api.zig)      │  flat exported functions — hgz_add_vertex, hgz_find_shortest_path, …
├─────────────────────────────┤
│  HypergraphZ (Zig core)     │  all algorithms, memory management, type-safe generics
└─────────────────────────────┘

The shared library (libhypergraphz.so / .dylib / .dll) is compiled once and shipped inside the wheel. Data crosses the boundary as JSON (vertex and hyperedge payloads) and as plain integer ID arrays (all structural operations). For bulk insertion, create_vertices and create_hyperedges serialise an entire payload list in one call, reducing FFI crossings from N to 1 — see Performance below.

Installation

pip install hypergraphz
# or with uv
uv add hypergraphz

Pre-built wheels are available for Linux (x86_64, aarch64), macOS (x86_64, arm64), and Windows (x86_64).

Quick start

from hypergraphz import Hypergraph

g = Hypergraph()

# Add vertices and hyperedges
alice = g.create_vertex({"name": "alice", "age": 30})
bob   = g.create_vertex({"name": "bob",   "age": 25})
carol = g.create_vertex({"name": "carol", "age": 35})

collab = g.create_hyperedge({"type": "project"})
g.append_vertices(collab, [alice, bob, carol])

# Build the reverse index before querying
g.build()

# Shortest path
path = g.find_shortest_path(alice, carol)

# Fluent query builders
active = (
    g.vertices()
     .where(lambda d: d["age"] > 28)
     .data()
)

# Structural algorithms
scores, _, _ = g.compute_page_rank()
centrality    = g.compute_centrality()
components    = g.get_connected_components()

# Sub-graph operations return independent Hypergraph objects
sub  = g.get_vertex_induced_subhypergraph([alice, bob])
dual = g.get_dual()

API summary

Category Methods
Lifecycle build(), clear(), save(), load(), clone()
Vertices create_vertex(), get_vertex(), update_vertex(), delete_vertex(), count_vertices(), get_all_vertex_ids()
Hyperedges create_hyperedge(), get_hyperedge(), update_hyperedge(), delete_hyperedge(), count_hyperedges(), get_all_hyperedge_ids()
Relations append_vertices(), prepend_vertices(), insert_vertex(), insert_vertices(), delete_vertex_from_hyperedge(), delete_vertex_at_index()
Degree get_vertex_indegree(), get_vertex_outdegree()
Queries get_hyperedge_vertices(), get_vertex_hyperedges(), get_vertex_neighborhood(), get_intersections(), get_hyperedges_connecting(), get_endpoints(), get_orphan_vertices(), get_orphan_hyperedges()
Boolean is_connected(), is_reachable(), has_cycle(), is_k_uniform()
Traversal find_shortest_path(), find_all_paths(), bfs(), dfs(), random_walk()
Algorithms get_connected_components(), topological_sort(), find_cut_vertices(), compute_centrality(), compute_page_rank(), get_inclusions(), get_nestedness_profile()
Matrices to_incidence_matrix(), to_incidence_matrix_coo(), to_laplacian()
Sub-graphs get_dual(), get_k_skeleton(), get_vertex_induced_subhypergraph(), get_edge_induced_subhypergraph(), get_core(), expand_to_graph(), expand_to_star(), get_line_graph(), get_transitive_closure()
Fluent builders vertices()VertexQuery, hyperedges()HyperedgeQuery

Exceptions

All errors map to typed exceptions from hypergraphz:

Exception When raised
NotBuiltError Query requires build() first
VertexNotFoundError Vertex ID does not exist
HyperedgeNotFoundError Hyperedge ID does not exist
CycleDetectedError Operation requires a DAG
NoPathError No directed path exists
IndexOutOfBoundsError Insertion index out of range
NotEnoughVerticesError Operation needs more vertices

Performance

Benchmarks run with pytest-benchmark on an Intel Core i9-13900H, 64 GB RAM, CachyOS Linux (kernel 7.0.5), ReleaseFast shared library, Python 3.14.

Insertion — 1,000 hyperedges × 1,000 vertices

API Mean vs atomic
create_vertex per vertex (atomic) ~4,095 ms
create_vertex per vertex + append_vertices (batch append) ~2,554 ms 1.6×
create_hyperedges + create_vertices (bulk, single FFI call each) ~415 ms ~10×

The dominant cost in the atomic and batch cases is ctypes call overhead (~1–2 µs per crossing). create_hyperedges and create_vertices each replace a per-item loop with a single FFI call, serialising the entire payload list as one JSON array.

Queries (chain / shared-vertex graphs, after build())

Operation Mean
find_shortest_path — chain of 1,000 vertices ~148 µs
find_cut_vertices — chain of 1,000 vertices ~351 µs
get_vertex_indegree × 100 — each vertex in 1,000 hyperedges ~4.7 ms

For Zig users

Zig version

HypergraphZ currently requires Zig 0.17.0-dev.242+5d55999d2.

Usage

Add hypergraphz as a dependency to your build.zig.zon:

zig fetch --save https://github.com/yamafaktory/hypergraphz/archive/v0.1.0.tar.gz

Add hypergraphz as a dependency to your build.zig:

const hypergraphz = b.dependency("hypergraphz", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("hypergraphz", hypergraphz.module("hypergraphz"));

Example

examples/coauthorship.zig models a small research community as a directed hypergraph where vertices are researchers and hyperedges are papers. The first listed author is treated as the corresponding author, giving each hyperedge a natural direction.

zig build example

It walks through seventeen features of the library in sequence:

Section API What it shows
Papers per researcher getVertexHyperedges reverse-index query
Research communities getConnectedComponents two isolated groups with no cross-group papers
Betweenness centrality computeCentrality which researchers bridge the most collaboration paths
Degrees of separation findShortestPath 1–3 hops within a community; unreachable across communities
Dual: paper-centric view getDual swap vertices ↔ hyperedges to see each researcher's papers
Shared authorship getIntersections researchers present on every paper in a given set
Seniority ordering topologicalSort hierarchy implied by the authorship direction
Pairwise expansion expandToGraph 6 papers encode 11 directed pairs in a regular graph
Spectral view toLaplacian normalized Laplacian; block-diagonal under disjoint groups
PageRank computePageRank citation-weighted stationary distribution; sums to 1
Random walk randomWalk seeded weighted walk; stays inside the start's component
Star expansion expandToStar bipartite (researcher ↔ paper) projection; 2-uniform
Line graph getLineGraph papers as vertices, linked when they share an author
K-core decomposition getCore (s, t)-core peeling; trims the lone-paper researcher
Nestedness getInclusions strict-subset pairs across hyperedges; sized profile
Co-author neighborhoods getVertexNeighborhood undirected co-occurrence neighbors across all hyperedges

Performance

Benchmarks run with zig build bench -Doptimize=ReleaseFast on an Intel Core i9-13900H, 64 GB RAM, CachyOS Linux (kernel 7.0.5).

Insertion — 1,000 hyperedges × 1,000 vertices

API Time
createVertex per vertex (atomic) 77.7 ms
createVertex per vertex + appendVerticesToHyperedge (batch append) 70.4 ms
createHyperedges + createVertices (bulk, single call each) 47.6 ms
build() — construct reverse index over all 1,000,000 vertices 227.8 ms

Queries (chain / shared-vertex graphs, after build())

Operation Time
getVertexIndegree × 100 — each vertex in 1,000 hyperedges 422 µs
findShortestPath — chain of 1,000 vertices 232 µs
findCutVertices — chain of 1,000 vertices 414 µs

Documentation

The latest online documentation can be found here.

Packages

 
 
 

Contributors

Languages