xgi.core.hypergraph.Hypergraph

class xgi.core.hypergraph.Hypergraph(incoming_data=None, **attr)[source]

Bases: object

A hypergraph is a collection of subsets of a set of nodes or vertices.

A hypergraph is a pair \((V, E)\), where \(V\) is a set of elements called nodes or vertices, and \(E\) is a set whose elements are subsets of \(V\), that is, each \(e \in E\) satisfies \(e \subset V\). The elements of \(E\) are called hyperedges or simply edges.

The Hypergraph class allows any hashable object as a node and can associate attributes to each node, edge, or the hypergraph itself, in the form of key/value pairs. In this representation, multiedges are allowed.

Parameters:
  • incoming_data (input hypergraph data, optional) –

    Data to initialize the hypergraph. If None (default), an empty hypergraph is created, i.e. one with no nodes or edges. The data can be in the following formats:

    • hyperedge list

    • hyperedge dictionary

    • 2-column Pandas dataframe (bipartite edges)

    • Incidence matrix: numpy ndarray or scipy.sparse array

    • Hypergraph object

    • SimplicialComplex object

  • **attr (dict, optional) – Attributes to add to the hypergraph as key, value pairs. By default, None.

Notes

Unique IDs are assigned to each node and edge internally and are used to refer to them throughout.

The attr keyword arguments are added as hypergraph attributes. To add node or edge attributes see add_node() and add_edge().

In addition to the methods listed in this page, other methods defined in the stats package are also accessible via the Hypergraph class. For more details, see the tutorial.

Examples

>>> import xgi
>>> H = xgi.Hypergraph([[1, 2, 3], [4], [5, 6], [6, 7, 8]])
>>> H.nodes
NodeView((1, 2, 3, 4, 5, 6, 7, 8))
>>> H.edges
EdgeView((0, 1, 2, 3))

Attributes

edges

An EdgeView of this network.

nodes

A NodeView of this network.

num_edges

The number of edges in the hypergraph.

num_nodes

The number of nodes in the hypergraph.

is_frozen

Checks whether a dihypergraph is frozen

Methods that modify the structure

add_node

Add one node with optional attributes.

add_edge

Add one edge with optional attributes.

add_nodes_from

Add multiple nodes with optional attributes.

add_edges_from

Add multiple edges with optional attributes.

add_node_to_edge

Add one node to an existing edge.

add_weighted_edges_from

Add multiple weighted edges with optional attributes.

set_node_attributes

Sets node attributes from a given value or dictionary of values.

set_edge_attributes

Set the edge attributes from a value or a dictionary of values.

update

Add nodes or edges to the hypergraph.

remove_node

Remove a single node.

remove_edge

Remove one edge.

remove_nodes_from

Remove multiple nodes.

remove_edges_from

Remove multiple edges.

remove_node_from_edge

Remove a node from an existing edge.

clear

Remove all nodes and edges from the graph.

clear_edges

Remove all edges from the graph without altering any nodes.

merge_duplicate_edges

Merges edges which have the same members.

cleanup

Removes potentially undesirable artifacts from the hypergraph.

freeze

Method for freezing a hypergraph which prevents it from being modified

double_edge_swap

Swap the edge memberships of two selected nodes, given two edges.

random_edge_shuffle

Randomly redistributes nodes between two hyperedges.

Methods that return other hypergraphs

copy

A deep copy of the hypergraph.

dual

The dual of the hypergraph.

add_edge(members, id=None, **attr)[source]

Add one edge with optional attributes.

Parameters:
  • members (Iterable) – An iterable of the ids of the nodes contained in the new edge.

  • id (hashable, optional) – Id of the new edge. If None (default), a unique numeric ID will be created.

  • **attr (dict, optional) – Attributes of the new edge.

Raises:

XGIError – If members is empty.

See also

add_edges_from

Add a collection of edges.

set_edge_attributes

Examples

Add edges with or without specifying an edge id.

>>> import xgi
>>> H = xgi.Hypergraph()
>>> H.add_edge([1, 2, 3])
>>> H.add_edge([3, 4], id='myedge')
>>> H.edges
EdgeView((0, 'myedge'))

Access attributes using square brackets. By default no attributes are created.

>>> H.edges[0]
{}
>>> H.add_edge([1, 4], color='red', place='peru')
>>> H.edges
EdgeView((0, 'myedge', 1))
>>> H.edges[1]
{'color': 'red', 'place': 'peru'}
add_edges_from(ebunch_to_add, **attr)[source]

Add multiple edges with optional attributes.

