Skip to content

Commit 8cc5557

Browse files
leotrsclaude
andcommitted
feat: add seed parameter to unseeded stochastic functions
Add seed parameter to h_eigenvector_centrality, degree_assortativity, simulate_kuramoto, and random_edge_shuffle for reproducibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent cc32ef6 commit 8cc5557

4 files changed

Lines changed: 26 additions & 6 deletions

File tree

xgi/algorithms/assortativity.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def dynamical_assortativity(H):
6565
return kk1 * k1**2 / k2**2 - 1
6666

6767

68-
def degree_assortativity(H, kind="uniform", exact=False, num_samples=1000):
68+
def degree_assortativity(H, kind="uniform", exact=False, num_samples=1000, seed=None):
6969
"""Computes the degree assortativity of a hypergraph
7070
7171
Parameters
@@ -81,6 +81,8 @@ def degree_assortativity(H, kind="uniform", exact=False, num_samples=1000):
8181
num_samples : int, optional
8282
if not exact, specify the number of samples for the computation.
8383
By default, 1000.
84+
seed : int or None, optional
85+
The seed for the random number generator. By default, None.
8486
8587
Returns
8688
-------
@@ -104,6 +106,10 @@ def degree_assortativity(H, kind="uniform", exact=False, num_samples=1000):
104106
DOI: 10.1093/comnet/cnaa018
105107
"""
106108

109+
if seed is not None:
110+
random.seed(seed)
111+
np.random.seed(seed)
112+
107113
if H.num_nodes == 0:
108114
raise XGIError("Hypergraph must contain nodes")
109115
elif H.num_edges == 0:

xgi/algorithms/centrality.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def katz_centrality(H, cutoff=100):
294294
return {nodedict[idx]: c[idx] for idx in nodedict}
295295

296296

297-
def h_eigenvector_centrality(H, max_iter=100, tol=1e-6):
297+
def h_eigenvector_centrality(H, max_iter=100, tol=1e-6, seed=None):
298298
"""Compute the H-eigenvector centrality of a hypergraph.
299299
300300
The H-eigenvector terminology comes from Qi (2005) which
@@ -309,6 +309,8 @@ def h_eigenvector_centrality(H, max_iter=100, tol=1e-6):
309309
By default, 100.
310310
tol : float > 0, optional
311311
The desired convergence tolerance. By default, 1e-6.
312+
seed : int or None, optional
313+
The seed for the random number generator. By default, None.
312314
313315
Returns
314316
-------
@@ -354,6 +356,9 @@ def h_eigenvector_centrality(H, max_iter=100, tol=1e-6):
354356
node_dict = new_H.nodes.memberships()
355357
r = new_H.edges.size.max()
356358

359+
if seed is not None:
360+
np.random.seed(seed)
361+
357362
x = np.random.uniform(size=(new_H.num_nodes))
358363
x = x / norm(x, 1)
359364
y = np.abs(np.array(ttsv1(node_dict, edge_dict, r, x)))

xgi/core/hypergraph.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ def double_edge_swap(self, n_id1, n_id2, e_id1, e_id2):
974974
self._edge[e_id1] = temp_members1
975975
self._edge[e_id2] = temp_members2
976976

977-
def random_edge_shuffle(self, e_id1=None, e_id2=None):
977+
def random_edge_shuffle(self, e_id1=None, e_id2=None, seed=None):
978978
"""Randomly redistributes nodes between two hyperedges.
979979
980980
The process is as follows:
@@ -989,6 +989,8 @@ def random_edge_shuffle(self, e_id1=None, e_id2=None):
989989
ID of first edge to shuffle.
990990
e_id2 : node ID, optional
991991
ID of second edge to shuffle.
992+
seed : int or None, optional
993+
The seed for the random number generator. By default, None.
992994
993995
Note
994996
----
@@ -1007,13 +1009,15 @@ def random_edge_shuffle(self, e_id1=None, e_id2=None):
10071009
Example
10081010
-------
10091011
>>> import xgi
1010-
>>> random.seed(42)
10111012
>>> H = xgi.Hypergraph([[1, 2, 3], [3, 4], [4, 5]])
1012-
>>> H.random_edge_shuffle()
1013+
>>> H.random_edge_shuffle(seed=42)
10131014
>>> H.edges.members()
10141015
[{2, 4, 5}, {3, 4}, {1, 3}]
10151016
10161017
"""
1018+
if seed is not None:
1019+
random.seed(seed)
1020+
10171021
if len(self._edge) < 2:
10181022
raise ValueError("Hypergraph must have at least two edges.")
10191023

xgi/dynamics/synchronization.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
]
1616

1717

18-
def simulate_kuramoto(H, k2, k3, omega=None, theta=None, timesteps=10000, dt=0.002):
18+
def simulate_kuramoto(H, k2, k3, omega=None, theta=None, timesteps=10000, dt=0.002, seed=None):
1919
"""Simulates the Kuramoto model on hypergraphs.
2020
This solves the Kuramoto model ODE on hypergraphs with edges of sizes 2 and 3
2121
using the Euler Method. It returns timeseries of the phases.
@@ -38,6 +38,8 @@ def simulate_kuramoto(H, k2, k3, omega=None, theta=None, timesteps=10000, dt=0.0
3838
The number of timesteps for Euler Method.
3939
dt : float greater than 0, default: 0.002
4040
The size of timesteps for Euler Method.
41+
seed : int or None, optional
42+
The seed for the random number generator. By default, None.
4143
4244
Returns
4345
-------
@@ -74,6 +76,9 @@ def simulate_kuramoto(H, k2, k3, omega=None, theta=None, timesteps=10000, dt=0.0
7476
theta_time = np.zeros((timesteps, n))
7577
times = np.arange(timesteps) * dt
7678

79+
if seed is not None:
80+
np.random.seed(seed)
81+
7782
if omega is None:
7883
omega = np.random.normal(0, 1, n)
7984

0 commit comments

Comments
 (0)