Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistent dunder methods for all complexes #378

Merged
merged 4 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions test/classes/test_cell_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,18 @@ def test_iter(self):
"""Test the iterator of the cell complex."""
CC = CellComplex()
CC.add_cell([1, 2, 3], rank=2)
CC.add_cell([2, 3, 4], rank=2)
assert set(iter(CC)) == {1, 2, 3, 4}
CC.add_cell([2, 4], rank=1)
assert set(CC) == {
(1,),
(2,),
(3,),
(4,),
(2, 1),
(2, 3),
(3, 1),
(2, 4),
(1, 2, 3),
}

def test_cell_equivalence_class(self):
"""Test the cell equivalence class method."""
Expand Down Expand Up @@ -1253,7 +1263,7 @@ def test_remove_singletons(self):
CC.remove_singletons()
assert CC.singletons() == []

def test_contains__(self):
def test_contains(self):
"""Test __contains__."""
CC = CellComplex()
CC.add_cell([1, 2, 3, 4], rank=2)
Expand All @@ -1264,6 +1274,10 @@ def test_contains__(self):
assert 3 in CC
assert 4 in CC
assert 5 in CC
assert 10 not in CC
assert (1, 2) in CC
assert (10, 12) not in CC
assert (1, 2, 3, 4) in CC
assert (1, 2, 3, 4, 5) not in CC

def test_neighbors(self):
Expand Down Expand Up @@ -1557,10 +1571,20 @@ def test_skeleton_method_exception(self):
def test_getitem_dunder_method(self):
"""Test if the dunder __getitem__ method returns the appropriate neighbors of the given node."""
CC = CellComplex()
CC.add_edges_from([(1, 2), (2, 3), (5, 2), (1, 9), (1, 6)])
assert sorted(CC.__getitem__(1)) == [2, 6, 9]
assert sorted(CC.__getitem__(2)) == [1, 3, 5]
assert sorted(CC.__getitem__(6)) == [1]
CC.add_node(1, color="red")
CC.add_edge(1, 2, weight=10)
CC.add_cell((2, 3, 4), rank=2, weight=5)

assert CC[1]["color"] == "red"
assert CC[(1,)]["color"] == "red"
assert CC[(1, 2)]["weight"] == 10
assert CC[(2, 3, 4)]["weight"] == 5

with pytest.raises(KeyError):
_ = CC[5]

CC[(1, 2)]["new"] = 1
assert CC[(1, 2)]["new"] == 1