Parameters:
  • ebunch_to_add (Iterable) –

    An iterable of edges. This may be an iterable of iterables (Format 1), where each element contains the members of the edge specified as valid node IDs. Alternatively, each element could also be a tuple in any of the following formats:

    • Format 2: 2-tuple (members, edge_id), or

    • Format 3: 2-tuple (members, attr), or

    • Format 4: 3-tuple (members, edge_id, attr),

    where members is an iterable of node IDs, edge_id is a hashable to use as edge ID, and attr is a dict of attributes. Finally, ebunch_to_add may be a dict of the form {edge_id: edge_members} (Format 5).

    Formats 2 and 3 are unambiguous because attr dicts are not hashable, while id`s must be. In Formats 2-4, each element of `ebunch_to_add must have the same length, i.e. you cannot mix different formats. The iterables containing edge members cannot be strings.

  • attr (**kwargs, optional) – Additional attributes to be assigned to all edges. Attribues specified via ebunch_to_add take precedence over attr.

See also

add_edge

Add a single edge.

add_weighted_edges_from

Convenient way to add weighted edges.

set_edge_attributes

Notes

Adding the same edge twice will create a multi-edge. Currently cannot add empty edges; the method skips over them.

Examples

>>> import xgi
>>> H = xgi.Hypergraph()

When specifying edges by their members only, numeric edge IDs will be assigned automatically.

>>> H.add_edges_from([[0, 1], [1, 2], [2, 3, 4]])
>>> H.edges.members(dtype=dict)
{0: {0, 1}, 1: {1, 2}, 2: {2, 3, 4}}

Custom edge ids can be specified using a dict.

>>> H = xgi.Hypergraph()
>>> H.add_edges_from({'one': [0, 1], 'two': [1, 2], 'three': [2, 3, 4]})
>>> H.edges.members(dtype=dict)
{'one': {0, 1}, 'two': {1, 2}, 'three': {2, 3, 4}}

You can use the dict format to easily add edges from another hypergraph.

>>> H2 = xgi.Hypergraph()
>>> H2.add_edges_from(H.edges.members(dtype=dict))
>>> H.edges == H2.edges
True

Alternatively, edge ids can be specified using an iterable of 2-tuples.

>>> H = xgi.Hypergraph()
>>> H.add_edges_from([([0, 1], 'one'), ([1, 2], 'two'), ([2, 3, 4], 'three')])
>>> H.edges.members(dtype=dict)
{'one': {0, 1}, 'two': {1, 2}, 'three': {2, 3, 4}}

Attributes for each edge may be specified using a 2-tuple for each edge. Numeric IDs will be assigned automatically.

>>> H = xgi.Hypergraph()
>>> edges = [
...     ([0, 1], {'color': 'red'}),
...     ([1, 2], {'age': 30}),
...     ([2, 3, 4], {'color': 'blue', 'age': 40}),
... ]
>>> H.add_edges_from(edges)
>>> {e: H.edges[e] for e in H.edges}
{0: {'color': 'red'}, 1: {'age': 30}, 2: {'color': 'blue', 'age': 40}}

Attributes and custom IDs may be specified using a 3-tuple for each edge.

>>> H = xgi.Hypergraph()
>>> edges = [
...     ([0, 1], 'one', {'color': 'red'}),
...     ([1, 2], 'two', {'age': 30}),
...     ([2, 3, 4], 'three', {'color': 'blue', 'age': 40}),
... ]
>>> H.add_edges_from(edges)
>>> {e: H.edges[e] for e in H.edges}
{'one': {'color': 'red'}, 'two': {'age': 30}, 'three': {'color': 'blue', 'age': 40}}
add_node(node, **attr)[source]

Add one node with optional attributes.

Parameters:
  • node (node) – A node can be any hashable Python object except None.

  • attr (keyword arguments, optional) – Set or change node attributes using key=value.

Notes

If node is already in the hypergraph, its attributes are still updated.

add_node_to_edge(edge, node)[source]

Add one node to an existing edge.

If the node or edge IDs do not exist, they are created.

Parameters:
  • edge (hashable) – edge ID

  • node (hashable) – node ID

Examples

>>> import xgi
>>> H = xgi.Hypergraph()
>>> H.add_edge(['apple', 'banana'], 'fruits')
>>> H.add_node_to_edge('fruits', 'pear')
>>> H.add_node_to_edge('veggies', 'lettuce')
>>> d = H.edges.members(dtype=dict)
>>> {id: sorted(list(e)) for id, e in d.items()}
{'fruits': ['apple', 'banana', 'pear'], 'veggies': ['lettuce']}
add_nodes_from(nodes_for_adding, **attr)[source]

