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

Removed random decorators #227

Merged
merged 2 commits into from
Nov 17, 2022
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
7 changes: 4 additions & 3 deletions xgi/drawing/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from .. import convert
from ..classes import SimplicialComplex, max_edge_order
from ..utils import np_random_state

__all__ = [
"random_layout",
Expand All @@ -14,7 +13,6 @@
]


@np_random_state("seed")
def random_layout(H, center=None, dim=2, seed=None):
"""Position nodes uniformly at random in the unit square. Exactly as networkx does.
For every node, a position is generated by choosing each of dim
Expand Down Expand Up @@ -52,8 +50,11 @@ def random_layout(H, center=None, dim=2, seed=None):
"""
import numpy as np

if seed is not None:
np.random.seed(seed)

H, center = nx.drawing.layout._process_params(H, center, dim)
pos = seed.rand(len(H), dim) + center
pos = np.random.rand(len(H), dim) + center
pos = pos.astype(np.float32)
pos = dict(zip(H, pos))

Expand Down
10 changes: 7 additions & 3 deletions xgi/generators/classic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

"""

import random
from collections import defaultdict
from itertools import combinations
from warnings import warn
Expand All @@ -13,7 +14,6 @@

from ..classes.function import subfaces
from ..exception import XGIError
from ..utils import py_random_state

__all__ = [
"empty_hypergraph",
Expand Down Expand Up @@ -177,7 +177,6 @@ def star_clique(n_star, n_clique, d_max):
return H


@py_random_state("seed")
def flag_complex(G, max_order=2, ps=None, seed=None):
"""Generate a flag (or clique) complex from a
NetworkX graph by filling all cliques up to dimension max_order.
Expand All @@ -193,6 +192,8 @@ def flag_complex(G, max_order=2, ps=None, seed=None):
hyperedge from a clique, at each order d. For example,
ps[0] is the probability of promoting any 3-node clique (triangle) to
a 3-hyperedge.
seed: int or None (default)
The seed for the random number generator

Returns
-------
Expand All @@ -207,6 +208,9 @@ def flag_complex(G, max_order=2, ps=None, seed=None):
# defined. Otherwise, a circular import error would happen.
from ..classes import SimplicialComplex

if seed is not None:
random.seed(seed)

nodes = G.nodes()
edges = G.edges()

Expand All @@ -233,7 +237,7 @@ def flag_complex(G, max_order=2, ps=None, seed=None):
# promote cliques with a given probability
for i, p in enumerate(ps[: max_order - 1]):
d = i + 2 # simplex order
cliques_d_to_add = [el for el in cliques_d[d + 1] if seed.random() <= p]
cliques_d_to_add = [el for el in cliques_d[d + 1] if random.random() <= p]
S.add_simplices_from(cliques_d_to_add, max_order=max_order)

return S
Expand Down
59 changes: 35 additions & 24 deletions xgi/generators/nonuniform.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Generate random (non-uniform) hypergraphs."""
import math
import random
import warnings
from collections import defaultdict
from itertools import combinations
Expand All @@ -8,7 +9,6 @@
import numpy as np

from ..classes import SimplicialComplex
from ..utils import np_random_state, py_random_state
from .classic import empty_hypergraph, ring_lattice

__all__ = [
Expand All @@ -22,7 +22,6 @@
]


@py_random_state("seed")
def chung_lu_hypergraph(k1, k2, seed=None):
"""A function to generate a Chung-Lu hypergraph

Expand All @@ -34,8 +33,8 @@ def chung_lu_hypergraph(k1, k2, seed=None):
k2 : dictionary
Dictionary where the keys are edge ids
and the values are edge sizes.
seed : integer, random_state, or None (default)
Indicator of random number generation state.
seed : integer or None (default)
The seed for the random number generator.

Returns
-------
Expand Down Expand Up @@ -68,6 +67,9 @@ def chung_lu_hypergraph(k1, k2, seed=None):
>>> H = xgi.chung_lu_hypergraph(k1, k2)

"""
if seed is not None:
random.seed(seed)

# sort dictionary by degree in decreasing order
node_labels = [n for n, _ in sorted(k1.items(), key=lambda d: d[1], reverse=True)]
edge_labels = [m for m, _ in sorted(k2.items(), key=lambda d: d[1], reverse=True)]
Expand All @@ -91,7 +93,7 @@ def chung_lu_hypergraph(k1, k2, seed=None):

while j < m:
if p != 1:
r = seed.random()
r = random.random()
try:
j = j + math.floor(math.log(r) / math.log(1 - p))
except ZeroDivisionError:
Expand All @@ -100,7 +102,7 @@ def chung_lu_hypergraph(k1, k2, seed=None):
if j < m:
v = edge_labels[j]
q = min((k1[u] * k2[v]) / S, 1)
r = seed.random()
r = random.random()
if r < q / p:
# no duplicates
H.add_node_to_edge(v, u)
Expand All @@ -110,7 +112,6 @@ def chung_lu_hypergraph(k1, k2, seed=None):
return H


@py_random_state("seed")
def dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=None):
"""A function to generate a DCSBM hypergraph.

