xgi
xgi copied to clipboard
Add support for directed hypergraphs
It would be good to add a class that allows users to specify a directed hypergraph. I've seen several ways to do this, but not sure which is best.
Can you please comment on a couple of those ways? So we can start a discussion comparing and contrasting them.
A few ways that I've seen:
- Oriented hypergraphs with a labeling function specifying inputs/outputs formalized in Spectral classes of hypergraphs by Raffaella Mulas.
- Directed hypergraphs with head (output) and tail (input) subsets of a given hyperedge, where the head and tail may be overlapping formalized in Exchange Pattern Mining in the Bitcoin Transaction Directed Hypergraph by Ranshous et al.
There may be other papers discussing these topics, but this is what came to mind.
Thanks! We should seek what is the most general way of implementing this so it covers different cases.
We should think of implementing this after #82
An initial idea that I have about this is to modify the Hypergraph
class so that there are H._node_in
and H._node_out
and H._edge_in
and H._edge_out
dictionaries (Directed bipartite network) instead of H._node
and H._edge
. Ideally, I would like to then be able to define H.node.in_degree
and H.node.out_degree
as Stats objects that accept the "in" and "out" dicts respectively, but not sure what would need to change to make this possible.
but not sure what would need to change to make this possible.
Pretty much everything? Like, literally everything depends on the underlying _node
and _edge
dicts.
Fair enough. But perhaps at least initially, we could separately create directed versions of the views and the stats?
The other thing is that unless I'm mistaken, edge size is an undirected notion, whereas (for instance) the degrees would not be.
Some initial thoughts about the API for this:
H = xgi.DiHypergraph()
H.nodes.degree # sum of the in- and out-degree
H.nodes.in_degree
H.nodes.out_degree
H.edges.size
H.add_edge([{0, 1, 2}, {2, 3, 4}], id=0)
H.add_edge({"head": {0, 1, 2}, "tail": {2, 3, 4}}) # would this be better named as source/sink or source/target or something like that?
H.edges.size.asdict()[0] = 5
H.nodes.out_degree.as_dict()[0] = 1
xgi.adjacency(H) # A_ij = 1 if i is in the tail of an edge and j is in the head of an edge.
xgi.incidence(H) # I've seen this with +/- entries, but this won't work with the head/tail formalism.
xgi.is_connected(H)
xgi.is_connected(H, strongly=False) # run the connectedness on an undirected hypergraph
# many of the algorithms that we have won't work for directed hypergraphs.