Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/utils/random_sequence.py: 26%
53 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
1"""
2Utilities for generating random numbers, random sequences, and
3random selections.
4"""
6import networkx as nx
7from networkx.utils import py_random_state
9__all__ = [
10 "powerlaw_sequence",
11 "zipf_rv",
12 "cumulative_distribution",
13 "discrete_sequence",
14 "random_weighted_sample",
15 "weighted_choice",
16]
19# The same helpers for choosing random sequences from distributions
20# uses Python's random module
21# https://docs.python.org/3/library/random.html
24@py_random_state(2)
25def powerlaw_sequence(n, exponent=2.0, seed=None):
26 """
27 Return sample sequence of length n from a power law distribution.
28 """
29 return [seed.paretovariate(exponent - 1) for i in range(n)]
32@py_random_state(2)
33def zipf_rv(alpha, xmin=1, seed=None):
34 r"""Returns a random value chosen from the Zipf distribution.
36 The return value is an integer drawn from the probability distribution
38 .. math::
40 p(x)=\frac{x^{-\alpha}}{\zeta(\alpha, x_{\min})},
42 where $\zeta(\alpha, x_{\min})$ is the Hurwitz zeta function.
44 Parameters
45 ----------
46 alpha : float
47 Exponent value of the distribution
48 xmin : int
49 Minimum value
50 seed : integer, random_state, or None (default)
51 Indicator of random number generation state.
52 See :ref:`Randomness<randomness>`.
54 Returns
55 -------
56 x : int
57 Random value from Zipf distribution
59 Raises
60 ------
61 ValueError:
62 If xmin < 1 or
63 If alpha <= 1
65 Notes
66 -----
67 The rejection algorithm generates random values for a the power-law
68 distribution in uniformly bounded expected time dependent on
69 parameters. See [1]_ for details on its operation.
71 Examples
72 --------
73 >>> nx.utils.zipf_rv(alpha=2, xmin=3, seed=42)
74 8
76 References
77 ----------
78 .. [1] Luc Devroye, Non-Uniform Random Variate Generation,
79 Springer-Verlag, New York, 1986.
80 """
81 if xmin < 1:
82 raise ValueError("xmin < 1")
83 if alpha <= 1:
84 raise ValueError("a <= 1.0")
85 a1 = alpha - 1.0
86 b = 2**a1
87 while True:
88 u = 1.0 - seed.random() # u in (0,1]
89 v = seed.random() # v in [0,1)
90 x = int(xmin * u ** -(1.0 / a1))
91 t = (1.0 + (1.0 / x)) ** a1
92 if v * x * (t - 1.0) / (b - 1.0) <= t / b:
93 break
94 return x
97def cumulative_distribution(distribution):
98 """Returns normalized cumulative distribution from discrete distribution."""
100 cdf = [0.0]
101 psum = sum(distribution)
102 for i in range(len(distribution)):
103 cdf.append(cdf[i] + distribution[i] / psum)
104 return cdf
107@py_random_state(3)
108def discrete_sequence(n, distribution=None, cdistribution=None, seed=None):
109 """
110 Return sample sequence of length n from a given discrete distribution
111 or discrete cumulative distribution.
113 One of the following must be specified.
115 distribution = histogram of values, will be normalized
117 cdistribution = normalized discrete cumulative distribution
119 """
120 import bisect
122 if cdistribution is not None:
123 cdf = cdistribution
124 elif distribution is not None:
125 cdf = cumulative_distribution(distribution)
126 else:
127 raise nx.NetworkXError(
128 "discrete_sequence: distribution or cdistribution missing"
129 )
131 # get a uniform random number
132 inputseq = [seed.random() for i in range(n)]
134 # choose from CDF
135 seq = [bisect.bisect_left(cdf, s) - 1 for s in inputseq]
136 return seq
139@py_random_state(2)
140def random_weighted_sample(mapping, k, seed=None):
141 """Returns k items without replacement from a weighted sample.
143 The input is a dictionary of items with weights as values.
144 """
145 if k > len(mapping):
146 raise ValueError("sample larger than population")
147 sample = set()
148 while len(sample) < k:
149 sample.add(weighted_choice(mapping, seed))
150 return list(sample)
153@py_random_state(1)
154def weighted_choice(mapping, seed=None):
155 """Returns a single element from a weighted sample.
157 The input is a dictionary of items with weights as values.
158 """
159 # use roulette method
160 rnd = seed.random() * sum(mapping.values())
161 for k, w in mapping.items():
162 rnd -= w
163 if rnd < 0:
164 return k