Skip to content

Commit

Permalink
Merge pull request #383 from pyt-team/frantzen/cleanup
Browse files Browse the repository at this point in the history
Remove unreachable code
  • Loading branch information
ffl096 authored Aug 5, 2024
2 parents 684ed9b + e5f77d5 commit 0e33fad
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 86 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get history and tags for SCM versioning to work
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: |
git fetch --prune --unshallow
git tag -d $(git tag --points-at HEAD)
- name: Set up Python
uses: actions/setup-python@v5
with:
Expand Down
5 changes: 3 additions & 2 deletions test/classes/test_colored_hypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,10 @@ def test_laplacian_matrix(self):
assert row == res
assert isinstance(L, csr_array)

# check cases where the rank is over the maximum rank of the CHG
CHG = ColoredHyperGraph()
L = CHG.laplacian_matrix(1)
assert L.shape == (0, 0)
with pytest.raises(ValueError):
_ = CHG.laplacian_matrix(1)

def test_singletons(self):
"""Test singletons of CHG."""
Expand Down
9 changes: 9 additions & 0 deletions test/classes/test_combinatorial_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,3 +653,12 @@ def test_remove_singletons(self):
CCC.add_cell([9], rank=0)
CCC = CCC.remove_singletons()
assert 9 not in CCC.nodes

def test_CCC_condition(self):
"""Test the _CCC_condition method of the CombinatorialComplex class."""
CCC = CombinatorialComplex([[1, 2, 3], [2, 3, 4]], ranks=2)

CCC._CCC_condition({1, 2}, rank=1)