Add multiple nodes with optional attributes.

Parameters:
  • nodes_for_adding (iterable) – An iterable of nodes (list, dict, set, etc.). OR An iterable of (node, attribute dict) tuples. Node attributes are updated using the attribute dict.

  • attr (keyword arguments, optional (default= no attributes)) – Update attributes for all nodes in nodes. Node attributes specified in nodes as a tuple take precedence over attributes specified via keyword arguments.

add_weighted_edges_from(ebunch, weight='weight', **attr)[source]

Add multiple weighted edges with optional attributes.

Parameters:
  • ebunch_to_add (iterable of edges) – Each edge given in the list or container will be added to the graph. The edges must be given as tuples of the form (node1, node2, …, noden, weight).

  • weight (string, optional) – The attribute name for the edge weights to be added, by default “weight”.

  • attr (keyword arguments, optional) – Edge attributes to add/update for all edges.

See also

add_edge

Add a single edge.

add_edges_from

Add multiple edges.

set_edge_attributes, get_edge_attributes

Notes

Adding the same edge twice creates a multiedge.

Examples

>>> import xgi
>>> H = xgi.Hypergraph()
>>> edges = [(0, 1, 0.3), (0, 2, 0.8)]
>>> H.add_weighted_edges_from(edges)
>>> H.edges[0]
{'weight': 0.3}
cleanup(isolates=False, singletons=False, multiedges=False, connected=True, relabel=True, in_place=True)[source]

Removes potentially undesirable artifacts from the hypergraph.

Parameters:
  • isolates (bool, optional) – Whether isolated nodes are allowed, by default False.

  • singletons (bool, optional) – Whether singleton edges are allowed, by default False.

  • multiedges (bool, optional) – Whether multiedges are allowed, by default False.

  • connected (bool, optional) – Whether the returned hypergraph should be connected. If true, returns the hypergraph induced on the largest connected component. By default, False.

  • relabel (bool, optional) – Whether to convert all node and edge labels to sequential integers, by default True.

  • in_place (bool, optional) – Whether to modify the current hypergraph or output a new one, by default True.

clear(hypergraph_attr=True)[source]

Remove all nodes and edges from the graph.

Also removes node and edge attributes, and optionally hypergraph attributes.

Parameters:

hypergraph_attr (bool, optional) – Whether to remove hypergraph attributes as well. By default, True.

clear_edges()[source]

Remove all edges from the graph without altering any nodes.

copy()[source]

A deep copy of the hypergraph.

A deep copy of the hypergraph, including node, edge, and hypergraph attributes.

Returns:

H – A copy of the hypergraph.

Return type:

Hypergraph

double_edge_swap(n_id1, n_id2, e_id1, e_id2)[source]

Swap the edge memberships of two selected nodes, given two edges.

Parameters:
  • n_id1 (hashable) – The ID of the first node, originally a member of the first edge.

  • n_id2 (hashable) – The ID of the second node, originally a member of the second edge.

  • e_id1 (hashable) – The ID of the first edge.

  • e_id2 (hashable) – The ID of the second edge.

Raises:
  • IDNotFound – If user specifies nodes or edges that do not exist or nodes that are not part of edges.

  • XGIError – If the swap does not preserve edge sizes.

Examples

>>> import xgi
>>> H = xgi.Hypergraph([[1, 2, 3], [3, 4]])
>>> H.double_edge_swap(1, 4, 0, 1)
>>> H.edges.members()
[{2, 3, 4}, {1, 3}]
dual()[source]

The dual of the hypergraph.

In the dual, nodes become edges and edges become nodes.

Returns:

The dual of the hypergraph.

Return type:

Hypergraph

property edges

An EdgeView of this network.

freeze()[source]

Method for freezing a hypergraph which prevents it from being modified

See also

frozen

Method that raises an error when a user tries to modify the hypergraph

is_frozen

Check whether a hypergraph is frozen

Examples

>>> import xgi
>>> edges = [[1, 2], [2, 3, 4]]
>>> H = xgi.Hypergraph(edges)
>>> H.freeze()
>>> H.add_node(5)
Traceback (most recent call last):
xgi.exception.XGIError: Frozen higher-order network can't be modified
property is_frozen

Checks whether a dihypergraph is frozen

Returns:

True if hypergraph is frozen, false if not.

Return type:

bool

See also

freeze

A method to prevent a hypergraph from being modified.

Examples

