Skip to content

Commit

Permalink
Remove id variable from XGI (#620)
Browse files Browse the repository at this point in the history
* Remove `id` from tests

* remove `id` from core data structures

* Remove `id` from all other files

* Fix failing test

* Fix failing notebook

* response to review
  • Loading branch information
nwlandry authored Nov 24, 2024
1 parent 2c6fadc commit 0726fe1
Show file tree
Hide file tree
Showing 23 changed files with 328 additions and 318 deletions.
14 changes: 7 additions & 7 deletions tests/core/test_dihypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ def test_add_edge_rejects_set():

def test_add_edge_handles_uid_correctly():
H1 = xgi.DiHypergraph()
H1.add_edge(([1, 2], [3]), id=0)
H1.add_edge(([3, 4], [4, 5]), id=2)
H1.add_edge(([1, 2], [3]), idx=0)
H1.add_edge(([3, 4], [4, 5]), idx=2)
H1.add_edge([[5, 6], [2, 3]])
assert H1.edges.dimembers(dtype=dict) == {
0: ({1, 2}, {3}),
Expand All @@ -225,13 +225,13 @@ def test_add_edge_warns_when_overwriting_edge_id():
H2.add_edge(([1, 2], [3]))
H2.add_edge(([3, 4], [5, 6, 7]))
with pytest.warns(Warning):
H2.add_edge(([5, 6], [8]), id=0)
H2.add_edge(([5, 6], [8]), idx=0)
assert {i: e["in"] for i, e in H2._edge.items()} == {0: {1, 2}, 1: {3, 4}}


def test_add_edge_with_id():
H = xgi.DiHypergraph()
H.add_edge(([1, 2, 3], [3, 4]), id="myedge")
H.add_edge(([1, 2, 3], [3, 4]), idx="myedge")
assert (1 in H) and (2 in H) and (3 in H) and (4 in H)
assert "myedge" in H.edges
assert {1, 2, 3, 4} in H.edges.members()
Expand Down Expand Up @@ -432,7 +432,7 @@ def test_copy(diedgelist1):
assert H._net_attr == copy._net_attr

H1 = xgi.DiHypergraph()
H1.add_edge(([1, 2], [3]), id="x")
H1.add_edge(([1, 2], [3]), idx="x")
copy2 = H1.copy() # does not throw error because of str id
assert list(copy2.nodes) == list(H1.nodes)
assert list(copy2.edges) == list(H1.edges)
Expand Down Expand Up @@ -563,8 +563,8 @@ def test_pickle(diedgelist1):

assert H1.nodes == H2.nodes
assert H1.edges == H2.edges
assert [H1.edges.members(id) for id in H1.edges] == [
H2.edges.members(id) for id in H2.edges
assert [H1.edges.members(e) for e in H1.edges] == [
H2.edges.members(e) for e in H2.edges
]


Expand Down
14 changes: 7 additions & 7 deletions tests/core/test_hypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ def test_add_edge():

# check that uid works correctly
H1 = xgi.Hypergraph()
H1.add_edge([1, 2], id=0)
H1.add_edge([3, 4], id=2)
H1.add_edge([1, 2], idx=0)
H1.add_edge([3, 4], idx=2)
H1.add_edge([5, 6])
assert H1._edge == {0: {1, 2}, 2: {3, 4}, 3: {5, 6}}

Expand All @@ -201,14 +201,14 @@ def test_add_edge():
with pytest.warns(
UserWarning, match="uid 0 already exists, cannot add edge {5, 6}"
):
H2.add_edge([5, 6], id=0)
H2.add_edge([5, 6], idx=0)

assert H2._edge == {0: {1, 2}, 1: {3, 4}}


def test_add_edge_with_id():
H = xgi.Hypergraph()
H.add_edge([1, 2, 3], id="myedge")
H.add_edge([1, 2, 3], idx="myedge")
assert (1 in H) and (2 in H) and (3 in H)
assert "myedge" in H.edges
assert {1, 2, 3} in H.edges.members()
Expand Down Expand Up @@ -472,7 +472,7 @@ def test_copy(edgelist1):
assert H._net_attr == copy._net_attr

H1 = xgi.Hypergraph()
H1.add_edge((1, 2), id="x")
H1.add_edge((1, 2), idx="x")
copy2 = H1.copy() # does not throw error because of str id
assert list(copy2.nodes) == list(H1.nodes)
assert list(copy2.edges) == list(H1.edges)
Expand Down Expand Up @@ -738,8 +738,8 @@ def test_pickle(edgelist1):

assert H1.nodes == H2.nodes
assert H1.edges == H2.edges
assert [H1.edges.members(id) for id in H1.edges] == [
H2.edges.members(id) for id in H2.edges
assert [H1.edges.members(e) for e in H1.edges] == [
H2.edges.members(e) for e in H2.edges
]


Expand Down
8 changes: 4 additions & 4 deletions tests/core/test_simplicialcomplex.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def test_add_simplex():
S2.add_simplex([1, 2])
S2.add_simplex([3, 4])
with pytest.warns(UserWarning, match="uid 1 already exists, cannot add simplex"):
S2.add_simplex([5, 6], id=1)
S2.add_simplex([5, 6], idx=1)
assert S2._edge == {0: frozenset({1, 2}), 1: frozenset({3, 4})}


Expand Down Expand Up @@ -410,7 +410,7 @@ def test_copy(edgelist1):
assert H._net_attr == copy._net_attr

H1 = xgi.SimplicialComplex()
H1.add_simplex((1, 2), id="x")
H1.add_simplex((1, 2), idx="x")
copy2 = H1.copy() # does not throw error because of str id
assert list(copy2.nodes) == list(H1.nodes)
assert list(copy2.edges) == list(H1.edges)
Expand Down Expand Up @@ -448,8 +448,8 @@ def test_remove_simplex_id(edgelist6):
S.add_simplices_from(edgelist6)

# remove simplex and others it belongs to
id = list(S._edge.values()).index(frozenset({2, 3}))
S.remove_simplex_id(id) # simplex {2, 3}
idx = list(S._edge.values()).index(frozenset({2, 3}))
S.remove_simplex_id(idx) # simplex {2, 3}
edges = [
frozenset({0, 1, 2}),
frozenset({0, 1}),
Expand Down
4 changes: 2 additions & 2 deletions tests/drawing/test_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,6 @@ def test_edge_positions_from_barycenters(edgelist1):
edge_pos = xgi.edge_positions_from_barycenters(H, node_pos)

assert len(edge_pos) == H.num_edges
for id, e in H.edges.members(dtype=dict).items():
for idx, e in H.edges.members(dtype=dict).items():
mean_pos = np.mean([node_pos[n] for n in e], axis=0)
assert np.allclose(edge_pos[id], mean_pos)
assert np.allclose(edge_pos[idx], mean_pos)
31 changes: 9 additions & 22 deletions tests/readwrite/test_bipartite_edgelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def test_read_bipartite_edgelist(file_string, extra_kwargs):

H = xgi.read_bipartite_edgelist(filename, nodetype=int, **extra_kwargs)
int_edgelist = [{0, 1, 2, 3}, {4}, {5, 6}, {6, 7, 8}]
assert [H.edges.members(id) for id in H.edges] == int_edgelist
assert [H.edges.members(eid) for eid in H.edges] == int_edgelist
H = xgi.read_bipartite_edgelist(filename, nodetype=str, **extra_kwargs)
str_edgelist = [{"0", "1", "2", "3"}, {"4"}, {"5", "6"}, {"6", "7", "8"}]
assert [H.edges.members(id) for id in H.edges] == str_edgelist
assert [H.edges.members(eid) for eid in H.edges] == str_edgelist


def test_parse_bipartite_edgelist():
Expand Down Expand Up @@ -92,28 +92,15 @@ def test_parse_bipartite_edgelist():
H = xgi.parse_bipartite_edgelist(lines, nodetype=int, edgetype=int)
assert list(H.nodes) == [0, 1, 2, 3, 4, 5, 6, 7, 8]
assert list(H.edges) == [0, 1, 2, 3]
assert [H.edges.members(id) for id in H.edges] == [
{0, 1, 2, 3},
{4},
{5, 6},
{6, 7, 8},
]
edges = [{0, 1, 2, 3}, {4}, {5, 6}, {6, 7, 8}]
assert [H.edges.members(eid) for eid in H.edges] == edges

H = xgi.parse_bipartite_edgelist(lines, nodetype=int, edgetype=int, dual=True)
assert list(H.nodes) == [0, 1, 2, 3]
assert list(H.edges) == [0, 1, 2, 3, 4, 5, 6, 7, 8]
print([H.edges.members(id) for id in H.edges])
assert [H.edges.members(id) for id in H.edges] == [
{0},
{0},
{0},
{0},
{1},
{2},
{2, 3},
{3},
{3},
]
print([H.edges.members(eid) for eid in H.edges])
edges = [{0}, {0}, {0}, {0}, {1}, {2}, {2, 3}, {3}, {3}]
assert [H.edges.members(eid) for eid in H.edges] == edges

# test less than two entries per line
with pytest.raises(XGIError):
Expand All @@ -135,6 +122,6 @@ def test_write_bipartite_edgelist(edgelist1):
H2 = xgi.read_bipartite_edgelist(filename, nodetype=int, edgetype=int)
assert H1.nodes == H2.nodes
assert H1.edges == H2.edges
assert [H1.edges.members(id) for id in H1.edges] == [
H2.edges.members(id) for id in H2.edges
assert [H1.edges.members(e) for e in H1.edges] == [
H2.edges.members(e) for e in H2.edges
]
16 changes: 6 additions & 10 deletions tests/readwrite/test_edgelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,18 @@ def test_read_edgelist(file_string, extra_kwargs):

H = xgi.read_edgelist(filename, nodetype=int, **extra_kwargs)
int_edgelist = [{1, 2}, {2, 3, 4}, {1, 4, 7, 8}, {2, 3}]
assert [H.edges.members(id) for id in H.edges] == int_edgelist
assert [H.edges.members(eid) for eid in H.edges] == int_edgelist
H = xgi.read_edgelist(filename, nodetype=str, **extra_kwargs)
str_edgelist = [{"1", "2"}, {"2", "3", "4"}, {"1", "4", "7", "8"}, {"2", "3"}]
assert [H.edges.members(id) for id in H.edges] == str_edgelist
assert [H.edges.members(eid) for eid in H.edges] == str_edgelist


def test_parse_edgelist():
H = xgi.parse_edgelist(["1 2", "2 3 4", "1 4 7 8", "2 3"], nodetype=int)
assert set(H.nodes) == {1, 2, 3, 4, 7, 8}
assert set(H.edges) == {0, 1, 2, 3}
assert [H.edges.members(id) for id in H.edges] == [
{1, 2},
{2, 3, 4},
{1, 4, 7, 8},
{2, 3},
]
edges = [{1, 2}, {2, 3, 4}, {1, 4, 7, 8}, {2, 3}]
assert [H.edges.members(eid) for eid in H.edges] == edges

# This will fail because the "test" node ID can't be converted to int
with pytest.raises(TypeError):
Expand All @@ -63,6 +59,6 @@ def test_write_edgelist(edgelist1):
H2 = xgi.read_edgelist(filename, nodetype=int)
assert H1.nodes == H2.nodes
assert H1.edges == H2.edges
assert [H1.edges.members(id) for id in H1.edges] == [
H2.edges.members(id) for id in H2.edges
assert [H1.edges.members(e) for e in H1.edges] == [
H2.edges.members(e) for e in H2.edges
]
6 changes: 3 additions & 3 deletions tests/readwrite/test_incidence_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_read_incidence_matrix(file_string, extra_kwargs):

H = xgi.read_incidence_matrix(filename, **extra_kwargs)
int_edgelist = [{0, 1, 2, 3}, {4}, {5, 6}, {6, 7, 8}]
assert [H.edges.members(id) for id in H.edges] == int_edgelist
assert [H.edges.members(eid) for eid in H.edges] == int_edgelist


def test_write_incidence_matrix(edgelist5):
Expand All @@ -55,6 +55,6 @@ def test_write_incidence_matrix(edgelist5):
H2 = xgi.read_incidence_matrix(fname)
assert H1.nodes == H2.nodes
assert H1.edges == H2.edges
assert [H1.edges.members(id) for id in H1.edges] == [
H2.edges.members(id) for id in H2.edges
assert [H1.edges.members(e) for e in H1.edges] == [
H2.edges.members(e) for e in H2.edges
]
8 changes: 4 additions & 4 deletions tests/readwrite/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ def test_read_json():
assert list(H2.nodes) == ["1", "2", "3", "4"]
assert H1["name"] == "test"
assert H1["author"] == "Nicholas Landry"
assert [H1.edges.members(id) for id in H1.edges] == [{1, 2}, {2, 3, 4}, {1, 4}]
assert [H2.edges.members(id) for id in H2.edges] == [
assert [H1.edges.members(e) for e in H1.edges] == [{1, 2}, {2, 3, 4}, {1, 4}]
assert [H2.edges.members(e) for e in H2.edges] == [
{"1", "2"},
{"2", "3", "4"},
{"1", "4"},
Expand Down Expand Up @@ -246,8 +246,8 @@ def test_write_json(edgelist1, edgelist2):

assert set(H1.nodes) == set(H2.nodes)
assert set(H1.edges) == set(H2.edges)
assert {frozenset(H1.edges.members(id)) for id in H1.edges} == {
frozenset(H2.edges.members(id)) for id in H2.edges
assert {frozenset(H1.edges.members(e)) for e in H1.edges} == {
frozenset(H2.edges.members(e)) for e in H2.edges
}
assert H2.nodes[2] == {"name": "Ilya"}
assert H2.edges[1] == {"weight": 2}
Expand Down
125 changes: 76 additions & 49 deletions tutorials/getting_started/quickstart.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion xgi/convert/bipartite_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def from_bipartite_graph(G, create_using=None, dual=False):
H.add_nodes_from(nodes)
for edge in edges:
nodes_in_edge = list(G.neighbors(edge))
H.add_edge(nodes_in_edge, id=edge)
H.add_edge(nodes_in_edge, idx=edge)
return H.dual() if dual else H


Expand Down
14 changes: 7 additions & 7 deletions xgi/convert/hypergraph_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,28 +110,28 @@ def from_hypergraph_dict(data, nodetype=None, edgetype=None, max_order=None):
raise XGIError("Failed to get hypergraph data attributes.")

try:
for id, dd in data["node-data"].items():
for idx, dd in data["node-data"].items():
if nodetype is not None:
try:
id = nodetype(id)
idx = nodetype(idx)
except ValueError as e:
raise TypeError(
f"Failed to convert edge IDs to type {nodetype}."
) from e
H.add_node(id, **dd)
H.add_node(idx, **dd)
except KeyError:
raise XGIError("Failed to import node attributes.")

try:
for id, edge in data["edge-dict"].items():
for idx, edge in data["edge-dict"].items():
if max_order and len(edge) > max_order + 1:
continue
if edgetype is not None:
try:
id = edgetype(id)
idx = edgetype(idx)
except ValueError as e:
raise TypeError(
f"Failed to convert the edge with ID {id} to type {edgetype}."
f"Failed to convert the edge with ID {idx} to type {edgetype}."
) from e

if nodetype is not None:
Expand All @@ -141,7 +141,7 @@ def from_hypergraph_dict(data, nodetype=None, edgetype=None, max_order=None):
raise TypeError(
f"Failed to convert nodes to type {nodetype}."
) from e
H.add_edge(edge, id)
H.add_edge(edge, idx)

except KeyError as e:
raise XGIError("Failed to import edge dictionary.") from e
Expand Down
Loading

0 comments on commit 0726fe1

Please sign in to comment.