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

Method for k-skeleton of a SC #578

Merged
merged 17 commits into from
Sep 12, 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
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)
Loading