with pytest.raises(ValueError):
CCC._CCC_condition({1, 2}, rank=3)
113 changes: 32 additions & 81 deletions toponetx/classes/colored_hypergraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ def dim(self) -> int:
int
The dimension of the colored hypergraph.
"""
if len(self._complex_set) == 0:
return 0
return max(self._complex_set.allranks)

@property
Expand Down Expand Up @@ -1018,15 +1020,15 @@ def remove_cells(self, cell_set) -> None:
for cell in cell_set:
self.remove_cell(cell)

def _incidence_matrix(
def incidence_matrix(
self,
rank,
to_rank,
weight: bool | None = None,
rank: int,
to_rank: int,
weight: str | None = None,
sparse: bool = True,
index: bool = False,
):
"""Compute incidence matrix.
"""Compute incidence matrix for the CHG indexed by nodes x cells.
An incidence matrix indexed by r-ranked hyperedges and k-ranked hyperedges
where r != k. When k is None, incidence_type will be considered instead.
Expand All @@ -1037,40 +1039,23 @@ def _incidence_matrix(
The rank for computing the incidence matrix.
to_rank : int
The rank for computing the incidence matrix.
weight : bool, default=None
If False, all nonzero entries are 1.
If True and self.static, all nonzero entries are filled by
self.cells.cell_weight dictionary values.
weight : str, default=None
The attribute to use as weight. If `None`, all weights are considered to be
one.
sparse : bool, default=True
Whether to return a sparse or dense incidence matrix.
index : bool, default=False
If True, return will include a dictionary of children uid: row number
and element uid: column number.
If True, return will include a dictionary of node uid: row number
and cell uid: column number.
Returns
-------
incidence_matrix : scipy.sparse.csr.csr_matrix or numpy.ndarray
incidence_matrix : scipy.sparse.csr.csr_matrix or np.ndarray
The incidence matrix.
row dictionary : dict
Dictionary identifying rows with items in the entityset's children.
Dictionary identifying rows with nodes.
column dictionary : dict
Dictionary identifying columns with items in the entityset's uidset.
Notes
-----
The `incidence_matrix` method is for generating the incidence matrix of a ColoredHyperGraph.
An incidence matrix describes the relationships between the hyperedges
of a complex. The rows correspond to the hyperedges, and the columns correspond to the faces.
The entries in the matrix are either 0 or 1, depending on whether a hyperedge contains a given face or not.
For example, if hyperedge i contains face j, then the entry in the ith row and jth column of the matrix will be 1,
otherwise, it will be 0.
To generate the incidence matrix, the method first creates a dictionary where the keys are the faces
of the complex, and the values are the hyperedges that contain that face.
The method then iterates over the hyperedges in the `HyperEdgeView` instance,
and for each hyperedge, it checks which faces it contains.
For each face that the hyperedge contains, the method increments the corresponding entry in the matrix.
Finally, the method returns the completed incidence matrix.
Dictionary identifying columns with cells.
"""
if rank == to_rank:
raise ValueError("incidence must be computed for k!=r, got equal r and k.")
Expand All @@ -1079,43 +1064,6 @@ def _incidence_matrix(

return compute_set_incidence(children, uidset, sparse, index)

def incidence_matrix(
self,
rank: int,
to_rank: int,
weight: bool | None = None,
sparse: bool = True,
index: bool = False,
):
"""Compute incidence matrix for the CHG indexed by nodes x cells.
Parameters
----------
rank : int
The rank for computing the incidence matrix.
to_rank : int
The rank for computing the incidence matrix.
weight : bool, default=None
If False, all nonzero entries are 1.
If True and self.static, all nonzero entries are filled by
self.cells.cell_weight dictionary values.
sparse : bool, default=True
Whether to return a sparse or dense incidence matrix.
index : bool, default False
If True, return will include a dictionary of node uid: row number
and cell uid: column number.
Returns
-------
incidence_matrix : scipy.sparse.csr.csr_matrix or np.ndarray
The incidence matrix.
row dictionary : dict
Dictionary identifying rows with nodes.
column dictionary : dict
Dictionary identifying columns with cells.
"""
return self._incidence_matrix(rank, to_rank, sparse=sparse, index=index)

def node_to_all_cell_incidence_matrix(
self, weight: str | None = None, index: bool = False
) -> scipy.sparse.csc_matrix | tuple[dict, dict, scipy.sparse.csc_matrix]:
Expand Down Expand Up @@ -1312,7 +1260,7 @@ def coadjacency_matrix(self, rank, via_rank, s: int = 1, index: bool = False):
return A

def degree_matrix(self, rank: int, index: bool = False):
"""Compute the degree matrix.
"""Compute the node-degree matrix.
Parameters
----------
Expand All @@ -1327,18 +1275,19 @@ def degree_matrix(self, rank: int, index: bool = False):
Dictionary identifying rows with nodes. If False, this does not exist.
degree_matrix : scipy.sparse.csr.csr_matrix
The degree matrix.
Raises
------
ValueError
If the rank is not in the range of the Colored Hypergraph.
"""
if rank < 1:
if not self.dim >= rank > 0:
raise ValueError(
"rank for the degree matrix must be larger or equal to 1, got {rank}"
f"Cannot compute degree matrix for rank {rank} in a {self.dim}-dimensional complex."
)

rowdict, _, M = self.incidence_matrix(0, rank, index=True)
if M.shape == (0, 0):
D = np.zeros(self.num_nodes)
else:
D = np.ravel(np.sum(M, axis=1))

D = np.ravel(np.sum(M, axis=1))
return (rowdict, D) if index else D

def laplacian_matrix(self, rank, sparse=False, index=False):
Expand All @@ -1359,25 +1308,27 @@ def laplacian_matrix(self, rank, sparse=False, index=False):
Array of dimension (N, N), where N is the number of nodes in the Colored Hypergraph.
If index is True, return a dictionary mapping node uid to row number.
Raises
------
ValueError
If the rank is not in the range of the Colored Hypergraph.
References
----------
.. [1] Lucas, M., Cencetti, G., & Battiston, F. (2020).
Multiorder Laplacian for synchronization in higher-order networks.
Physical Review Research, 2(3), 033410.
"""
if rank < 1:
if not 0 < rank <= self.dim:
raise ValueError(
"rank for the laplacian matrix must be larger or equal to 1, got {rank}"
f"Cannot compute Laplacian matrix for rank {rank} in a {self.dim}-dimensional complex."
)

if len(self.nodes) == 0:
A = np.empty((0, 0))
else:
row_dict, A = self.adjacency_matrix(0, rank, index=True)

if A.shape == (0, 0):
L = csr_array((0, 0)) if sparse else np.empty((0, 0))
return ({}, L) if index else L

if sparse:
K = csr_array(diags(self.degree_matrix(rank)))
else:
Expand Down
6 changes: 3 additions & 3 deletions toponetx/classes/combinatorial_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class CombinatorialComplex(ColoredHyperGraph):
A Combinatorial Complex (CCC) is a triple $CCC = (S, X, rk)$ where:
- $S$ is an abstract set of entities,
- $X$ a subset of the power set of $X$, and
- $X$ a subset of the power set of $S$, and
- $rk$ is the a rank function that associates for every set x in X a rank, a positive integer.
The rank function $rk$ must satisfy $x \leq y$ then $rk(x) \leq rk(y)$.
The rank function $rk$ must satisfy $x \subseteq y$ then $rk(x) \leq rk(y)$.
We call this condition the CCC condition.
A CCC is a generalization of graphs, hypergraphs, cellular and simplicial complexes.
Expand Down Expand Up @@ -564,7 +564,7 @@ def _add_hyperedge_helper(self, hyperedge_, rank, **attr):
self._node_membership[i] = set()
self._node_membership[i].add(hyperedge_)

def _CCC_condition(self, hyperedge_, rank):
def _CCC_condition(self, hyperedge_: set, rank: int) -> None:
"""Check if hyperedge_ satisfies the CCC condition.
Parameters
Expand Down

0 comments on commit 0e33fad

Please sign in to comment.