Skip to content

Commit

Permalink
Add support for bidirectional self-loop edges
Browse files Browse the repository at this point in the history
Do not allow the adding of duplicate edges.
  • Loading branch information
dhimmel committed Feb 16, 2017
1 parent 8531e2b commit d32ba2a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 15 deletions.
41 changes: 29 additions & 12 deletions hetio/hetnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def add_node(self, kind, identifier, name=None, data={}):
metanode = self.metagraph.node_dict[kind]
node = Node(metanode, identifier, name, data)
node_id = node.get_id()
assert node_id not in self
assert node_id not in self, 'node already exists'
self.node_dict[node_id] = node
self.n_nodes += 1
return node
Expand All @@ -392,23 +392,40 @@ def add_edge(self, source_id, target_id, kind, direction, data=dict()):
"""source_id and target_id are (metanode, node) tuples"""
source = self.node_dict[source_id]
target = self.node_dict[target_id]
metaedge_id = source.metanode.get_id(), target.metanode.get_id(), kind, direction
metaedge_id = (
source.metanode.get_id(),
target.metanode.get_id(),
kind,
direction,
)
metaedge = self.metagraph.edge_dict[metaedge_id]

# Check that edges do not already exist
edge_id = source_id, target_id, kind, metaedge.direction
inverse_id = target_id, source_id, kind, metaedge.inverse.direction
assert edge_id not in self.edge_dict, 'edge already exists'
assert inverse_id not in self.edge_dict, 'inverse edge already exists'

# Create edge
edge = Edge(source, target, metaedge, data)
self.edge_dict[edge.get_id()] = edge
edge.inverted = metaedge.inverted

inverse = Edge(target, source, metaedge.inverse, data)
inverse_id = inverse.get_id()
self.edge_dict[inverse_id] = inverse
inverse.inverted = not edge.inverted

edge.inverse = inverse
inverse.inverse = edge
self.n_edges += 1
self.n_inverts += 1

return edge, inverse
# Create inverse edge if not identical
if edge_id == inverse_id:
# Self loop of a bidirectional edge
edge.inverse = edge
else:
inverse = Edge(target, source, metaedge.inverse, data)
inverse_id = inverse.get_id()
self.edge_dict[inverse_id] = inverse
inverse.inverted = not edge.inverted
edge.inverse = inverse
inverse.inverse = edge
self.n_inverts += 1

return edge, edge.inverse

def unmask(self):
"""Unmask all nodes and edges contained within the graph"""
Expand Down
22 changes: 19 additions & 3 deletions test/graph_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,33 @@ def test_creation():
SPI1 = graph.add_node('gene', 6688, name='SPI1',
data={'description': 'Spi-1 proto-oncogene'})

# Attempt to add a duplicate node
with pytest.raises(AssertionError):
graph.add_node('gene', 3575, 'IL7R')

# Misordered node creation arguments
with pytest.raises(KeyError):
# misordered args
graph.add_node('DOID:2377', 'multiple sclerosis', 'disease')

graph.add_edge(IL7R.get_id(), SPI1.get_id(), 'transcribes', 'forward')
graph.add_edge(IL7R.get_id(), SPI1.get_id(), 'interacts', 'both')
graph.add_edge(ms.get_id(), IL7R.get_id(), 'associates', 'both')

# Enable in future to check that creating a duplicate edge throws an error
# graph.add_edge(SPI1.get_id(), IL7R.get_id(), 'transcribes', 'backward')
with pytest.raises(AssertionError) as excinfo:
graph.add_edge(IL7R.get_id(), SPI1.get_id(), 'transcribes', 'forward')
excinfo.match(r'edge already exists')
with pytest.raises(AssertionError):
graph.add_edge(SPI1.get_id(), IL7R.get_id(), 'transcribes', 'backward')

# Add bidirectional self loop
graph.add_edge(IL7R.get_id(), IL7R.get_id(), 'interacts', 'both')

# Test node and edge counts
assert graph.n_nodes == 3
assert graph.n_edges == 3
assert graph.n_edges == 4
assert graph.n_inverts == 3
assert graph.n_nodes == len(list(graph.get_nodes()))
assert graph.n_edges == len(list(graph.get_edges(exclude_inverts=True)))
assert (graph.n_edges + graph.n_inverts ==
len(list(graph.get_edges(exclude_inverts=False))))

0 comments on commit d32ba2a

Please sign in to comment.