>>> import xgi
>>> edges = [[1, 2], [2, 3, 4]]
>>> H = xgi.Hypergraph(edges)
>>> H.freeze()
>>> H.is_frozen
True
merge_duplicate_edges(rename='first', merge_rule='first', multiplicity=None)[source]

Merges edges which have the same members.

Parameters:
  • rename (str, optional) – Either “first” (default), “tuple”, or “new”. If “first”, the new edge ID is the first of the sorted duplicate edge IDs. If “tuple”, the new edge ID is a tuple of the sorted duplicate edge IDs. If “new”, a new ID will be selected automatically.

  • merge_rule (str, optional) – Either “first” (default) or “union”. If “first”, takes the attributes of the first duplicate. If “union”, takes the set of attributes of all the duplicates.

  • multiplicity (str, optional) – The attribute in which to store the multiplicity of the hyperedge, by default None.

Raises:

XGIError – If invalid rename or merge_rule specified.

Warns:
  • If the user chooses merge_rule=”union”. Tells the

  • user that they can no longer draw based on this stat.

Examples

>>> import xgi
>>> edges = [{1, 2}, {1, 2}, {1, 2}, {3, 4, 5}, {3, 4, 5}]
>>> edge_attrs = dict()
>>> edge_attrs[0] = {"color": "blue"}
>>> edge_attrs[1] = {"color": "red", "weight": 2}
>>> edge_attrs[2] = {"color": "yellow"}
>>> edge_attrs[3] = {"color": "purple"}
>>> edge_attrs[4] = {"color": "purple", "name": "test"}
>>> H = xgi.Hypergraph(edges)
>>> H.set_edge_attributes(edge_attrs)
>>> H.edges
EdgeView((0, 1, 2, 3, 4))

There are several ways to rename the duplicate edges after merging:

  1. The merged edge ID is the first duplicate edge ID.

>>> H1 = H.copy()
>>> H1.merge_duplicate_edges()
>>> H1.edges
EdgeView((0, 3))
  1. The merged edge ID is a tuple of all the duplicate edge IDs.

>>> H2 = H.copy()
>>> H2.merge_duplicate_edges(rename="tuple")
>>> H2.edges
EdgeView(((0, 1, 2), (3, 4)))
  1. The merged edge ID is assigned a new edge ID.

>>> H3 = H.copy()
>>> H3.merge_duplicate_edges(rename="new")
>>> H3.edges
EdgeView((5, 6))

We can also specify how we would like to combine the attributes of the merged edges:

  1. The attributes are the attributes of the first merged edge.

>>> H4 = H.copy()
>>> H4.merge_duplicate_edges()
>>> H4.edges[0]
{'color': 'blue'}

2. The attributes are the union of every attribute that each merged edge has. If a duplicate edge doesn’t have that attribute, it is set to None.

>>> H5 = H.copy()
>>> H5.merge_duplicate_edges(merge_rule="union")
>>> H5.edges[0] == {'color': {'blue', 'red', 'yellow'}, 'weight':{2, None}}
True

3. We can also set the attributes to the intersection, i.e., if a particular attribute is the same across the duplicate edges, we use this attribute, otherwise, we set it to None.

>>> H6 = H.copy()
>>> H6.merge_duplicate_edges(merge_rule="intersection")
>>> H6.edges[0] == {'color': None, 'weight': None}
True
>>> H6.edges[3] == {'color': 'purple', 'name': None}
True

We can also choose to store the multiplicity of the edge as an attribute. The user simply provides the string of the attribute which stores it. Note that this will not prevent other attributes from being over written (e.g., weight), so be careful that the attribute is not already in use.

>>> H7 = H.copy()
>>> H7.merge_duplicate_edges(multiplicity="mult")
>>> H7.edges[0]['mult'] == 3
True
property nodes

A NodeView of this network.

property num_edges

The number of edges in the hypergraph.

Returns:

The number of edges in the hypergraph.

Return type:

int

See also

num_nodes

returns the number of nodes in the hypergraph

Examples

>>> import xgi
>>> hyperedge_list = [[1, 2], [2, 3, 4]]
>>> H = xgi.Hypergraph(hyperedge_list)
>>> H.num_edges
2
property num_nodes

The number of nodes in the hypergraph.

Returns:

The number of nodes in the hypergraph.

Return type:

int

See also

num_edges

returns the number of edges in the hypergraph

Examples

>>> import xgi
>>> hyperedge_list = [[1, 2], [2, 3, 4]]
>>> H = xgi.Hypergraph(hyperedge_list)
>>> H.num_nodes
4
random_edge_shuffle(e_id1=None, e_id2=None)[source]

