Skip to content

Commit ad44ce4

Browse files
committed
initial implementation of s-connectedness
1 parent 80b06e2 commit ad44ce4

6 files changed

Lines changed: 109 additions & 30 deletions

File tree

examples/layouts/plot_barycenter_spring_layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
=================
3-
Barycenter spring
3+
Barycenter spring
44
=================
55
66
Draw simple hypergraph with barycenter_spring layout.

examples/layouts/plot_simple_graph.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
=================
3-
Circular
3+
Circular
44
=================
55
66
Draw simple hypergraph with circular layout.

examples/layouts/plot_spiral_layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
=================
3-
Spiral
3+
Spiral
44
=================
55
66
Draw simple hypergraph with spiral layout.

examples/layouts/plot_triangular_lattice.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import xgi
1313

1414
# generate lattice
15-
m, n = 5, 10 # lattice dimensions
16-
p = 0.5 # probability to promote 3-clique to 2-simplex
15+
m, n = 5, 10 # lattice dimensions
16+
p = 0.5 # probability to promote 3-clique to 2-simplex
1717

1818
G = nx.triangular_lattice_graph(m, n, with_positions=True)
1919

@@ -22,10 +22,10 @@
2222
inv_mapping = {v: k for k, v in mapping.items()}
2323

2424
G_aux = nx.relabel_nodes(G, inv_mapping)
25-
S = xgi.flag_complex_d2(G_aux, p2=p)
25+
S = xgi.flag_complex_d2(G_aux, p2=p)
2626

2727
# draw lattice
2828
pos = {inv_mapping[k]: v for k, v in pos.items()}
2929
xgi.draw(S, pos=pos)
3030

31-
plt.show()
31+
plt.show()

tests/algorithms/test_connected.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ def test_connected_components(edgelist1, edgelist2, edgelist4):
2828
assert sorted([len(cc) for cc in cc3]) == [5]
2929
assert {1, 2, 3, 4, 5} in cc3
3030

31+
cc4 = list(xgi.connected_components(H3, s=3))
32+
33+
assert sorted([len(cc) for cc in cc1]) == [1, 3, 4]
34+
3135

3236
def test_number_connected_components(edgelist1, edgelist2, edgelist4):
3337
H1 = xgi.Hypergraph(edgelist1)

xgi/algorithms/connected.py

Lines changed: 98 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
]
1414

1515

16-
def is_connected(H):
16+
def is_connected(H, s=1):
1717
"""
1818
A function to determine whether a hypergraph is connected.
1919
2020
Parameters
2121
----------
2222
H: Hypergraph object
2323
The hypergraph of interest
24+
s: int, optional
25+
The overlap parameter
2426
2527
Returns
2628
-------
@@ -34,6 +36,13 @@ def is_connected(H):
3436
largest_connected_component
3537
largest_connected_hypergraph
3638
39+
References
40+
----------
41+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
42+
Hypernetwork science via high-order hypergraph walks.
43+
EPJ Data Sci. 9, 16 (2020).
44+
https://doi.org/10.1140/epjds/s13688-020-00231-0
45+
3746
Example
3847
-------
3948
>>> import xgi
@@ -42,17 +51,19 @@ def is_connected(H):
4251
True
4352
4453
"""
45-
return len(_plain_bfs(H, list(H.nodes)[0])) == len(H)
54+
return len(_plain_bfs(H, list(H.nodes)[0], s=s)) == len(H)
4655

4756

48-
def connected_components(H):
57+
def connected_components(H, s=1):
4958
"""
5059
A function to find the connected components of a hypergraph.
5160
5261
Parameters
5362
----------
5463
H: Hypergraph object
5564
The hypergraph of interest
65+
s: int, optional
66+
The overlap parameter
5667
5768
Returns
5869
-------
@@ -66,6 +77,13 @@ def connected_components(H):
6677
largest_connected_component
6778
largest_connected_hypergraph
6879
80+
References
81+
----------
82+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
83+
Hypernetwork science via high-order hypergraph walks.
84+
EPJ Data Sci. 9, 16 (2020).
85+
https://doi.org/10.1140/epjds/s13688-020-00231-0
86+
6987
Example
7088
-------
7189
>>> import xgi
@@ -77,19 +95,21 @@ def connected_components(H):
7795
seen = set()
7896
for v in H:
7997
if v not in seen:
80-
c = _plain_bfs(H, v)
98+
c = _plain_bfs(H, v, s=s)
8199
seen.update(c)
82100
yield c
83101

84102

85-
def number_connected_components(H):
103+
def number_connected_components(H, s=1):
86104
"""
87105
A function to find the number of connected components of a hypergraph.
88106
89107
Parameters
90108
----------
91109
H: Hypergraph object
92110
The hypergraph of interest
111+
s: int, optional
112+
The overlap parameter
93113
94114
Returns
95115
-------
@@ -103,6 +123,13 @@ def number_connected_components(H):
103123
largest_connected_component
104124
largest_connected_hypergraph
105125
126+
References
127+
----------
128+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
129+
Hypernetwork science via high-order hypergraph walks.
130+
EPJ Data Sci. 9, 16 (2020).
131+
https://doi.org/10.1140/epjds/s13688-020-00231-0
132+
106133
Example
107134
-------
108135
>>> import xgi
@@ -115,20 +142,22 @@ def number_connected_components(H):
115142
seen = set()
116143
for v in H:
117144
if v not in seen:
118-
c = _plain_bfs(H, v)
145+
c = _plain_bfs(H, v, s=s)
119146
seen.update(c)
120147
num_cc += 1
121148
return num_cc
122149

