def add_node_to_edge(self, node, edge): """ Adds node to an edge in hypergraph edges Parameters ---------- node: hashable or Entity If Entity, only uid and properties will be used. If uid is already in nodes then the known node will be used edge: uid of edge or edge, must belong to self.edges Returns ------- hypergraph : Hypergraph """ if edge in self._edges: if not isinstance(edge, Entity): edge = self._edges[edge] if node in self._nodes: if not isinstance(node, Entity): node = self._nodes[node] self._edges[edge].add(node) else: if not isinstance(node, Entity): node = Entity(node) else: node = Entity(node.uid, **node.properties) self._nodes.add(node) self._edges[edge].add(node) return self
def restrict_to_nodes(self, nodeset, name=None): """ Constructs a new hypergraph by restricting the edges in the hypergraph to the nodes referenced by nodeset. Parameters ---------- nodeset: iterable of hashables References a subset of elements of self.nodes name: string, optional, default: None Returns ------- new hypergraph : Hypergraph """ memberships = set() for node in nodeset: if node in self.nodes: memberships.update(set(self.nodes[node].memberships)) newedgeset = dict() for e in memberships: if e in self.edges: temp = self.edges[e].uidset.intersection(nodeset) if temp: newedgeset[e] = Entity(e, temp, **self.edges[e].properties) return Hypergraph(newedgeset, name)
def from_bipartite(cls, B, set_names=[0, 1], name=None): """ Static method creates a Hypergraph from a bipartite graph. Parameters ---------- B: nx.Graph() A networkx bipartite graph. Each node in the graph has a property 'bipartite' taking one of two values set_names: iterable An ordered list :math:`[x_0, x_1]`, corresponding to the values assigned to the bipartite property in B. name: hashable Returns ------- new hypergraph : Hypergraph Notes ----- A partition for the nodes in a bipartite graph generates a hypergraph as follows. For each node n in B with bipartite property equal to set_names[0] there is a node n in the hypergraph. For each node e in B with bipartite property equal to set_names[1], there is an edge in the hypergraph. For each edge (n,e) in B add n to the edge e in the hypergraph. """ if not bipartite.is_bipartite(B): raise HyperNetxError('Error: Method requires a bipartite graph.') entities = [] for n, d in B.nodes(data=True): if d['bipartite'] == set_names[1]: elements = [] for nei in B.neighbors(n): elements.append( Entity(nei, [], properties=B.nodes(data=True)[nei])) if elements: entities.append(Entity(n, elements, properties=d)) name = name or '_' return Hypergraph(EntitySet(name, entities), name=name)
def _add_nodes_from(self, nodes): """ Private helper method instantiates new nodes when edges added to hypergraph. Parameters ---------- nodes : iterable of hashables or Entities """ for node in nodes: if node in self._edges: raise HyperNetxError("Node already an edge.") elif node in self._nodes and isinstance(node, Entity): self._nodes[node].__dict__.update(node.properties) elif node not in self._nodes: if isinstance(node, Entity): self._nodes.add(Entity(node.uid, **node.properties)) else: self._nodes.add(Entity(node))
def add_edge(self, edge): """ Adds a single edge to hypergraph. Parameters ---------- edge : hashable or Entity If hashable the edge returned will be empty. Returns ------- hypergraph : Hypergraph Notes ----- When adding an edge to a hypergraph children must be removed so that nodes do not have elements. Each node (element of edge) must be instantiated as a node, making sure its uid isn't already present in the self. If an added edge contains nodes that cannot be added to hypergraph then an error will be thrown. """ if edge in self._edges: warnings.warn("Cannot add edge. Edge already in hypergraph") elif edge in self._nodes: warnings.warn("Cannot add edge. Edge is already a Node") elif isinstance(edge, Entity): if len(edge) > 0: self._add_nodes_from(edge.elements.values()) self._edges.add( Entity(edge.uid, elements=[self._nodes[k] for k in edge], **edge.properties)) for n in edge.elements: self._nodes[n].memberships[edge.uid] = self._edges[ edge.uid] else: self._edges.add(Entity(edge.uid, **edge.properties)) else: self._edges.add(Entity(edge)) ### this generates an empty edge return self
def __init__(self, setsystem=None, name='_'): self.name = name ##### Check setsystem type and change into an EntitySet before constructing hypergraph: if not setsystem: setsystem = EntitySet('_', elements=[]) elif isinstance(setsystem, dict): ### Must be a dictionary with values equal to iterables of Entities and hashables. ### Keys will be uids for new edges and values of the dictionary will generate the nodes. setsystem = EntitySet('_', setsystem) ### If no ids are given, return default ids indexed by position in iterator ### This should be an iterable of sets elif not isinstance(setsystem, EntitySet): labels = [self.name + str(x) for x in range(len(setsystem))] setsystem = EntitySet('_', dict(zip(labels, setsystem))) _reg = setsystem.registry _nodes = {k: Entity(k, **_reg[k].properties) for k in _reg} _elements = { j: {k: _nodes[k] for k in setsystem[j]} for j in setsystem } _edges = { j: Entity(j, elements=_elements[j].values(), **setsystem[j].properties) for j in setsystem } self._edges = EntitySet(f'{self.name}:Edges', elements=_edges.values(), **setsystem.properties) self._nodes = EntitySet(f'{self.name}:Nodes', elements=_nodes.values())