Getting started with hypergraphs

Hypergraphs generalise standard graphs by allowing edges to contain any number of vertices. Reticula provides simple ways of generating and inspecting them. Reticula provides both directed and undirected hypergraphs. Make sure you have installed the library with pip install reticula and imported it as ret:

>>> import reticula as ret

Creating a random hypergraph

Let’s stat with a simple example of a random hypergraph. The function random_uniform_hypergraph() generates a hypergraph with a given number of vertices, edges, and edge degree, each edge existing independently with a given probability. It requires a pseudo random number generator, which we create here with mersenne_twister():

>>> gen = ret.mersenne_twister(42)
>>> h = ret.random_uniform_hypergraph[ret.int64](
...     size=100, edge_degree=3, edge_prob=0.01, random_state=gen)
>>> h
<undirected_hypergraph[int64] with 100 verts and 1659 edges>

Examining the structure

Edges and vertices are again simple Python lists:

>>> h.vertices()[:5]
[0, 1, 2, 3, 4]
>>> h.edges()[:2]
[undirected_hyperedge[int64]([0, 3, 96]), undirected_hyperedge[int64]([0, 4, 11])]
>>> len(h.edges())
1659

Hypergraph degrees count how many hyperedges a vertex belongs to:

>>> ret.degree(h, 0)
3

Since hypergraph h is undirected, the degree of a vertex is the same as its in- and out-degree:

>>> ret.in_degree(h, 0)
3
>>> ret.out_degree(h, 0)
3
>>> ret.incident_degree(h, 0)
3

You can also probe each edge, for example to find out how many vertices it contains, using edge_degree(). This is also known as the edge degree or edge rank:

>>> e = h.edges()[0]
>>> e
undirected_hyperedge[int64]([0, 3, 96])
>>> ret.edge_degree(e)
3
This also provices directed variants, but they are identical for undirected hypergraphs::
>>> ret.in_edge_degree(e)
3
>>> ret.out_edge_degree(e)
3

Hyperedge mutators and mutated vertices work similarly to undirected edges in dyadic networks. The mutator vertices are those that can change the state of the other vertices through the hyperedge, while the mutated vertices are those whose state can change because of the mutators. For undirected hyperedges, all vertices incident to the hyperedge can act as mutators or mutated vertices:

>>> e.mutator_verts()
[0, 3, 96]
>>> e.mutated_verts()
[0, 3, 96]
>>> e.incident_verts()
[0, 3, 96]

For directed hyperedges, the mutator and mutated vertices can be different:

>>> e = ret.directed_hyperedge[int64]([1, 2, 3], [4, 5, 6])
>>> e.mutator_verts()
[1, 2, 3]
>>> e.tails()
[1, 2, 3]

>>> e.mutated_verts()
[4, 5, 6]
>>> e.heads()
[4, 5, 6]

>>> e.incident_verts()
[1, 2, 3, 4, 5, 6]

Connected components

Connected components work exactly the same as for dyadic static graphs:

>>> comps = ret.connected_components(h)
>>> comps
[<component[int64] of 100 nodes: {99, 98, 97, 96, 95, ...})>]
>>> len(comps)
1