Randomly redistributes nodes between two hyperedges.

The process is as follows:

  1. randomly select two hyperedges

  2. place all their nodes into a single bucket

  3. randomly redistribute the nodes between those two hyperedges

Parameters:
  • e_id1 (node ID, optional) – ID of first edge to shuffle.

  • e_id2 (node ID, optional) – ID of second edge to shuffle.

Note

After shuffling, the sizes of the two hyperedges are unchanged. Edge IDs and attributes are also unchanged. If the same node appears in both hyperedges, then this is still true after reshuffling. If either e_id1 or e_id2 is not provided, then two random edges are selected.

Philip S C., 2020. “Configuration models of random hypergraphs.” Journal of Complex Networks, 8(3). https://doi.org/10.1093/comnet/cnaa018

Example

>>> import xgi
>>> random.seed(42)
>>> H = xgi.Hypergraph([[1, 2, 3], [3, 4], [4, 5]])
>>> H.random_edge_shuffle()
>>> H.edges.members()
[{2, 4, 5}, {3, 4}, {1, 3}]
remove_edge(id)[source]

Remove one edge.

Parameters:

id (Hashable) – edge ID to remove

Raises:

XGIError – If no edge has that ID.

See also

remove_edges_from

Remove multiple edges.

remove_edges_from(ebunch)[source]

Remove multiple edges.

Parameters:

ebunch (Iterable) – Edges to remove.

Raises:

xgi.exception.IDNotFound – If an id in ebunch is not part of the network.

See also

remove_edge

remove a single edge.

remove_node(n, strong=False)[source]

Remove a single node.

The removal may be weak (default) or strong. In weak removal, the node is removed from each of its containing edges. If it is contained in any singleton edges, then these are also removed. In strong removal, all edges containing the node are removed, regardless of size.

Parameters:
  • n (node) – A node in the hypergraph

  • strong (bool, optional) – Whether to execute weak or strong removal. By default, False.

Raises:

XGIError – If n is not in the hypergraph.

remove_node_from_edge(edge, node)[source]

Remove a node from an existing edge.

Parameters:
  • edge (hashable) – The edge ID

  • node (hashable) – The node ID

Raises:

XGIError – If either the node or edge does not exist.

Notes

If edge is left empty as a result of removing node from it, the edge is also removed.

remove_nodes_from(nodes)[source]

Remove multiple nodes.

Parameters:

nodes (iterable) – An iterable of nodes.

See also

remove_node

set_edge_attributes(values, name=None)[source]

Set the edge attributes from a value or a dictionary of values.

Parameters:
  • values (scalar value, dict-like) – What the edge attribute should be set to. If values is not a dictionary, then it is treated as a single attribute value that is then applied to every edge in H. This means that if you provide a mutable object, like a list, updates to that object will be reflected in the edge attribute for each edge. The attribute name will be name. If values is a dict or a dict of dict, it should be keyed by edge ID to either an attribute value or a dict of attribute key/value pairs used to update the edge’s attributes.

  • name (string, optional) – Name of the edge attribute to set if values is a scalar. By default, None.

Notes

Note that if the dict contains edge IDs that are not in H, they are silently ignored.

set_node_attributes(values, name=None)[source]

Sets node attributes from a given value or dictionary of values.

Parameters:
  • values (scalar value, dict-like) –

    What the node attribute should be set to. If values is not a dictionary, then it is treated as a single attribute value that is then applied to every node in H. This means that if you provide a mutable object, like a list, updates to that object will be reflected in the node attribute for every node. The attribute name will be name.

    If values is a dict or a dict of dict, it should be keyed by node to either an attribute value or a dict of attribute key/value pairs used to update the node’s attributes.

  • name (string, optional) – Name of the node attribute to set if values is a scalar, by default None.

Notes

After computing some property of the nodes of a hypergraph, you may want to assign a node attribute to store the value of that property for each node.

If you provide a list as the second argument, updates to the list will be reflected in the node attribute for each node.

If you provide a dictionary of dictionaries as the second argument, the outer dictionary is assumed to be keyed by node to an inner dictionary of node attributes for that node.

Note that if the dictionary contains nodes that are not in G, the values are silently ignored.

update(*, edges=None, nodes=None)[source]

Add nodes or edges to the hypergraph.

Parameters:
  • edges (Iterable, optional) – Edges to be added. By default, None.

  • nodes (Iterable, optional) – Nodes to be added. By default, None.

See also

add_edges_from

Add multiple edges.

add_nodes_from

Add multiple nodes.