Expand All @@ -136,8 +137,8 @@ def dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=None):
The number of rows must match the number of node communities
and the number of columns must match the number of edge
communities.
seed : int, random_state, or None (default)
Indicator of random number generation state.
seed : int or None (default)
Seed for the random number generator.

Returns
-------
Expand Down Expand Up @@ -175,6 +176,8 @@ def dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=None):
>>> # H = xgi.dcsbm_hypergraph(k1, k2, g1, g2, omega)

"""
if seed is not None:
random.seed(seed)

# sort dictionary by degree in decreasing order
node_labels = [n for n, _ in sorted(k1.items(), key=lambda d: d[1], reverse=True)]
Expand Down Expand Up @@ -230,15 +233,15 @@ def dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=None):
p = min(k1[u] * k2[v] * group_constant, 1)
while j < len(community2_nodes[group2]):
if p != 1:
r = seed.random()
r = random.random()
try:
j = j + math.floor(math.log(r) / math.log(1 - p))
except ZeroDivisionError:
j = np.inf
if j < len(community2_nodes[group2]):
v = community2_nodes[group2][j]
q = min((k1[u] * k2[v]) * group_constant, 1)
r = seed.random()
r = random.random()
if r < q / p:
# no duplicates
H.add_node_to_edge(v, u)
Expand All @@ -247,7 +250,6 @@ def dcsbm_hypergraph(k1, k2, g1, g2, omega, seed=None):
return H


@py_random_state("seed")
def random_hypergraph(N, ps, seed=None):
"""Generates a random hypergraph

Expand All @@ -263,8 +265,8 @@ def random_hypergraph(N, ps, seed=None):
hyperedge at each order d between any d+1 nodes. For example,
ps[0] is the wiring probability of any edge (2 nodes), ps[1]
of any triangles (3 nodes).
seed : integer, random_state, or None (default)
Indicator of random number generation state.
seed : integer or None (default)
Seed for the random number generator.

Returns
-------
Expand All @@ -281,6 +283,8 @@ def random_hypergraph(N, ps, seed=None):
>>> H = xgi.random_hypergraph(50, [0.1, 0.01])

"""
if seed is not None:
random.seed(seed)

if (np.any(np.array(ps) < 0)) or (np.any(np.array(ps) > 1)):
raise ValueError("All elements of ps must be between 0 and 1 included.")
Expand All @@ -292,7 +296,7 @@ def random_hypergraph(N, ps, seed=None):
d = i + 1 # order, ps[0] is prob of edges (d=1)

for hyperedge in combinations(nodes, d + 1):
if seed.random() <= p:
if random.random() <= p:
hyperedges.append(hyperedge)

hyperedges += [[i] for i in nodes] # add singleton edges
Expand All @@ -304,7 +308,6 @@ def random_hypergraph(N, ps, seed=None):
return H


@py_random_state("seed")
def random_simplicial_complex(N, ps, seed=None):
"""Generates a random hypergraph

Expand All @@ -321,6 +324,8 @@ def random_simplicial_complex(N, ps, seed=None):
hyperedge at each order d between any d+1 nodes. For example,
ps[0] is the wiring probability of any edge (2 nodes), ps[1]
of any triangles (3 nodes).
seed : int or None (default)
The seed for the random number generator

Returns
-------
Expand All @@ -340,6 +345,8 @@ def random_simplicial_complex(N, ps, seed=None):
>>> H = xgi.random_simplicial_complex(20, [0.1, 0.01])

"""
if seed is not None:
random.seed(seed)

if (np.any(np.array(ps) < 0)) or (np.any(np.array(ps) > 1)):
raise ValueError("All elements of ps must be between 0 and 1 included.")
Expand All @@ -351,7 +358,7 @@ def random_simplicial_complex(N, ps, seed=None):
d = i + 1 # order, ps[0] is prob of edges (d=1)

for simplex in combinations(nodes, d + 1):
if seed.random() <= p:
if random.random() <= p:
simplices.append(simplex)

S = SimplicialComplex()
Expand All @@ -361,7 +368,6 @@ def random_simplicial_complex(N, ps, seed=None):
return S


@py_random_state("seed")
def random_flag_complex_d2(N, p, seed=None):
"""Generate a maximal simplicial complex (up to order 2) from a
:math:`G_{N,p}` Erdős-Rényi random graph by filling all empty triangles with 2-simplices.
Expand All @@ -373,6 +379,8 @@ def random_flag_complex_d2(N, p, seed=None):
p : float
Probabilities (between 0 and 1) to create an edge
between any 2 nodes
seed : int or None (default)
The seed for the random number generator

