Skip to content

Commit

Permalink
Fix empty edge error when loading BiGG data. (#447)
Browse files Browse the repository at this point in the history
* Fix error when loading BiGG data

* format: isort and black
  • Loading branch information
nwlandry authored Aug 11, 2023
1 parent 1d26dfa commit 290729a
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 63 deletions.
2 changes: 0 additions & 2 deletions tests/convert/test_encapsulation_dag.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ def test_to_encapsulation_dag(edgelist1, edgelist8, hypergraph1, hypergraph2):
assert len(list(L.predecessors(0))) == 1
assert len(list(L.successors(1))) == 1


L = xgi.to_encapsulation_dag(H, subset_types="empirical")
assert isinstance(L, DiGraph)
assert set(L.nodes) == set(list(range(9)))
Expand All @@ -47,7 +46,6 @@ def test_to_encapsulation_dag(edgelist1, edgelist8, hypergraph1, hypergraph2):
assert len(list(L.predecessors(0))) == 1
assert len(list(L.successors(1))) == 1


L = xgi.to_encapsulation_dag(H, subset_types="empirical")
assert isinstance(L, DiGraph)
assert set(L.nodes) == set(list(range(9)))
Expand Down
59 changes: 29 additions & 30 deletions tests/convert/test_line_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,47 +42,46 @@ def test_abs_weighted_line_graph(edgelist1, hypergraph1, hypergraph2):

L = xgi.to_line_graph(H, weights="absolute")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {0, 1, 2, 3}
assert [set(e) for e in L.edges] == [{2, 3}]
assert L.edges[(2,3)]['weight'] == 1
assert L.edges[(2, 3)]["weight"] == 1

L = xgi.to_line_graph(hypergraph1, weights="absolute")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {"e1", "e2", "e3"}
assert [set(e) for e in L.edges] == [{"e1", "e2"}, {"e2", "e3"}]
assert L.edges[("e1","e2")]['weight'] == 2
assert L.edges[("e2","e3")]['weight'] == 1
assert sum([dat["weight"] for _,_,dat in L.edges(data=True)]) == 3

assert L.edges[("e1", "e2")]["weight"] == 2
assert L.edges[("e2", "e3")]["weight"] == 1
assert sum([dat["weight"] for _, _, dat in L.edges(data=True)]) == 3

L = xgi.to_line_graph(hypergraph1, s=2, weights="absolute")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {"e1", "e2", "e3"}
assert [set(e) for e in L.edges] == [{"e1", "e2"}]
assert L.edges[("e1","e2")]['weight'] == 2
assert sum([dat["weight"] for _,_,dat in L.edges(data=True)]) == 2
assert L.edges[("e1", "e2")]["weight"] == 2
assert sum([dat["weight"] for _, _, dat in L.edges(data=True)]) == 2

L = xgi.to_line_graph(hypergraph2, weights="absolute")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {"e1", "e2", "e3"}
assert [set(e) for e in L.edges] == [{"e1", "e2"}, {"e1", "e3"}, {"e2", "e3"}]
assert L.edges[("e1","e2")]['weight'] == 1
assert L.edges[("e2","e3")]['weight'] == 2
assert L.edges[("e1","e3")]['weight'] == 2
assert sum([dat["weight"] for _,_,dat in L.edges(data=True)]) == 5
assert L.edges[("e1", "e2")]["weight"] == 1
assert L.edges[("e2", "e3")]["weight"] == 2
assert L.edges[("e1", "e3")]["weight"] == 2
assert sum([dat["weight"] for _, _, dat in L.edges(data=True)]) == 5

L = xgi.to_line_graph(hypergraph2, s=2, weights="absolute")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {"e1", "e2", "e3"}
assert [set(e) for e in L.edges] == [{"e1", "e3"}, {"e2", "e3"}]
assert L.edges[("e2","e3")]['weight'] == 2
assert L.edges[("e1","e3")]['weight'] == 2
assert sum([dat["weight"] for _,_,dat in L.edges(data=True)]) == 4
assert L.edges[("e2", "e3")]["weight"] == 2
assert L.edges[("e1", "e3")]["weight"] == 2
assert sum([dat["weight"] for _, _, dat in L.edges(data=True)]) == 4


def test_normed_weighted_line_graph(edgelist1, hypergraph1, edgelist2, hypergraph2):
Expand All @@ -91,26 +90,26 @@ def test_normed_weighted_line_graph(edgelist1, hypergraph1, edgelist2, hypergrap

L = xgi.to_line_graph(H, weights="normalized")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {0, 1, 2, 3}
assert [set(e) for e in L.edges] == [{2, 3}]
assert L.edges[(2,3)]['weight'] == 0.5
assert L.edges[(2, 3)]["weight"] == 0.5

L = xgi.to_line_graph(hypergraph1, weights="normalized")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {"e1", "e2", "e3"}
assert [set(e) for e in L.edges] == [{"e1", "e2"}, {"e2", "e3"}]
assert L.edges[("e1","e2")]['weight'] == 1.0
assert L.edges[("e2","e3")]['weight'] == 1.0
assert sum([dat["weight"] for _,_,dat in L.edges(data=True)]) == 2.0
assert L.edges[("e1", "e2")]["weight"] == 1.0
assert L.edges[("e2", "e3")]["weight"] == 1.0
assert sum([dat["weight"] for _, _, dat in L.edges(data=True)]) == 2.0

L = xgi.to_line_graph(hypergraph2, weights="normalized")
assert isinstance(L, Graph)
assert all(["weight" in dat for u,v,dat in L.edges(data=True)])
assert all(["weight" in dat for u, v, dat in L.edges(data=True)])
assert set(L.nodes) == {"e1", "e2", "e3"}
assert [set(e) for e in L.edges] == [{"e1", "e2"}, {"e1", "e3"}, {"e2", "e3"}]
assert L.edges[("e1","e2")]['weight'] == 0.5
assert L.edges[("e2","e3")]['weight'] == 1.0
assert L.edges[("e1","e3")]['weight'] == 1.0
assert sum([dat["weight"] for _,_,dat in L.edges(data=True)]) == 2.5
assert L.edges[("e1", "e2")]["weight"] == 0.5
assert L.edges[("e2", "e3")]["weight"] == 1.0
assert L.edges[("e1", "e3")]["weight"] == 1.0
assert sum([dat["weight"] for _, _, dat in L.edges(data=True)]) == 2.5
8 changes: 8 additions & 0 deletions tests/readwrite/test_bigg_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ def test_load_bigg_data(capfd):

with pytest.raises(XGIError):
load_bigg_data("test")


def test_411():
with pytest.warns(Warning):
H = load_bigg_data("iCN718")
assert H["name"] == "iCN718"
assert H.num_nodes == 888
assert H.num_edges == 1014
50 changes: 28 additions & 22 deletions xgi/convert/encapsulation_dag.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from ..exception import XGIError

import networkx as nx

from ..exception import XGIError

__all__ = ["to_encapsulation_dag", "empirical_subsets_filter"]


def to_encapsulation_dag(H, subset_types="all"):
"""The encapsulation DAG (Directed Acyclic Graph) of
the hypergraph H.
Expand Down Expand Up @@ -57,8 +58,10 @@ def to_encapsulation_dag(H, subset_types="all"):
"""
if not (subset_types in ["all", "immediate", "empirical"]):
raise XGIError(f"{subset_types} not a valid subset_types option. Choices are "
"'all', 'immediate', and 'empirical'.")
raise XGIError(
f"{subset_types} not a valid subset_types option. Choices are "
"'all', 'immediate', and 'empirical'."
)

# Construct the dag
dag = nx.DiGraph()
Expand Down Expand Up @@ -90,6 +93,7 @@ def to_encapsulation_dag(H, subset_types="all"):

return dag


def _encapsulated(larger, smaller):
"""Test if a larger hyperedge encapsulates a smaller hyperedge.
Expand All @@ -108,6 +112,7 @@ def _encapsulated(larger, smaller):
"""
return len(set(larger).intersection(set(smaller))) == len(smaller)


def _get_candidates(subset_types, H, he):
"""Get the candidate hyperedges for encapsulation by he based on the subset type.
Expand Down Expand Up @@ -135,33 +140,35 @@ def _get_candidates(subset_types, H, he):

return candidates


def _check_candidate(subset_types, he, cand):
"""Check whether a hyperedge cand is a candidate to be encapsulated by
hyperedge he based on subset_types.
Parameters
----------
subset_types : str
Type of subset relationships
he : Set
The hyperedge
cand : Set
The candidate
Returns
-------
is_candidate : bool
True if cand is a valid candidate to be encapsulated by he, False
otherwise.
hyperedge he based on subset_types.
Parameters
----------
subset_types : str
Type of subset relationships
he : Set
The hyperedge
cand : Set
The candidate
Returns
-------
is_candidate : bool
True if cand is a valid candidate to be encapsulated by he, False
otherwise.
"""
is_candidate = False
if subset_types in ["all", "empirical"]:
if len(he) != len(cand):
is_candidate = True
elif subset_types == "immediate":
if len(he) == len(cand)-1 or len(he)-1 == len(cand):
if len(he) == len(cand) - 1 or len(he) - 1 == len(cand):
is_candidate = True
return is_candidate


def empirical_subsets_filter(H, dag):
"""
Filters encapsulation DAG of H in place to only include edges between hyperedges
Expand Down Expand Up @@ -190,8 +197,7 @@ def empirical_subsets_filter(H, dag):
preds = list(dag.predecessors(edge_idx))
if len(preds) > 0:
# Get the minimum superface size
min_sup_size = min([len(H.edges.members(cand_idx)) for cand_idx in
preds])
min_sup_size = min([len(H.edges.members(cand_idx)) for cand_idx in preds])
# Keep only the superfaces with that size
to_remove = []
for cand_idx in preds:
Expand Down
23 changes: 14 additions & 9 deletions xgi/convert/line_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from itertools import combinations

from ..exception import XGIError

import networkx as nx

from ..exception import XGIError

__all__ = ["to_line_graph"]


Expand Down Expand Up @@ -47,8 +47,10 @@ def to_line_graph(H, s=1, weights=None):
"""
if weights not in [None, "absolute", "normalized"]:
raise XGIError(f"{weights} not a valid weights option. Choices are "
"None, 'absolute', and 'normalized'.")
raise XGIError(
f"{weights} not a valid weights option. Choices are "
"None, 'absolute', and 'normalized'."
)
LG = nx.Graph()

edge_label_dict = {tuple(edge): index for index, edge in H._edge.items()}
Expand All @@ -61,16 +63,19 @@ def to_line_graph(H, s=1, weights=None):
if intersection_size >= s:
if not weights:
# Add unweighted edge
LG.add_edge(edge_label_dict[tuple(edge1)],
edge_label_dict[tuple(edge2)])
LG.add_edge(
edge_label_dict[tuple(edge1)], edge_label_dict[tuple(edge2)]
)
else:
# Compute the (normalized) weight
weight = intersection_size
if weights == "normalized":
weight /= min([len(edge1), len(edge2)])
# Add edge with weight
LG.add_edge(edge_label_dict[tuple(edge1)],
edge_label_dict[tuple(edge2)],
weight=weight)
LG.add_edge(
edge_label_dict[tuple(edge1)],
edge_label_dict[tuple(edge2)],
weight=weight,
)

return LG
5 changes: 5 additions & 0 deletions xgi/readwrite/bigg_data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Load a metabolic network from the BiGG models database."""

from warnings import warn

from ..utils import request_json_from_url, request_json_from_url_cached

__all__ = ["load_bigg_data"]
Expand Down Expand Up @@ -106,6 +108,9 @@ def _bigg_to_dihypergraph(d_index, d_model):
else:
tail.add(m)

if not head and not tail:
warn(f"{r['id']} is an empty reaction!")
continue
DH.add_edge((tail, head), id=r["id"], name=r["name"])

return DH

0 comments on commit 290729a

Please sign in to comment.