Skip to content

Commit

Permalink
Method for k-skeleton of a SC (#578)
Browse files Browse the repository at this point in the history
* feat: function + test

* style: formatted with black

* fix: iteration over orders

* fix: removed iteration across orders

* test: added test for k=0, related to #581

* style: black

* docs: added explanation + link to ref

* docs: rephrased definition

* moved function to `convert.simplex` + created file for test

* added k_skeleton to api rst file

* use `max_edge_order` function

* created cut_to_order + modified k_skeleton + tests

* added cut_to_order to api

* style: black

* minor change for consistency with other functions

* modified recipe

* changed formatting in the recipe
  • Loading branch information
thomasrobiglio authored Sep 12, 2024
1 parent 032f7a2 commit 52c7938
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 49 deletions.
3 changes: 2 additions & 1 deletion docs/source/api/convert/xgi.convert.higher_order_network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ xgi.convert.higher_order_network

.. autofunction:: to_hypergraph
.. autofunction:: to_dihypergraph
.. autofunction:: to_simplicial_complex
.. autofunction:: to_simplicial_complex
.. autofunction:: cut_to_order
3 changes: 2 additions & 1 deletion docs/source/api/convert/xgi.convert.simplex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ xgi.convert.simplex
.. rubric:: Functions

.. autofunction:: from_max_simplices
.. autofunction:: from_simplex_dict
.. autofunction:: from_simplex_dict
.. autofunction:: k_skeleton
17 changes: 17 additions & 0 deletions tests/convert/test_higher_order_network.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import pytest

import xgi
from xgi.exception import XGIError


def test_convert_empty_hypergraph():
Expand Down Expand Up @@ -71,3 +74,17 @@ def test_convert_pandas_dataframe_to_simplicial_complex(dataframe5):
assert isinstance(SC, xgi.SimplicialComplex)
assert set(SC.nodes) == set(dataframe5["col1"])
assert SC.edges.maximal().members() == [{0, 1, 2, 3}, {4}, {5, 6}, {8, 6, 7}]


def test_cut_to_order(edgelist1, edgelist3):
H = xgi.Hypergraph(edgelist1)
H_cut = xgi.cut_to_order(H, 1)
edges_cut = [frozenset({4}), frozenset({5, 6})]
assert H_cut.edges.members() == edges_cut

with pytest.raises(XGIError):
xgi.cut_to_order(H, 5)

H1 = xgi.Hypergraph(edgelist3)
H1_cut = xgi.cut_to_order(H1, 0)
assert H1_cut.num_edges == 0
24 changes: 24 additions & 0 deletions tests/convert/test_k_skeleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest

import xgi
from xgi.exception import XGIError


def test_k_skeleton(edgelist1, edgelist2):
S = xgi.SimplicialComplex(edgelist1)
S1 = xgi.k_skeleton(S, 1)
edges_skeleton = [
frozenset({4}),
frozenset({5, 6}),
frozenset({1, 2}),
frozenset({8, 7}),
frozenset({2, 3}),
frozenset({6, 7}),
frozenset({8, 6}),
frozenset({1, 3}),
]
assert set(S1.edges.members()) == set(edges_skeleton)

H = xgi.Hypergraph(edgelist2)
with pytest.raises(XGIError):
xgi.k_skeleton(H, 2)
86 changes: 40 additions & 46 deletions tutorials/recipes/recipes.ipynb

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions xgi/convert/higher_order_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
from .incidence import from_incidence_matrix
from .pandas import from_bipartite_pandas_dataframe
from .simplex import from_simplex_dict
from ..algorithms.properties import max_edge_order

__all__ = [
"to_hypergraph",
"to_dihypergraph",
"to_simplicial_complex",
"cut_to_order",
]


Expand Down Expand Up @@ -270,3 +272,31 @@ def to_simplicial_complex(data, create_using=None):
)
else:
raise XGIError("Input data has unsupported type.")


def cut_to_order(H, order):
"""Returns a copy of the higher-order network with edges of order less than or equal to the given order.
Parameters
----------
H : Hypergraph
The higher-order network to cut
order : int
The order of the edges to keep
Returns
-------
Hypergraph object
A copy of the higher-order network with edges of order less than or equal to the given order
"""
_H = H.copy()
max_order = max_edge_order(H)
if order > max_order:
raise XGIError(f"The order must be less than or equal to {max_order}")
if order != max_order:
bunch = _H.edges.filterby("order", order, "gt")
if type(_H) == SimplicialComplex:
_H.remove_simplex_ids_from(bunch)
else:
_H.remove_edges_from(bunch)
return _H
27 changes: 26 additions & 1 deletion xgi/convert/simplex.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ..exception import XGIError
from ..generators import empty_simplicial_complex

__all__ = ["from_simplex_dict", "from_max_simplices"]
__all__ = ["from_simplex_dict", "from_max_simplices", "k_skeleton"]


def from_simplex_dict(d, create_using=None):
Expand Down Expand Up @@ -53,3 +53,28 @@ def from_max_simplices(SC):
H.add_nodes_from(SC.nodes) # to keep node order and isolated nodes
H.add_edges_from([list(SC.edges.members(e)) for e in max_simplices])
return H


def k_skeleton(SC, order):
"""Returns the k-skeleton of the simplicial complex.
The :math:`k`-skeleton of a simplicial complex is the subcomplex
containing all the simplices of the original complex of dimension at most :math:`k`.
Parameters
----------
SC : SimplicialComplex
The simplicial complex to return the k-skeleton of.
order : int
The order (k) of the skeleton to return.
References
----------
https://en.wikipedia.org/wiki/N-skeleton
"""
from .higher_order_network import cut_to_order

if type(SC) != SimplicialComplex:
raise XGIError("The input must be a SimplicialComplex")
return cut_to_order(SC, order)

0 comments on commit 52c7938

Please sign in to comment.