Returns
-------
Expand All @@ -382,6 +390,8 @@ def random_flag_complex_d2(N, p, seed=None):
-----
Computing all cliques quickly becomes heavy for large networks.
"""
if seed is not None:
random.seed(seed)

if (p < 0) or (p > 1):
raise ValueError("p must be between 0 and 1 included.")
Expand All @@ -404,7 +414,6 @@ def random_flag_complex_d2(N, p, seed=None):
return S


@py_random_state(3)
def random_flag_complex(N, p, max_order=2, seed=None):
"""Generate a flag (or clique) complex from a
:math:`G_{N,p}` Erdős-Rényi random graph by filling all cliques up to dimension max_order.
Expand All @@ -416,9 +425,10 @@ def random_flag_complex(N, p, max_order=2, seed=None):
p : float
Probabilities (between 0 and 1) to create an edge
between any 2 nodes

max_order : int
maximal dimension of simplices to add to the output simplicial complex
seed : int or None (default)
The seed for the random number generator

Returns
-------
Expand Down Expand Up @@ -447,16 +457,17 @@ def random_flag_complex(N, p, max_order=2, seed=None):
return S


@np_random_state("seed")
def watts_strogatz_hypergraph(n, d, k, l, p, seed=None):
if seed is not None:
np.random.seed(seed)
H = ring_lattice(n, d, k, l)
to_remove = []
to_add = []
for e in H.edges:
if seed.random() < p:
if np.random.random() < p:
to_remove.append(e)
node = H.edges.members(e)[0]
neighbors = seed.choice(H.nodes, size=d - 1)
node = min(H.edges.members(e))
neighbors = np.random.choice(H.nodes, size=d - 1)
to_add.append(np.append(neighbors, node))
H.remove_edges_from(to_remove)
H.add_edges_from(to_add)
Expand Down
14 changes: 8 additions & 6 deletions xgi/generators/uniform.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
"""Generate random uniform hypergraphs."""
import random
import warnings

from ..utils import py_random_state
from .classic import empty_hypergraph

__all__ = ["uniform_hypergraph_configuration_model"]


@py_random_state(2)
def uniform_hypergraph_configuration_model(k, m, seed=None):
"""
A function to generate an m-uniform configuration model
Expand All @@ -19,8 +18,8 @@ def uniform_hypergraph_configuration_model(k, m, seed=None):
and the values are node degrees.
m : int
specifies the hyperedge size
seed : integer, random_state, or None (default)
Indicator of random number generation state.
seed : integer or None (default)
The seed for the random number generator

Returns
-------
Expand Down Expand Up @@ -57,13 +56,16 @@ def uniform_hypergraph_configuration_model(k, m, seed=None):
>>> H = xgi.uniform_hypergraph_configuration_model(k, m)

"""
if seed is not None:
random.seed(seed)

# Making sure we have the right number of stubs
remainder = sum(k.values()) % m
if remainder != 0:
warnings.warn(
"This degree sequence is not realizable. Increasing the degree of random nodes so that it is."
)
random_ids = seed.sample(list(k.keys()), int(round(m - remainder)))
random_ids = random.sample(list(k.keys()), int(round(m - remainder)))
for id in random_ids:
k[id] = k[id] + 1

Expand All @@ -76,7 +78,7 @@ def uniform_hypergraph_configuration_model(k, m, seed=None):
H.add_nodes_from(k.keys())

while len(stubs) != 0:
u = seed.sample(range(len(stubs)), m)
u = random.sample(range(len(stubs)), m)
edge = set()
for index in u:
edge.add(stubs[index])
Expand Down
2 changes: 1 addition & 1 deletion xgi/stats/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def nodestat_func(func):
AttributeError:...

Use the `nodestat_func` decorator to turn `my_degree` into a valid stat.

>>> original_my_degree = my_degree
>>> my_degree = xgi.nodestat_func(my_degree)
>>> H.my_degree()
Expand Down
3 changes: 1 addition & 2 deletions xgi/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
from . import decorators, utilities
from .decorators import *
from . import utilities
from .utilities import *
Loading