Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/scipy/stats/_rvs_sampling.py : 11%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import numpy as np
2from scipy._lib._util import check_random_state
5def rvs_ratio_uniforms(pdf, umax, vmin, vmax, size=1, c=0, random_state=None):
6 """
7 Generate random samples from a probability density function using the
8 ratio-of-uniforms method.
10 Parameters
11 ----------
12 pdf : callable
13 A function with signature `pdf(x)` that is proportional to the
14 probability density function of the distribution.
15 umax : float
16 The upper bound of the bounding rectangle in the u-direction.
17 vmin : float
18 The lower bound of the bounding rectangle in the v-direction.
19 vmax : float
20 The upper bound of the bounding rectangle in the v-direction.
21 size : int or tuple of ints, optional
22 Defining number of random variates (default is 1).
23 c : float, optional.
24 Shift parameter of ratio-of-uniforms method, see Notes. Default is 0.
25 random_state : {None, int, `~np.random.RandomState`, `~np.random.Generator`}, optional
26 If `random_state` is `None` the `~np.random.RandomState` singleton is
27 used.
28 If `random_state` is an int, a new ``RandomState`` instance is used,
29 seeded with random_state.
30 If `random_state` is already a ``RandomState`` or ``Generator``
31 instance, then that object is used.
32 Default is None.
34 Returns
35 -------
36 rvs : ndarray
37 The random variates distributed according to the probability
38 distribution defined by the pdf.
40 Notes
41 -----
42 Given a univariate probability density function `pdf` and a constant `c`,
43 define the set ``A = {(u, v) : 0 < u <= sqrt(pdf(v/u + c))}``.
44 If `(U, V)` is a random vector uniformly distributed over `A`,
45 then `V/U + c` follows a distribution according to `pdf`.
47 The above result (see [1]_, [2]_) can be used to sample random variables
48 using only the pdf, i.e. no inversion of the cdf is required. Typical
49 choices of `c` are zero or the mode of `pdf`. The set `A` is a subset of
50 the rectangle ``R = [0, umax] x [vmin, vmax]`` where
52 - ``umax = sup sqrt(pdf(x))``
53 - ``vmin = inf (x - c) sqrt(pdf(x))``
54 - ``vmax = sup (x - c) sqrt(pdf(x))``
56 In particular, these values are finite if `pdf` is bounded and
57 ``x**2 * pdf(x)`` is bounded (i.e. subquadratic tails).
58 One can generate `(U, V)` uniformly on `R` and return
59 `V/U + c` if `(U, V)` are also in `A` which can be directly
60 verified.
62 The algorithm is not changed if one replaces `pdf` by k * `pdf` for any
63 constant k > 0. Thus, it is often convenient to work with a function
64 that is proportional to the probability density function by dropping
65 unneccessary normalization factors.
67 Intuitively, the method works well if `A` fills up most of the
68 enclosing rectangle such that the probability is high that `(U, V)`
69 lies in `A` whenever it lies in `R` as the number of required
70 iterations becomes too large otherwise. To be more precise, note that
71 the expected number of iterations to draw `(U, V)` uniformly
72 distributed on `R` such that `(U, V)` is also in `A` is given by
73 the ratio ``area(R) / area(A) = 2 * umax * (vmax - vmin) / area(pdf)``,
74 where `area(pdf)` is the integral of `pdf` (which is equal to one if the
75 probability density function is used but can take on other values if a
76 function proportional to the density is used). The equality holds since
77 the area of `A` is equal to 0.5 * area(pdf) (Theorem 7.1 in [1]_).
78 If the sampling fails to generate a single random variate after 50000
79 iterations (i.e. not a single draw is in `A`), an exception is raised.
81 If the bounding rectangle is not correctly specified (i.e. if it does not
82 contain `A`), the algorithm samples from a distribution different from
83 the one given by `pdf`. It is therefore recommended to perform a
84 test such as `~scipy.stats.kstest` as a check.
86 References
87 ----------
88 .. [1] L. Devroye, "Non-Uniform Random Variate Generation",
89 Springer-Verlag, 1986.
91 .. [2] W. Hoermann and J. Leydold, "Generating generalized inverse Gaussian
92 random variates", Statistics and Computing, 24(4), p. 547--557, 2014.
94 .. [3] A.J. Kinderman and J.F. Monahan, "Computer Generation of Random
95 Variables Using the Ratio of Uniform Deviates",
96 ACM Transactions on Mathematical Software, 3(3), p. 257--260, 1977.
98 Examples
99 --------
100 >>> from scipy import stats
102 Simulate normally distributed random variables. It is easy to compute the
103 bounding rectangle explicitly in that case. For simplicity, we drop the
104 normalization factor of the density.
106 >>> f = lambda x: np.exp(-x**2 / 2)
107 >>> v_bound = np.sqrt(f(np.sqrt(2))) * np.sqrt(2)
108 >>> umax, vmin, vmax = np.sqrt(f(0)), -v_bound, v_bound
109 >>> np.random.seed(12345)
110 >>> rvs = stats.rvs_ratio_uniforms(f, umax, vmin, vmax, size=2500)
112 The K-S test confirms that the random variates are indeed normally
113 distributed (normality is not rejected at 5% significance level):
115 >>> stats.kstest(rvs, 'norm')[1]
116 0.33783681428365553
118 The exponential distribution provides another example where the bounding
119 rectangle can be determined explicitly.
121 >>> np.random.seed(12345)
122 >>> rvs = stats.rvs_ratio_uniforms(lambda x: np.exp(-x), umax=1,
123 ... vmin=0, vmax=2*np.exp(-1), size=1000)
124 >>> stats.kstest(rvs, 'expon')[1]
125 0.928454552559516
127 """
129 if vmin >= vmax:
130 raise ValueError("vmin must be smaller than vmax.")
132 if umax <= 0:
133 raise ValueError("umax must be positive.")
135 size1d = tuple(np.atleast_1d(size))
136 N = np.prod(size1d) # number of rvs needed, reshape upon return
138 # start sampling using ratio of uniforms method
139 rng = check_random_state(random_state)
140 x = np.zeros(N)
141 simulated, i = 0, 1
143 # loop until N rvs have been generated: expected runtime is finite.
144 # to avoid infinite loop, raise exception if not a single rv has been
145 # generated after 50000 tries. even if the expected numer of iterations
146 # is 1000, the probability of this event is (1-1/1000)**50000
147 # which is of order 10e-22
148 while simulated < N:
149 k = N - simulated
150 # simulate uniform rvs on [0, umax] and [vmin, vmax]
151 u1 = umax * rng.uniform(size=k)
152 v1 = rng.uniform(vmin, vmax, size=k)
153 # apply rejection method
154 rvs = v1 / u1 + c
155 accept = (u1**2 <= pdf(rvs))
156 num_accept = np.sum(accept)
157 if num_accept > 0:
158 x[simulated:(simulated + num_accept)] = rvs[accept]
159 simulated += num_accept
161 if (simulated == 0) and (i*N >= 50000):
162 msg = ("Not a single random variate could be generated in {} "
163 "attempts. The ratio of uniforms method does not appear "
164 "to work for the provided parameters. Please check the "
165 "pdf and the bounds.".format(i*N))
166 raise RuntimeError(msg)
167 i += 1
169 return np.reshape(x, size1d)