def test_remove_nodes(self):
"""Test remove nodes method of the class Cell Complex."""
Expand Down
53 changes: 34 additions & 19 deletions test/classes/test_colored_hypergraph.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Unit tests for the colored hypergraph class."""

import collections

import networkx as nx
import pytest
from scipy.sparse import csr_array
Expand All @@ -10,8 +8,8 @@
from toponetx.classes.hyperedge import HyperEdge


class TestCombinatorialComplex:
"""Test CombinatorialComplex class."""
class TestColoredHyperGraph:
"""Test ColoredHyperGraph class."""

def test_init_empty_chg(self):
"""Test creation of an empty CHG."""
Expand Down Expand Up @@ -103,38 +101,55 @@ def test_chg_repr(self):
def test_chg_iter(self):
"""Test CHG iter."""
CHG = ColoredHyperGraph([[1, 2, 3], [2, 3, 4]], ranks=2)
isinstance(CHG, collections.abc.Iterable)
it = iter(CHG)
assert next(it) == frozenset({1})
assert next(it) == frozenset({2})
assert next(it) == frozenset({3})
assert next(it) == frozenset({4})
with pytest.raises(StopIteration):
next(it)
assert set(CHG) == {
frozenset({1}),
frozenset({2}),
frozenset({3}),
frozenset({4}),
frozenset({1, 2, 3}),
frozenset({2, 3, 4}),
}

def test_chg_contains(self):
"""Test chg contains property."""
CHG = ColoredHyperGraph([[1, 2, 3], [2, 3, 4]], ranks=2)

assert 1 in CHG
assert 2 in CHG
assert 3 in CHG
assert 4 in CHG
assert 5 not in CHG

assert (1, 2) not in CHG
assert (1, 2, 3) in CHG

def test_chg_getitem(self):
"""Test chg get node properties."""
CHG = ColoredHyperGraph([[1, 2, 3], [2, 3, 4]], ranks=2)
assert CHG[1] == {"weight": 1}
CHG.add_cell([5, 6], capacity=10)
CHG.add_cell([5, 6], key=1, capacity=15)
CHG.add_cell([5, 6, 7], capacity=5)

def test_chg_set(self):
"""Test chg set node properties."""
CHG = ColoredHyperGraph([[1, 2, 3], [2, 3, 4]], ranks=2)
assert CHG[1] == {"weight": 1}
CHG.__setitem__(1, weight=2)
assert CHG[1] == {"weight": 2}
assert CHG[(5, 6)]["capacity"] == 10
assert CHG[HyperEdge([5, 6])]["capacity"] == 10
assert CHG[(5, 6, 7)]["capacity"] == 5
assert CHG[HyperEdge([5, 6, 7])]["capacity"] == 5

assert CHG[((5, 6), 0)]["capacity"] == 10
assert CHG[(HyperEdge([5, 6]), 1)]["capacity"] == 15

# non-existing hyperedges
with pytest.raises(KeyError):
_ = CHG[(0, 1, 2)]
with pytest.raises(KeyError):
_ = CHG[((5, 6), 2)]

# invalid inputs should raise `KeyError`s as well
with pytest.raises(KeyError):
_ = CHG[tuple()]
with pytest.raises(KeyError):
CHG[5]
_ = CHG[(tuple(), 0)]

def test_add_cell(self):
"""Test adding a cell to a CHG."""
Expand Down
8 changes: 8 additions & 0 deletions test/classes/test_combinatorial_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,14 @@ def test_contains(self):
CCC.add_cell([1, 2, 4, 3], rank=2)
CCC.add_cell([2, 5], rank=1)
CCC.add_cell([2, 6, 4], rank=2)

assert 1 in CCC
assert 3 in CCC
assert 7 not in CCC

assert (1, 2) in CCC
assert (1, 4) not in CCC

assert [(1)] in CCC.nodes
assert [2] in CCC.nodes
assert [3] in CCC.nodes
Expand Down
13 changes: 12 additions & 1 deletion test/classes/test_path_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ def test_add_path(self):
assert [1, 2] in PC.paths
assert [2, 3] in PC.paths

def test_contains(self):
"""Test the __contains__ method."""
PC = PathComplex([[1, 2], [3], [4]])

assert 1 in PC
assert 3 in PC
assert 5 not in PC

assert (1, 2) in PC
assert (1, 3) not in PC

def test_constructor_using_graph(self):
"""Test constructor using graph."""
G = nx.Graph()
Expand Down Expand Up @@ -291,7 +302,7 @@ def test_get_len_(self):
"""Test get size of the path complex."""
PC = PathComplex()
PC.add_paths_from([[1, 2, 3], [1, 2, 4]])
assert len(PC) == 4
assert len(PC) == 9

def test_add_paths_from(self):
"""Test add paths from graph."""
Expand Down
42 changes: 20 additions & 22 deletions test/classes/test_reportviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,7 @@ class TestReportViews_ColoredHyperEdgeView:

def test_getitem(self):
"""Test the getitem method of the ColoredHyperEdgeView class."""
assert self.colorhg_view.__getitem__(((1, 2), 0)) == {"weight": 1}
with pytest.raises(KeyError):
self.colorhg_view.__getitem__((1, 2))
assert self.colorhg_view[((1, 2), 0)] == {"weight": 1}

def test_repr(self):
"""Test the repr method."""
Expand All @@ -525,19 +523,19 @@ def test_str(self):
def test_contains(self):
"""Test the contains method."""
assert ((1, 2), 0) in self.colorhg_view
assert self.colorhg_view.__contains__([]) is False
assert self.colorhg_view.__contains__(((2, 3), 0)) is True
assert self.colorhg_view.__contains__(1) is False
assert self.colorhg_view.__contains__(([], 1)) is False
assert self.colorhg_view.__contains__(((5, 6), 0)) is False
assert self.colorhg_view.__contains__(HyperEdge([1, 2])) is True
assert self.colorhg_view.__contains__((HyperEdge([1, 2, 3]), 0)) is False
assert self.colorhg_view.__contains__((HyperEdge([1, 2]), 0)) is True
assert self.colorhg_view.__contains__((HyperEdge([]), 0)) is False
assert [] not in self.colorhg_view
assert ((2, 3), 0) in self.colorhg_view
assert 1 in self.colorhg_view
assert ([], 1) not in self.colorhg_view
assert ((5, 6), 0) not in self.colorhg_view
assert HyperEdge([1, 2]) in self.colorhg_view
assert (HyperEdge([1, 2, 3]), 0) not in self.colorhg_view
assert (HyperEdge([1, 2]), 0) in self.colorhg_view
assert (HyperEdge([]), 0) not in self.colorhg_view

# test for empty CHG
assert self.colorhg_view1.__contains__(HyperEdge([1, 2])) is False
assert self.colorhg_view1.__contains__([]) is False
assert HyperEdge([1, 2]) not in self.colorhg_view1
assert (HyperEdge([1, 2]), 0) not in self.colorhg_view1

def test_skeleton(self):
"""Test the skeleton method of ColorHyperGraphView."""
Expand Down Expand Up @@ -651,14 +649,14 @@ def test_get_item(self):

def test_contains(self):
"""Test the __contains__ method of the PathView class."""
assert self.path_view.__contains__(1) is True
assert self.path_view.__contains__((1,)) is True
assert self.path_view.__contains__(Path(1)) is True
assert self.path_view.__contains__((1, 2, 3, 4)) is False
assert self.path_view.__contains__(Path((1, 2, 4))) is False
assert self.path_view.__contains__({(1, 2, 3)}) is False
assert self.path_view.__contains__([]) is False
assert self.path_view.__contains__(Path([1, 2, 3, 4])) is False
assert 1 in self.path_view
assert (1,) in self.path_view
assert Path(1) in self.path_view
assert (1, 2, 3, 4) not in self.path_view
assert Path((1, 2, 4)) not in self.path_view
assert {(1, 2, 3)} not in self.path_view
assert [] not in self.path_view
assert Path([1, 2, 3, 4]) not in self.path_view

def test_repr(self):
"""Test __repr__ method of the PathView class."""
Expand Down
68 changes: 42 additions & 26 deletions test/classes/test_simplicial_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,30 +118,35 @@ def test_rep_str(self):

def test_iter(self):
"""Test iter method."""
sc = SimplicialComplex([[1, 2, 3], [2, 3, 4], [0, 1]])
assert len(list(sc)) == 5
_i = iter(sc)
assert next(_i) == 1
assert next(_i) == 2
assert next(_i) == 3
assert next(_i) == 4
assert next(_i) == 0
with pytest.raises(StopIteration):
next(_i)
SC = SimplicialComplex([[1, 2, 3], [2, 4], [5]])
simplices = set(SC)
assert simplices == {
frozenset({1}),
frozenset({2}),
frozenset({3}),
frozenset({4}),
frozenset({5}),
frozenset({1, 2}),
frozenset({1, 3}),
frozenset({2, 3}),
frozenset({2, 4}),
frozenset({1, 2, 3}),
}

def test_getittem__(self):
"""Test __getitem__ and __setitem__ methods."""
G = nx.Graph()
G.add_edge(0, 1)
G.add_edge(2, 5)
G.add_edge(5, 4, weight=5)
SC = SimplicialComplex(G, name="graph complex")
"""Test __getitem__ methods."""
SC = SimplicialComplex()
SC.add_simplex((0, 1), weight=5)
SC.add_simplex((1, 2, 3), heat=5)
# with pytest.raises(ValueError):

assert SC[(0, 1)]["weight"] == 5
assert SC[(1, 2, 3)]["heat"] == 5
with pytest.raises(KeyError):
SC[(1, 2, 3, 4, 5)]["heat"]

SC[(0, 1)]["new"] = 10
assert SC[(0, 1)]["new"] == 10

def test_setting_simplex_attributes(self):
"""Test setting simplex attributes through a `SimplicialComplex` object."""
G = nx.Graph()
Expand Down Expand Up @@ -278,6 +283,17 @@ def test_add_simplex(self):
SC.add_simplex("test")
assert ("test",) in SC.simplices

def test_contains(self):
"""Test the __contains__ method."""
SC = SimplicialComplex([[1, 2], [3], [4]])

assert 1 in SC
assert 3 in SC
assert 5 not in SC

assert (1, 2) in SC
assert (1, 3) not in SC

def test_remove_maximal_simplex(self):
"""Test remove_maximal_simplex method."""
# create a SimplicialComplex object with a few simplices
Expand All @@ -304,15 +320,15 @@ def test_remove_maximal_simplex(self):
c1 = Simplex((1, 2, 3, 4, 5))
SC.add_simplex(c1)
SC.remove_maximal_simplex((1, 2, 3, 4, 5))
assert (1, 2, 3, 4, 5) not in SC
assert (1, 2, 3, 4, 5) not in SC.simplices

# check removal with Simplex
SC = SimplicialComplex()
SC.add_simplex((1, 2, 3, 4), weight=1)
c1 = Simplex((1, 2, 3, 4, 5))
SC.add_simplex(c1)
SC.remove_maximal_simplex(c1)
assert (1, 2, 3, 4, 5) not in SC
assert (1, 2, 3, 4, 5) not in SC.simplices

# check error when simplex not in complex
with pytest.raises(KeyError):
Expand All @@ -331,12 +347,12 @@ def test_remove_nodes(self) -> None:
SC = SimplicialComplex([[0, 1], [1, 2, 3], [2, 3, 4], [4, 5]])
SC.remove_nodes([2, 5])

assert [0, 1] in SC
assert [1, 3] in SC
assert [3, 4] in SC
assert [4] in SC
assert [2, 3] not in SC
assert [2, 4] not in SC
assert [0, 1] in SC.simplices
assert [1, 3] in SC.simplices
assert [3, 4] in SC.simplices
assert [4] in SC.simplices
assert [2, 3] not in SC.simplices
assert [2, 4] not in SC.simplices

assert SC.is_maximal([0, 1])
assert SC.is_maximal([1, 3])
Expand Down Expand Up @@ -1019,7 +1035,7 @@ def test_clone(self):
assert SC2[(1, 2, 3)] is not SC[(1, 2, 3)]
SC2.remove_maximal_simplex([1, 2, 3])
assert 1 in SC
assert (1, 2, 3) in SC
assert (1, 2, 3) in SC.simplices

def test_normalized_laplacian_matrix(self):
"""Test the normalized_laplacian_matrix method of SimplicialComplex."""
Expand Down
Loading
Loading