123150

124-
def largest_connected_component(H):
151+
def largest_connected_component(H, s=1):
125152
"""
126153
A function to find the largest connected component of a hypergraph.
127154
128155
Parameters
129156
----------
130157
H: Hypergraph object
131158
The hypergraph of interest
159+
s: int, optional
160+
The overlap parameter
132161
133162
Returns
134163
-------
@@ -140,6 +169,13 @@ def largest_connected_component(H):
140169
connected_components
141170
largest_connected_hypergraph
142171
172+
References
173+
----------
174+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
175+
Hypernetwork science via high-order hypergraph walks.
176+
EPJ Data Sci. 9, 16 (2020).
177+
https://doi.org/10.1140/epjds/s13688-020-00231-0
178+
143179
Example
144180
-------
145181
>>> import xgi
@@ -148,10 +184,10 @@ def largest_connected_component(H):
148184
50
149185
150186
"""
151-
return max(connected_components(H), key=len)
187+
return max(connected_components(H, s=s), key=len)
152188

153189

154-
def node_connected_component(H, n):
190+
def node_connected_component(H, n, s=1):
155191
"""
156192
A function to find the connected component of which a node in the
157193
hypergraph is a part.
@@ -162,6 +198,8 @@ def node_connected_component(H, n):
162198
The hypergraph of interest
163199
n: hashable
164200
Node label
201+
s: int, optional
202+
The overlap parameter
165203
166204
See Also
167205
--------
@@ -173,6 +211,13 @@ def node_connected_component(H, n):
173211
Returns the connected component of which the specified node in the
174212
hypergraph is a part.
175213
214+
References
215+
----------
216+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
217+
Hypernetwork science via high-order hypergraph walks.
218+
EPJ Data Sci. 9, 16 (2020).
219+
https://doi.org/10.1140/epjds/s13688-020-00231-0
220+
176221
Example
177222
-------
178223
>>> import xgi
@@ -183,19 +228,21 @@ def node_connected_component(H, n):
183228
184229
"""
185230
if n in H:
186-
return _plain_bfs(H, n)
231+
return _plain_bfs(H, n, s=s)
187232
else:
188233
raise XGIError("Specified node is not in the hypergraph!")
189234

190235

191-
def largest_connected_hypergraph(H, in_place=False):
236+
def largest_connected_hypergraph(H, s=1, in_place=False):
192237
"""
193238
A function to find the largest connected hypergraph from a data set.
194239
195240
Parameters
196241
----------
197242
H: Hypergraph
198243
The hypergraph of interest
244+
s: int, optional
245+
The overlap parameter
199246
in_place: bool, optional
200247
If False, creates a copy; if True, modifies the existing hypergraph.
201248
By default, True.
@@ -214,35 +261,63 @@ def largest_connected_hypergraph(H, in_place=False):
214261
connected_components
215262
largest_connected_component
216263
264+
References
265+
----------
266+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
267+
Hypernetwork science via high-order hypergraph walks.
268+
EPJ Data Sci. 9, 16 (2020).
269+
https://doi.org/10.1140/epjds/s13688-020-00231-0
270+
217271
Example
218272
-------
219273
>>> import xgi
220274
>>> H = xgi.random_hypergraph(10, [0.1, 0.01], seed=1)
221275
>>> H_gcc = xgi.largest_connected_hypergraph(H)
222276
>>> print(H_gcc.num_nodes)
223277
6
224-
225278
"""
226-
connected_nodes = max(connected_components(H), key=len)
279+
connected_nodes = max(connected_components(H, s=s), key=len)
227280
if not in_place:
228281
return subhypergraph(H, nodes=connected_nodes).copy()
229282
else:
230283
H.remove_nodes_from(set(H.nodes).difference(connected_nodes))
231284

232285

233-
def _plain_bfs(H, source):
234-
"""A fast BFS node generator
286+
def _plain_bfs(H, source, s=1):
287+
"""A helper function to do an edge-first BFS search
288+
289+
Parameters
290+
----------
291+
H : xgi.Hypergraph
292+
The hypergraph
293+
source : hashable
294+
The ID of the starting node for the BFS
295+
s : int, optional
296+
The overlap of edges, by default 1
235297
236-
Source:
298+
Returns
299+
-------
300+
set
301+
A list of all nodes in the s-component.
302+
303+
References
304+
----------
237305
https://networkx.org/documentation/stable/_modules/networkx/algorithms/components/connected.html
306+
307+
Aksoy, S.G., Joslyn, C., Ortiz Marrero, C. et al.
308+
Hypernetwork science via high-order hypergraph walks.
309+
EPJ Data Sci. 9, 16 (2020).
310+
https://doi.org/10.1140/epjds/s13688-020-00231-0
238311
"""
239-
seen = set()
240-
nextlevel = {source}
312+
seen_edges = set()
313+
nodes = {source}
314+
nextlevel = set(H.edges(H.nodes.memberships(source)).filterby("size", s, "geq"))
241315
while nextlevel:
242316
thislevel = nextlevel
243317
nextlevel = set()
244-
for v in thislevel:
245-
if v not in seen:
246-
seen.add(v)
247-
nextlevel.update(H.nodes.neighbors(v))
248-
return seen
318+
for e in thislevel:
319+
if e not in seen_edges:
320+
nodes.update(H.edges.members(e))
321+
seen_edges.add(e)
322+
nextlevel.update(H.edges.neighbors(e, s=s))
323+
return nodes

0 commit comments

Comments
 (0)