Videre
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,740 @@
|
||||
"""
|
||||
Algorithmic implementations for generating different types
|
||||
of random distributions.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numba.core.extending import register_jitable
|
||||
from numba.np.random._constants import (wi_double, ki_double,
|
||||
ziggurat_nor_r, fi_double,
|
||||
wi_float, ki_float,
|
||||
ziggurat_nor_inv_r_f,
|
||||
ziggurat_nor_r_f, fi_float,
|
||||
we_double, ke_double,
|
||||
ziggurat_exp_r, fe_double,
|
||||
we_float, ke_float,
|
||||
ziggurat_exp_r_f, fe_float,
|
||||
INT64_MAX, ziggurat_nor_inv_r)
|
||||
from numba.np.random.generator_core import (next_double, next_float,
|
||||
next_uint32, next_uint64)
|
||||
from numba import float32, int64
|
||||
from numba.np.numpy_support import numpy_version
|
||||
# All of the following implementations are direct translations from:
|
||||
# https://github.com/numpy/numpy/blob/7cfef93c77599bd387ecc6a15d186c5a46024dac/numpy/random/src/distributions/distributions.c
|
||||
|
||||
|
||||
@register_jitable
|
||||
def np_log1p(x):
|
||||
return np.log1p(x)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def np_log1pf(x):
|
||||
return np.log1p(float32(x))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_rayleigh(bitgen, mode):
|
||||
return mode * np.sqrt(2.0 * random_standard_exponential(bitgen))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def np_expm1(x):
|
||||
return np.expm1(x)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_normal(bitgen):
|
||||
while 1:
|
||||
r = next_uint64(bitgen)
|
||||
idx = r & 0xff
|
||||
r >>= 8
|
||||
sign = r & 0x1
|
||||
rabs = (r >> 1) & 0x000fffffffffffff
|
||||
x = rabs * wi_double[idx]
|
||||
if (sign & 0x1):
|
||||
x = -x
|
||||
if rabs < ki_double[idx]:
|
||||
return x
|
||||
if idx == 0:
|
||||
while 1:
|
||||
xx = -ziggurat_nor_inv_r * np.log1p(-next_double(bitgen))
|
||||
yy = -np.log1p(-next_double(bitgen))
|
||||
if (yy + yy > xx * xx):
|
||||
if ((rabs >> 8) & 0x1):
|
||||
return -(ziggurat_nor_r + xx)
|
||||
else:
|
||||
return ziggurat_nor_r + xx
|
||||
else:
|
||||
if (((fi_double[idx - 1] - fi_double[idx]) *
|
||||
next_double(bitgen) + fi_double[idx]) <
|
||||
np.exp(-0.5 * x * x)):
|
||||
return x
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_normal_f(bitgen):
|
||||
while 1:
|
||||
r = next_uint32(bitgen)
|
||||
idx = r & 0xff
|
||||
sign = (r >> 8) & 0x1
|
||||
rabs = (r >> 9) & 0x0007fffff
|
||||
x = float32(float32(rabs) * wi_float[idx])
|
||||
if (sign & 0x1):
|
||||
x = -x
|
||||
if (rabs < ki_float[idx]):
|
||||
return x
|
||||
if (idx == 0):
|
||||
while 1:
|
||||
xx = float32(-ziggurat_nor_inv_r_f *
|
||||
np_log1pf(-next_float(bitgen)))
|
||||
yy = float32(-np_log1pf(-next_float(bitgen)))
|
||||
if (float32(yy + yy) > float32(xx * xx)):
|
||||
if ((rabs >> 8) & 0x1):
|
||||
return -float32(ziggurat_nor_r_f + xx)
|
||||
else:
|
||||
return float32(ziggurat_nor_r_f + xx)
|
||||
else:
|
||||
if (((fi_float[idx - 1] - fi_float[idx]) * next_float(bitgen) +
|
||||
fi_float[idx]) < float32(np.exp(-float32(0.5) * x * x))):
|
||||
return x
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_exponential(bitgen):
|
||||
while 1:
|
||||
ri = next_uint64(bitgen)
|
||||
ri >>= 3
|
||||
idx = ri & 0xFF
|
||||
ri >>= 8
|
||||
x = ri * we_double[idx]
|
||||
if (ri < ke_double[idx]):
|
||||
return x
|
||||
else:
|
||||
if idx == 0:
|
||||
return ziggurat_exp_r - np_log1p(-next_double(bitgen))
|
||||
elif ((fe_double[idx - 1] - fe_double[idx]) * next_double(bitgen) +
|
||||
fe_double[idx] < np.exp(-x)):
|
||||
return x
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_exponential_f(bitgen):
|
||||
while 1:
|
||||
ri = next_uint32(bitgen)
|
||||
ri >>= 1
|
||||
idx = ri & 0xFF
|
||||
ri >>= 8
|
||||
x = float32(float32(ri) * we_float[idx])
|
||||
if (ri < ke_float[idx]):
|
||||
return x
|
||||
else:
|
||||
if (idx == 0):
|
||||
return float32(ziggurat_exp_r_f -
|
||||
float32(np_log1pf(-next_float(bitgen))))
|
||||
elif ((fe_float[idx - 1] - fe_float[idx]) * next_float(bitgen) +
|
||||
fe_float[idx] < float32(np.exp(float32(-x)))):
|
||||
return x
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_exponential_inv(bitgen):
|
||||
return -np_log1p(-next_double(bitgen))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_exponential_inv_f(bitgen):
|
||||
return -np.log(float32(1.0) - next_float(bitgen))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_gamma(bitgen, shape):
|
||||
if (shape == 1.0):
|
||||
return random_standard_exponential(bitgen)
|
||||
elif (shape == 0.0):
|
||||
return 0.0
|
||||
elif (shape < 1.0):
|
||||
while 1:
|
||||
U = next_double(bitgen)
|
||||
V = random_standard_exponential(bitgen)
|
||||
if (U <= 1.0 - shape):
|
||||
X = pow(U, 1. / shape)
|
||||
if (X <= V):
|
||||
return X
|
||||
else:
|
||||
Y = -np.log((1 - U) / shape)
|
||||
X = pow(1.0 - shape + shape * Y, 1. / shape)
|
||||
if (X <= (V + Y)):
|
||||
return X
|
||||
else:
|
||||
b = shape - 1. / 3.
|
||||
c = 1. / np.sqrt(9 * b)
|
||||
while 1:
|
||||
while 1:
|
||||
X = random_standard_normal(bitgen)
|
||||
V = 1.0 + c * X
|
||||
if (V > 0.0):
|
||||
break
|
||||
|
||||
V = V * V * V
|
||||
U = next_double(bitgen)
|
||||
if (U < 1.0 - 0.0331 * (X * X) * (X * X)):
|
||||
return (b * V)
|
||||
|
||||
if (np.log(U) < 0.5 * X * X + b * (1. - V + np.log(V))):
|
||||
return (b * V)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_gamma_f(bitgen, shape):
|
||||
f32_one = float32(1.0)
|
||||
shape = float32(shape)
|
||||
if (shape == f32_one):
|
||||
return random_standard_exponential_f(bitgen)
|
||||
elif (shape == float32(0.0)):
|
||||
return float32(0.0)
|
||||
elif (shape < f32_one):
|
||||
while 1:
|
||||
U = next_float(bitgen)
|
||||
V = random_standard_exponential_f(bitgen)
|
||||
if (U <= f32_one - shape):
|
||||
X = float32(pow(U, float32(f32_one / shape)))
|
||||
if (X <= V):
|
||||
return X
|
||||
else:
|
||||
Y = float32(-np.log(float32((f32_one - U) / shape)))
|
||||
X = float32(pow(f32_one - shape + float32(shape * Y),
|
||||
float32(f32_one / shape)))
|
||||
if (X <= (V + Y)):
|
||||
return X
|
||||
else:
|
||||
b = shape - f32_one / float32(3.0)
|
||||
c = float32(f32_one / float32(np.sqrt(float32(9.0) * b)))
|
||||
while 1:
|
||||
while 1:
|
||||
X = float32(random_standard_normal_f(bitgen))
|
||||
V = float32(f32_one + c * X)
|
||||
if (V > float32(0.0)):
|
||||
break
|
||||
|
||||
V = float32(V * V * V)
|
||||
U = next_float(bitgen)
|
||||
if (U < f32_one - float32(0.0331) * (X * X) * (X * X)):
|
||||
return float32(b * V)
|
||||
|
||||
if (np.log(U) < float32(0.5) * X * X + b *
|
||||
(f32_one - V + np.log(V))):
|
||||
return float32(b * V)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_normal(bitgen, loc, scale):
|
||||
scaled_normal = scale * random_standard_normal(bitgen)
|
||||
return loc + scaled_normal
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_normal_f(bitgen, loc, scale):
|
||||
scaled_normal = float32(scale * random_standard_normal_f(bitgen))
|
||||
return float32(loc + scaled_normal)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_exponential(bitgen, scale):
|
||||
return scale * random_standard_exponential(bitgen)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_uniform(bitgen, lower, range):
|
||||
scaled_uniform = range * next_double(bitgen)
|
||||
return lower + scaled_uniform
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_gamma(bitgen, shape, scale):
|
||||
return scale * random_standard_gamma(bitgen, shape)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_gamma_f(bitgen, shape, scale):
|
||||
return float32(scale * random_standard_gamma_f(bitgen, shape))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_beta(bitgen, a, b):
|
||||
if a <= 1.0 and b <= 1.0:
|
||||
while 1:
|
||||
U = next_double(bitgen)
|
||||
V = next_double(bitgen)
|
||||
X = pow(U, 1.0 / a)
|
||||
Y = pow(V, 1.0 / b)
|
||||
XpY = X + Y
|
||||
if XpY <= 1.0 and XpY > 0.0:
|
||||
if (X + Y > 0):
|
||||
return X / XpY
|
||||
else:
|
||||
logX = np.log(U) / a
|
||||
logY = np.log(V) / b
|
||||
logM = min(logX, logY)
|
||||
logX -= logM
|
||||
logY -= logM
|
||||
|
||||
return np.exp(logX - np.log(np.exp(logX) + np.exp(logY)))
|
||||
else:
|
||||
Ga = random_standard_gamma(bitgen, a)
|
||||
Gb = random_standard_gamma(bitgen, b)
|
||||
return Ga / (Ga + Gb)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_chisquare(bitgen, df):
|
||||
return 2.0 * random_standard_gamma(bitgen, df / 2.0)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_f(bitgen, dfnum, dfden):
|
||||
return ((random_chisquare(bitgen, dfnum) * dfden) /
|
||||
(random_chisquare(bitgen, dfden) * dfnum))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_cauchy(bitgen):
|
||||
return random_standard_normal(bitgen) / random_standard_normal(bitgen)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_pareto(bitgen, a):
|
||||
return np_expm1(random_standard_exponential(bitgen) / a)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_weibull(bitgen, a):
|
||||
if (a == 0.0):
|
||||
return 0.0
|
||||
return pow(random_standard_exponential(bitgen), 1. / a)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_power(bitgen, a):
|
||||
return pow(-np_expm1(-random_standard_exponential(bitgen)), 1. / a)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_laplace(bitgen, loc, scale):
|
||||
U = next_double(bitgen)
|
||||
while U <= 0:
|
||||
U = next_double(bitgen)
|
||||
if (U >= 0.5):
|
||||
U = loc - scale * np.log(2.0 - U - U)
|
||||
elif (U > 0.0):
|
||||
U = loc + scale * np.log(U + U)
|
||||
return U
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_logistic(bitgen, loc, scale):
|
||||
U = next_double(bitgen)
|
||||
while U <= 0.0:
|
||||
U = next_double(bitgen)
|
||||
return loc + scale * np.log(U / (1.0 - U))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_lognormal(bitgen, mean, sigma):
|
||||
return np.exp(random_normal(bitgen, mean, sigma))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_standard_t(bitgen, df):
|
||||
num = random_standard_normal(bitgen)
|
||||
denom = random_standard_gamma(bitgen, df / 2)
|
||||
return np.sqrt(df / 2) * num / np.sqrt(denom)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_wald(bitgen, mean, scale):
|
||||
mu_2l = mean / (2 * scale)
|
||||
Y = random_standard_normal(bitgen)
|
||||
Y = mean * Y * Y
|
||||
X = mean + mu_2l * (Y - np.sqrt(4 * scale * Y + Y * Y))
|
||||
U = next_double(bitgen)
|
||||
if (U <= mean / (mean + X)):
|
||||
return X
|
||||
else:
|
||||
return mean * mean / X
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_geometric_search(bitgen, p):
|
||||
X = 1
|
||||
sum = prod = p
|
||||
q = 1.0 - p
|
||||
U = next_double(bitgen)
|
||||
while (U > sum):
|
||||
prod *= q
|
||||
sum += prod
|
||||
X = X + 1
|
||||
return X
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_geometric_inversion(bitgen, p):
|
||||
return np.ceil(-random_standard_exponential(bitgen) / np.log1p(-p))
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_geometric(bitgen, p):
|
||||
if (p >= 0.333333333333333333333333):
|
||||
return random_geometric_search(bitgen, p)
|
||||
else:
|
||||
return random_geometric_inversion(bitgen, p)
|
||||
|
||||
|
||||
if numpy_version < (2, 1):
|
||||
@register_jitable
|
||||
def random_zipf(bitgen, a):
|
||||
am1 = a - 1.0
|
||||
b = pow(2.0, am1)
|
||||
while 1:
|
||||
U = 1.0 - next_double(bitgen)
|
||||
V = next_double(bitgen)
|
||||
X = np.floor(pow(U, -1.0 / am1))
|
||||
if (X > INT64_MAX or X < 1.0):
|
||||
continue
|
||||
T = pow(1.0 + 1.0 / X, am1)
|
||||
if (V * X * (T - 1.0) / (b - 1.0) <= T / b):
|
||||
return X
|
||||
else:
|
||||
@register_jitable
|
||||
def random_zipf(bitgen, a):
|
||||
am1 = a - 1.0
|
||||
b = pow(2.0, am1)
|
||||
Umin = pow(INT64_MAX, -am1)
|
||||
while 1:
|
||||
U01 = next_double(bitgen)
|
||||
U = U01 * Umin + (1 - U01)
|
||||
V = next_double(bitgen)
|
||||
X = np.floor(pow(U, -1.0 / am1))
|
||||
if (X > INT64_MAX or X < 1.0):
|
||||
continue
|
||||
|
||||
T = pow(1.0 + 1.0 / X, am1)
|
||||
if (V * X * (T - 1.0) / (b - 1.0) <= T / b):
|
||||
return X
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_triangular(bitgen, left, mode,
|
||||
right):
|
||||
base = right - left
|
||||
leftbase = mode - left
|
||||
ratio = leftbase / base
|
||||
leftprod = leftbase * base
|
||||
rightprod = (right - mode) * base
|
||||
|
||||
U = next_double(bitgen)
|
||||
if (U <= ratio):
|
||||
return left + np.sqrt(U * leftprod)
|
||||
else:
|
||||
return right - np.sqrt((1.0 - U) * rightprod)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_loggam(x):
|
||||
a = [8.333333333333333e-02, -2.777777777777778e-03,
|
||||
7.936507936507937e-04, -5.952380952380952e-04,
|
||||
8.417508417508418e-04, -1.917526917526918e-03,
|
||||
6.410256410256410e-03, -2.955065359477124e-02,
|
||||
1.796443723688307e-01, -1.39243221690590e+00]
|
||||
|
||||
if ((x == 1.0) or (x == 2.0)):
|
||||
return 0.0
|
||||
elif (x < 7.0):
|
||||
n = int(7 - x)
|
||||
else:
|
||||
n = 0
|
||||
|
||||
x0 = x + n
|
||||
x2 = (1.0 / x0) * (1.0 / x0)
|
||||
# /* log(2 * M_PI) */
|
||||
lg2pi = 1.8378770664093453e+00
|
||||
gl0 = a[9]
|
||||
|
||||
for k in range(0, 9):
|
||||
gl0 *= x2
|
||||
gl0 += a[8 - k]
|
||||
|
||||
gl = gl0 / x0 + 0.5 * lg2pi + (x0 - 0.5) * np.log(x0) - x0
|
||||
if (x < 7.0):
|
||||
for k in range(1, n + 1):
|
||||
gl = gl - np.log(x0 - 1.0)
|
||||
x0 = x0 - 1.0
|
||||
|
||||
return gl
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_poisson_mult(bitgen, lam):
|
||||
enlam = np.exp(-lam)
|
||||
X = 0
|
||||
prod = 1.0
|
||||
while (1):
|
||||
U = next_double(bitgen)
|
||||
prod *= U
|
||||
if (prod > enlam):
|
||||
X += 1
|
||||
else:
|
||||
return X
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_poisson_ptrs(bitgen, lam):
|
||||
|
||||
slam = np.sqrt(lam)
|
||||
loglam = np.log(lam)
|
||||
b = 0.931 + 2.53 * slam
|
||||
a = -0.059 + 0.02483 * b
|
||||
invalpha = 1.1239 + 1.1328 / (b - 3.4)
|
||||
vr = 0.9277 - 3.6224 / (b - 2)
|
||||
|
||||
while (1):
|
||||
U = next_double(bitgen) - 0.5
|
||||
V = next_double(bitgen)
|
||||
us = 0.5 - np.fabs(U)
|
||||
k = int((2 * a / us + b) * U + lam + 0.43)
|
||||
if ((us >= 0.07) and (V <= vr)):
|
||||
return k
|
||||
|
||||
if ((k < 0) or ((us < 0.013) and (V > us))):
|
||||
continue
|
||||
|
||||
# /* log(V) == log(0.0) ok here */
|
||||
# /* if U==0.0 so that us==0.0, log is ok since always returns */
|
||||
if ((np.log(V) + np.log(invalpha) - np.log(a / (us * us) + b)) <=
|
||||
(-lam + k * loglam - random_loggam(k + 1))):
|
||||
return k
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_poisson(bitgen, lam):
|
||||
if (lam >= 10):
|
||||
return random_poisson_ptrs(bitgen, lam)
|
||||
elif (lam == 0):
|
||||
return 0
|
||||
else:
|
||||
return random_poisson_mult(bitgen, lam)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_negative_binomial(bitgen, n, p):
|
||||
Y = random_gamma(bitgen, n, (1 - p) / p)
|
||||
return random_poisson(bitgen, Y)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_noncentral_chisquare(bitgen, df, nonc):
|
||||
if np.isnan(nonc):
|
||||
return np.nan
|
||||
|
||||
if nonc == 0:
|
||||
return random_chisquare(bitgen, df)
|
||||
|
||||
if 1 < df:
|
||||
Chi2 = random_chisquare(bitgen, df - 1)
|
||||
n = random_standard_normal(bitgen) + np.sqrt(nonc)
|
||||
return Chi2 + n * n
|
||||
else:
|
||||
i = random_poisson(bitgen, nonc / 2.0)
|
||||
return random_chisquare(bitgen, df + 2 * i)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_noncentral_f(bitgen, dfnum, dfden, nonc):
|
||||
t = random_noncentral_chisquare(bitgen, dfnum, nonc) * dfden
|
||||
return t / (random_chisquare(bitgen, dfden) * dfnum)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_logseries(bitgen, p):
|
||||
r = np_log1p(-p)
|
||||
|
||||
while 1:
|
||||
V = next_double(bitgen)
|
||||
if (V >= p):
|
||||
return 1
|
||||
U = next_double(bitgen)
|
||||
q = -np.expm1(r * U)
|
||||
if (V <= q * q):
|
||||
result = int64(np.floor(1 + np.log(V) / np.log(q)))
|
||||
if result < 1 or V == 0.0:
|
||||
continue
|
||||
else:
|
||||
return result
|
||||
if (V >= q):
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_binomial_btpe(bitgen, n, p):
|
||||
r = min(p, 1.0 - p)
|
||||
q = 1.0 - r
|
||||
fm = n * r + r
|
||||
m = int(np.floor(fm))
|
||||
p1 = np.floor(2.195 * np.sqrt(n * r * q) - 4.6 * q) + 0.5
|
||||
xm = m + 0.5
|
||||
xl = xm - p1
|
||||
xr = xm + p1
|
||||
c = 0.134 + 20.5 / (15.3 + m)
|
||||
a = (fm - xl) / (fm - xl * r)
|
||||
laml = a * (1.0 + a / 2.0)
|
||||
a = (xr - fm) / (xr * q)
|
||||
lamr = a * (1.0 + a / 2.0)
|
||||
p2 = p1 * (1.0 + 2.0 * c)
|
||||
p3 = p2 + c / laml
|
||||
p4 = p3 + c / lamr
|
||||
|
||||
case = 10
|
||||
y = k = 0
|
||||
while 1:
|
||||
if case == 10:
|
||||
nrq = n * r * q
|
||||
u = next_double(bitgen) * p4
|
||||
v = next_double(bitgen)
|
||||
if (u > p1):
|
||||
case = 20
|
||||
continue
|
||||
y = int(np.floor(xm - p1 * v + u))
|
||||
case = 60
|
||||
continue
|
||||
elif case == 20:
|
||||
if (u > p2):
|
||||
case = 30
|
||||
continue
|
||||
x = xl + (u - p1) / c
|
||||
v = v * c + 1.0 - np.fabs(m - x + 0.5) / p1
|
||||
if (v > 1.0):
|
||||
case = 10
|
||||
continue
|
||||
y = int(np.floor(x))
|
||||
case = 50
|
||||
continue
|
||||
elif case == 30:
|
||||
if (u > p3):
|
||||
case = 40
|
||||
continue
|
||||
y = int(np.floor(xl + np.log(v) / laml))
|
||||
if ((y < 0) or (v == 0.0)):
|
||||
case = 10
|
||||
continue
|
||||
v = v * (u - p2) * laml
|
||||
case = 50
|
||||
continue
|
||||
elif case == 40:
|
||||
y = int(np.floor(xr - np.log(v) / lamr))
|
||||
if ((y > n) or (v == 0.0)):
|
||||
case = 10
|
||||
continue
|
||||
v = v * (u - p3) * lamr
|
||||
case = 50
|
||||
continue
|
||||
elif case == 50:
|
||||
k = abs(y - m)
|
||||
if ((k > 20) and (k < ((nrq) / 2.0 - 1))):
|
||||
case = 52
|
||||
continue
|
||||
s = r / q
|
||||
a = s * (n + 1)
|
||||
F = 1.0
|
||||
if (m < y):
|
||||
for i in range(m + 1, y + 1):
|
||||
F = F * (a / i - s)
|
||||
elif (m > y):
|
||||
for i in range(y + 1, m + 1):
|
||||
F = F / (a / i - s)
|
||||
if (v > F):
|
||||
case = 10
|
||||
continue
|
||||
case = 60
|
||||
continue
|
||||
elif case == 52:
|
||||
rho = (k / (nrq)) * \
|
||||
((k * (k / 3.0 + 0.625) + 0.16666666666666666) /
|
||||
nrq + 0.5)
|
||||
t = -k * k / (2 * nrq)
|
||||
A = np.log(v)
|
||||
if (A < (t - rho)):
|
||||
case = 60
|
||||
continue
|
||||
if (A > (t + rho)):
|
||||
case = 10
|
||||
continue
|
||||
x1 = y + 1
|
||||
f1 = m + 1
|
||||
z = n + 1 - m
|
||||
w = n - y + 1
|
||||
x2 = x1 * x1
|
||||
f2 = f1 * f1
|
||||
z2 = z * z
|
||||
w2 = w * w
|
||||
if (A > (xm * np.log(f1 / x1) + (n - m + 0.5) * np.log(z / w) +
|
||||
(y - m) * np.log(w * r / (x1 * q)) +
|
||||
(13680. - (462. - (132. - (99. - 140. / f2) / f2) / f2)
|
||||
/ f2) / f1 / 166320. +
|
||||
(13680. - (462. - (132. - (99. - 140. / z2) / z2) / z2)
|
||||
/ z2) / z / 166320. +
|
||||
(13680. - (462. - (132. - (99. - 140. / x2) / x2) / x2)
|
||||
/ x2) / x1 / 166320. +
|
||||
(13680. - (462. - (132. - (99. - 140. / w2) / w2) / w2)
|
||||
/ w2) / w / 66320.)):
|
||||
case = 10
|
||||
continue
|
||||
case = 60
|
||||
continue
|
||||
elif case == 60:
|
||||
if (p > 0.5):
|
||||
y = n - y
|
||||
return y
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_binomial_inversion(bitgen, n, p):
|
||||
q = 1.0 - p
|
||||
qn = np.exp(n * np.log(q))
|
||||
_np = n * p
|
||||
bound = min(n, _np + 10.0 * np.sqrt(_np * q + 1))
|
||||
|
||||
X = 0
|
||||
px = qn
|
||||
U = next_double(bitgen)
|
||||
while (U > px):
|
||||
X = X + 1
|
||||
if (X > bound):
|
||||
X = 0
|
||||
px = qn
|
||||
U = next_double(bitgen)
|
||||
else:
|
||||
U -= px
|
||||
px = ((n - X + 1) * p * px) / (X * q)
|
||||
|
||||
return X
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_binomial(bitgen, n, p):
|
||||
if ((n == 0) or (p == 0.0)):
|
||||
return 0
|
||||
|
||||
if (p <= 0.5):
|
||||
if (p * n <= 30.0):
|
||||
return random_binomial_inversion(bitgen, n, p)
|
||||
else:
|
||||
return random_binomial_btpe(bitgen, n, p)
|
||||
else:
|
||||
q = 1.0 - p
|
||||
if (q * n <= 30.0):
|
||||
return n - random_binomial_inversion(bitgen, n, q)
|
||||
else:
|
||||
return n - random_binomial_btpe(bitgen, n, q)
|
||||
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
Core Implementations for Generator/BitGenerator Models.
|
||||
"""
|
||||
|
||||
from llvmlite import ir
|
||||
from numba.core import cgutils, types
|
||||
from numba.core.extending import (intrinsic, make_attribute_wrapper, models,
|
||||
overload, register_jitable,
|
||||
register_model)
|
||||
|
||||
|
||||
@register_model(types.NumPyRandomBitGeneratorType)
|
||||
class NumPyRngBitGeneratorModel(models.StructModel):
|
||||
def __init__(self, dmm, fe_type):
|
||||
members = [
|
||||
('parent', types.pyobject),
|
||||
('state_address', types.uintp),
|
||||
('state', types.uintp),
|
||||
('fnptr_next_uint64', types.uintp),
|
||||
('fnptr_next_uint32', types.uintp),
|
||||
('fnptr_next_double', types.uintp),
|
||||
('bit_generator', types.uintp),
|
||||
]
|
||||
super(NumPyRngBitGeneratorModel, self).__init__(dmm, fe_type, members)
|
||||
|
||||
|
||||
_bit_gen_type = types.NumPyRandomBitGeneratorType('bit_generator')
|
||||
|
||||
|
||||
@register_model(types.NumPyRandomGeneratorType)
|
||||
class NumPyRandomGeneratorTypeModel(models.StructModel):
|
||||
def __init__(self, dmm, fe_type):
|
||||
members = [
|
||||
('bit_generator', _bit_gen_type),
|
||||
('meminfo', types.MemInfoPointer(types.voidptr)),
|
||||
('parent', types.pyobject)
|
||||
]
|
||||
super(
|
||||
NumPyRandomGeneratorTypeModel,
|
||||
self).__init__(
|
||||
dmm,
|
||||
fe_type,
|
||||
members)
|
||||
|
||||
|
||||
# The Generator instances have a bit_generator attr
|
||||
make_attribute_wrapper(
|
||||
types.NumPyRandomGeneratorType,
|
||||
'bit_generator',
|
||||
'bit_generator')
|
||||
|
||||
|
||||
def _generate_next_binding(overloadable_function, return_type):
|
||||
"""
|
||||
Generate the overloads for "next_(some type)" functions.
|
||||
"""
|
||||
@intrinsic
|
||||
def intrin_NumPyRandomBitGeneratorType_next_ty(tyctx, inst):
|
||||
sig = return_type(inst)
|
||||
|
||||
def codegen(cgctx, builder, sig, llargs):
|
||||
name = overloadable_function.__name__
|
||||
struct_ptr = cgutils.create_struct_proxy(inst)(cgctx, builder,
|
||||
value=llargs[0])
|
||||
|
||||
# Get the 'state' and 'fnptr_next_(type)' members of the struct
|
||||
state = struct_ptr.state
|
||||
next_double_addr = getattr(struct_ptr, f'fnptr_{name}')
|
||||
|
||||
# LLVM IR types needed
|
||||
ll_void_ptr_t = cgctx.get_value_type(types.voidptr)
|
||||
ll_return_t = cgctx.get_value_type(return_type)
|
||||
ll_uintp_t = cgctx.get_value_type(types.uintp)
|
||||
|
||||
# Convert the stored Generator function address to a pointer
|
||||
next_fn_fnptr = builder.inttoptr(
|
||||
next_double_addr, ll_void_ptr_t)
|
||||
# Add the function to the module
|
||||
fnty = ir.FunctionType(ll_return_t, (ll_uintp_t,))
|
||||
next_fn = cgutils.get_or_insert_function(
|
||||
builder.module, fnty, name)
|
||||
# Bit cast the function pointer to the function type
|
||||
fnptr_as_fntype = builder.bitcast(next_fn_fnptr, next_fn.type)
|
||||
# call it with the "state" address as the arg
|
||||
ret = builder.call(fnptr_as_fntype, (state,))
|
||||
return ret
|
||||
return sig, codegen
|
||||
|
||||
@overload(overloadable_function)
|
||||
def ol_next_ty(bitgen):
|
||||
if isinstance(bitgen, types.NumPyRandomBitGeneratorType):
|
||||
def impl(bitgen):
|
||||
return intrin_NumPyRandomBitGeneratorType_next_ty(bitgen)
|
||||
return impl
|
||||
|
||||
|
||||
# Some function stubs for "next(some type)", these will be overloaded
|
||||
def next_double(bitgen):
|
||||
return bitgen.ctypes.next_double(bitgen.ctypes.state)
|
||||
|
||||
|
||||
def next_uint32(bitgen):
|
||||
return bitgen.ctypes.next_uint32(bitgen.ctypes.state)
|
||||
|
||||
|
||||
def next_uint64(bitgen):
|
||||
return bitgen.ctypes.next_uint64(bitgen.ctypes.state)
|
||||
|
||||
|
||||
_generate_next_binding(next_double, types.double)
|
||||
_generate_next_binding(next_uint32, types.uint32)
|
||||
_generate_next_binding(next_uint64, types.uint64)
|
||||
|
||||
|
||||
# See: https://github.com/numpy/numpy/pull/20314
|
||||
@register_jitable
|
||||
def next_float(bitgen):
|
||||
return types.float32(types.float32(next_uint32(bitgen) >> 8)
|
||||
* types.float32(1.0)
|
||||
/ types.float32(16777216.0))
|
||||
@@ -0,0 +1,971 @@
|
||||
"""
|
||||
Implementation of method overloads for Generator objects.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from numba.core import types
|
||||
from numba.core.extending import overload_method, register_jitable
|
||||
from numba.np.numpy_support import as_dtype, from_dtype
|
||||
from numba.np.random.generator_core import next_float, next_double
|
||||
from numba.np.numpy_support import is_nonelike
|
||||
from numba.core.errors import TypingError
|
||||
from numba.core.types.containers import Tuple, UniTuple
|
||||
from numba.np.random.distributions import \
|
||||
(random_standard_exponential_inv_f, random_standard_exponential_inv,
|
||||
random_standard_exponential, random_standard_normal_f,
|
||||
random_standard_gamma, random_standard_normal, random_uniform,
|
||||
random_standard_exponential_f, random_standard_gamma_f, random_normal,
|
||||
random_exponential, random_gamma, random_beta, random_power,
|
||||
random_f,random_chisquare,random_standard_cauchy,random_pareto,
|
||||
random_weibull, random_laplace, random_logistic,
|
||||
random_lognormal, random_rayleigh, random_standard_t, random_wald,
|
||||
random_geometric, random_zipf, random_triangular,
|
||||
random_poisson, random_negative_binomial, random_logseries,
|
||||
random_noncentral_chisquare, random_noncentral_f, random_binomial)
|
||||
from numba.np.random import random_methods
|
||||
|
||||
|
||||
def _get_proper_func(func_32, func_64, dtype, dist_name="the given"):
|
||||
"""
|
||||
Most of the standard NumPy distributions that accept dtype argument
|
||||
only support either np.float32 or np.float64 as dtypes.
|
||||
|
||||
This is a helper function that helps Numba select the proper underlying
|
||||
implementation according to provided dtype.
|
||||
"""
|
||||
if isinstance(dtype, types.Omitted):
|
||||
dtype = dtype.value
|
||||
|
||||
np_dt = dtype
|
||||
if isinstance(dtype, type):
|
||||
nb_dt = from_dtype(np.dtype(dtype))
|
||||
elif isinstance(dtype, types.NumberClass):
|
||||
nb_dt = dtype
|
||||
np_dt = as_dtype(nb_dt)
|
||||
|
||||
if np_dt not in [np.float32, np.float64]:
|
||||
raise TypingError("Argument dtype is not one of the" +
|
||||
" expected type(s): " +
|
||||
" np.float32 or np.float64")
|
||||
|
||||
if np_dt == np.float32:
|
||||
next_func = func_32
|
||||
else:
|
||||
next_func = func_64
|
||||
|
||||
return next_func, nb_dt
|
||||
|
||||
|
||||
def check_size(size):
|
||||
if not any([isinstance(size, UniTuple) and
|
||||
isinstance(size.dtype, types.Integer),
|
||||
isinstance(size, Tuple) and size.count == 0,
|
||||
isinstance(size, types.Integer)]):
|
||||
raise TypingError("Argument size is not one of the" +
|
||||
" expected type(s): " +
|
||||
" an integer, an empty tuple or a tuple of integers")
|
||||
|
||||
|
||||
def check_types(obj, type_list, arg_name):
|
||||
"""
|
||||
Check if given object is one of the provided types.
|
||||
If not raises an TypeError
|
||||
"""
|
||||
if isinstance(obj, types.Omitted):
|
||||
obj = obj.value
|
||||
|
||||
if not isinstance(type_list, (list, tuple)):
|
||||
type_list = [type_list]
|
||||
|
||||
if not any([isinstance(obj, _type) for _type in type_list]):
|
||||
raise TypingError(f"Argument {arg_name} is not one of the" +
|
||||
f" expected type(s): {type_list}")
|
||||
|
||||
|
||||
# Overload the Generator().integers()
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'integers')
|
||||
def NumPyRandomGeneratorType_integers(inst, low, high, size=None,
|
||||
dtype=np.int64, endpoint=False):
|
||||
check_types(low, [types.Integer,
|
||||
types.Boolean, bool, int], 'low')
|
||||
check_types(high, [types.Integer, types.Boolean,
|
||||
bool, int], 'high')
|
||||
check_types(endpoint, [types.Boolean, bool], 'endpoint')
|
||||
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if isinstance(dtype, types.Omitted):
|
||||
dtype = dtype.value
|
||||
|
||||
if isinstance(dtype, type):
|
||||
nb_dt = from_dtype(np.dtype(dtype))
|
||||
_dtype = dtype
|
||||
elif isinstance(dtype, types.NumberClass):
|
||||
nb_dt = dtype
|
||||
_dtype = as_dtype(nb_dt)
|
||||
else:
|
||||
raise TypingError("Argument dtype is not one of the" +
|
||||
" expected type(s): " +
|
||||
"np.int32, np.int64, np.int16, np.int8, "
|
||||
"np.uint32, np.uint64, np.uint16, np.uint8, "
|
||||
"np.bool_")
|
||||
|
||||
if _dtype == np.bool_:
|
||||
int_func = random_methods.random_bounded_bool_fill
|
||||
lower_bound = -1
|
||||
upper_bound = 2
|
||||
else:
|
||||
try:
|
||||
i_info = np.iinfo(_dtype)
|
||||
except ValueError:
|
||||
raise TypingError("Argument dtype is not one of the" +
|
||||
" expected type(s): " +
|
||||
"np.int32, np.int64, np.int16, np.int8, "
|
||||
"np.uint32, np.uint64, np.uint16, np.uint8, "
|
||||
"np.bool_")
|
||||
int_func = getattr(random_methods,
|
||||
f'random_bounded_uint{i_info.bits}_fill')
|
||||
lower_bound = i_info.min
|
||||
upper_bound = i_info.max
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, low, high, size=None,
|
||||
dtype=np.int64, endpoint=False):
|
||||
random_methods._randint_arg_check(low, high, endpoint,
|
||||
lower_bound, upper_bound)
|
||||
if not endpoint:
|
||||
high -= dtype(1)
|
||||
low = dtype(low)
|
||||
high = dtype(high)
|
||||
rng = high - low
|
||||
return int_func(inst.bit_generator, low, rng, 1, dtype)[0]
|
||||
else:
|
||||
low = dtype(low)
|
||||
high = dtype(high)
|
||||
rng = high - low
|
||||
return int_func(inst.bit_generator, low, rng, 1, dtype)[0]
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, low, high, size=None,
|
||||
dtype=np.int64, endpoint=False):
|
||||
random_methods._randint_arg_check(low, high, endpoint,
|
||||
lower_bound, upper_bound)
|
||||
if not endpoint:
|
||||
high -= dtype(1)
|
||||
low = dtype(low)
|
||||
high = dtype(high)
|
||||
rng = high - low
|
||||
return int_func(inst.bit_generator, low, rng, size, dtype)
|
||||
else:
|
||||
low = dtype(low)
|
||||
high = dtype(high)
|
||||
rng = high - low
|
||||
return int_func(inst.bit_generator, low, rng, size, dtype)
|
||||
return impl
|
||||
|
||||
|
||||
# The following `shuffle` implementation is a direct translation from:
|
||||
# https://github.com/numpy/numpy/blob/95e3e7f445407e4f355b23d6a9991d8774f0eb0c/numpy/random/_generator.pyx#L4578
|
||||
|
||||
# Overload the Generator().shuffle()
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'shuffle')
|
||||
def NumPyRandomGeneratorType_shuffle(inst, x, axis=0):
|
||||
check_types(x, [types.Array], 'x')
|
||||
check_types(axis, [int, types.Integer], 'axis')
|
||||
|
||||
def impl(inst, x, axis=0):
|
||||
if axis < 0:
|
||||
axis = axis + x.ndim
|
||||
if axis > x.ndim - 1 or axis < 0:
|
||||
raise IndexError("Axis is out of bounds for the given array")
|
||||
|
||||
z = np.swapaxes(x, 0, axis)
|
||||
buf = np.empty_like(z[0, ...])
|
||||
|
||||
for i in range(len(z) - 1, 0, -1):
|
||||
j = types.intp(random_methods.random_interval(inst.bit_generator,
|
||||
i))
|
||||
if i == j:
|
||||
continue
|
||||
buf[...] = z[j, ...]
|
||||
z[j, ...] = z[i, ...]
|
||||
z[i, ...] = buf
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
# The following `permutation` implementation is a direct translation from:
|
||||
# https://github.com/numpy/numpy/blob/95e3e7f445407e4f355b23d6a9991d8774f0eb0c/numpy/random/_generator.pyx#L4710
|
||||
# Overload the Generator().permutation()
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'permutation')
|
||||
def NumPyRandomGeneratorType_permutation(inst, x, axis=0):
|
||||
check_types(x, [types.Array, types.Integer], 'x')
|
||||
check_types(axis, [int, types.Integer], 'axis')
|
||||
|
||||
IS_INT = isinstance(x, types.Integer)
|
||||
|
||||
def impl(inst, x, axis=0):
|
||||
if IS_INT:
|
||||
new_arr = np.arange(x)
|
||||
# NumPy ignores the axis argument when x is an integer
|
||||
inst.shuffle(new_arr)
|
||||
else:
|
||||
new_arr = x.copy()
|
||||
inst.shuffle(new_arr, axis=axis)
|
||||
return new_arr
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().random()
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'random')
|
||||
def NumPyRandomGeneratorType_random(inst, size=None, dtype=np.float64):
|
||||
dist_func, nb_dt = _get_proper_func(next_float, next_double,
|
||||
dtype, "random")
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, size=None, dtype=np.float64):
|
||||
return nb_dt(dist_func(inst.bit_generator))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, size=None, dtype=np.float64):
|
||||
out = np.empty(size, dtype=dtype)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = dist_func(inst.bit_generator)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().standard_exponential() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'standard_exponential')
|
||||
def NumPyRandomGeneratorType_standard_exponential(inst, size=None,
|
||||
dtype=np.float64,
|
||||
method='zig'):
|
||||
check_types(method, [types.UnicodeType, str], 'method')
|
||||
dist_func_inv, nb_dt = _get_proper_func(
|
||||
random_standard_exponential_inv_f,
|
||||
random_standard_exponential_inv,
|
||||
dtype
|
||||
)
|
||||
|
||||
dist_func, nb_dt = _get_proper_func(random_standard_exponential_f,
|
||||
random_standard_exponential,
|
||||
dtype)
|
||||
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, size=None, dtype=np.float64, method='zig'):
|
||||
if method == 'zig':
|
||||
return nb_dt(dist_func(inst.bit_generator))
|
||||
elif method == 'inv':
|
||||
return nb_dt(dist_func_inv(inst.bit_generator))
|
||||
else:
|
||||
raise ValueError("Method must be either 'zig' or 'inv'")
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, size=None, dtype=np.float64, method='zig'):
|
||||
out = np.empty(size, dtype=dtype)
|
||||
out_f = out.flat
|
||||
if method == 'zig':
|
||||
for i in range(out.size):
|
||||
out_f[i] = dist_func(inst.bit_generator)
|
||||
elif method == 'inv':
|
||||
for i in range(out.size):
|
||||
out_f[i] = dist_func_inv(inst.bit_generator)
|
||||
else:
|
||||
raise ValueError("Method must be either 'zig' or 'inv'")
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().standard_normal() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'standard_normal')
|
||||
def NumPyRandomGeneratorType_standard_normal(inst, size=None, dtype=np.float64):
|
||||
dist_func, nb_dt = _get_proper_func(random_standard_normal_f,
|
||||
random_standard_normal,
|
||||
dtype)
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, size=None, dtype=np.float64):
|
||||
return nb_dt(dist_func(inst.bit_generator))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, size=None, dtype=np.float64):
|
||||
out = np.empty(size, dtype=dtype)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = dist_func(inst.bit_generator)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().standard_gamma() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'standard_gamma')
|
||||
def NumPyRandomGeneratorType_standard_gamma(inst, shape, size=None,
|
||||
dtype=np.float64):
|
||||
check_types(shape, [types.Float, types.Integer, int, float], 'shape')
|
||||
dist_func, nb_dt = _get_proper_func(random_standard_gamma_f,
|
||||
random_standard_gamma,
|
||||
dtype)
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, shape, size=None, dtype=np.float64):
|
||||
return nb_dt(dist_func(inst.bit_generator, shape))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, shape, size=None, dtype=np.float64):
|
||||
out = np.empty(size, dtype=dtype)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = dist_func(inst.bit_generator, shape)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().normal() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'normal')
|
||||
def NumPyRandomGeneratorType_normal(inst, loc=0.0, scale=1.0,
|
||||
size=None):
|
||||
check_types(loc, [types.Float, types.Integer, int, float], 'loc')
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, loc=0.0, scale=1.0, size=None):
|
||||
return random_normal(inst.bit_generator, loc, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, loc=0.0, scale=1.0, size=None):
|
||||
out = np.empty(size, dtype=np.float64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_normal(inst.bit_generator, loc, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().uniform() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'uniform')
|
||||
def NumPyRandomGeneratorType_uniform(inst, low=0.0, high=1.0,
|
||||
size=None):
|
||||
check_types(low, [types.Float, types.Integer, int, float], 'low')
|
||||
check_types(high, [types.Float, types.Integer, int, float], 'high')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, low=0.0, high=1.0, size=None):
|
||||
return random_uniform(inst.bit_generator, low, high - low)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, low=0.0, high=1.0, size=None):
|
||||
out = np.empty(size, dtype=np.float64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_uniform(inst.bit_generator, low, high - low)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().exponential() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'exponential')
|
||||
def NumPyRandomGeneratorType_exponential(inst, scale=1.0, size=None):
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, scale=1.0, size=None):
|
||||
return random_exponential(inst.bit_generator, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, scale=1.0, size=None):
|
||||
out = np.empty(size, dtype=np.float64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_exponential(inst.bit_generator, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().gamma() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'gamma')
|
||||
def NumPyRandomGeneratorType_gamma(inst, shape, scale=1.0, size=None):
|
||||
check_types(shape, [types.Float, types.Integer, int, float], 'shape')
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, shape, scale=1.0, size=None):
|
||||
return random_gamma(inst.bit_generator, shape, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, shape, scale=1.0, size=None):
|
||||
out = np.empty(size, dtype=np.float64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_gamma(inst.bit_generator, shape, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().beta() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'beta')
|
||||
def NumPyRandomGeneratorType_beta(inst, a, b, size=None):
|
||||
check_types(a, [types.Float, types.Integer, int, float], 'a')
|
||||
check_types(b, [types.Float, types.Integer, int, float], 'b')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, a, b, size=None):
|
||||
return random_beta(inst.bit_generator, a, b)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, a, b, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_beta(inst.bit_generator, a, b)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().f() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'f')
|
||||
def NumPyRandomGeneratorType_f(inst, dfnum, dfden, size=None):
|
||||
check_types(dfnum, [types.Float, types.Integer, int, float], 'dfnum')
|
||||
check_types(dfden, [types.Float, types.Integer, int, float], 'dfden')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, dfnum, dfden, size=None):
|
||||
return random_f(inst.bit_generator, dfnum, dfden)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, dfnum, dfden, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_f(inst.bit_generator, dfnum, dfden)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
# Overload the Generator().chisquare() method
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'chisquare')
|
||||
def NumPyRandomGeneratorType_chisquare(inst, df, size=None):
|
||||
check_types(df, [types.Float, types.Integer, int, float], 'df')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, df, size=None):
|
||||
return random_chisquare(inst.bit_generator, df)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, df, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_chisquare(inst.bit_generator, df)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'standard_cauchy')
|
||||
def NumPyRandomGeneratorType_standard_cauchy(inst, size=None):
|
||||
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, size=None):
|
||||
return random_standard_cauchy(inst.bit_generator)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_standard_cauchy(inst.bit_generator)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'pareto')
|
||||
def NumPyRandomGeneratorType_pareto(inst, a, size=None):
|
||||
check_types(a, [types.Float, types.Integer, int, float], 'a')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, a, size=None):
|
||||
return random_pareto(inst.bit_generator, a)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, a, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_pareto(inst.bit_generator, a)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'weibull')
|
||||
def NumPyRandomGeneratorType_weibull(inst, a, size=None):
|
||||
check_types(a, [types.Float, types.Integer, int, float], 'a')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, a, size=None):
|
||||
return random_weibull(inst.bit_generator, a)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, a, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_weibull(inst.bit_generator, a)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'power')
|
||||
def NumPyRandomGeneratorType_power(inst, a, size=None):
|
||||
check_types(a, [types.Float, types.Integer, int, float], 'a')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, a, size=None):
|
||||
return random_power(inst.bit_generator, a)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, a, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_power(inst.bit_generator, a)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'laplace')
|
||||
def NumPyRandomGeneratorType_laplace(inst, loc=0.0, scale=1.0, size=None):
|
||||
check_types(loc, [types.Float, types.Integer, int, float], 'loc')
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, loc=0.0, scale=1.0, size=None):
|
||||
return random_laplace(inst.bit_generator, loc, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, loc=0.0, scale=1.0, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_laplace(inst.bit_generator, loc, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'logistic')
|
||||
def NumPyRandomGeneratorType_logistic(inst, loc=0.0, scale=1.0, size=None):
|
||||
check_types(loc, [types.Float, types.Integer, int, float], 'loc')
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, loc=0.0, scale=1.0, size=None):
|
||||
return random_logistic(inst.bit_generator, loc, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, loc=0.0, scale=1.0, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_logistic(inst.bit_generator, loc, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'lognormal')
|
||||
def NumPyRandomGeneratorType_lognormal(inst, mean=0.0, sigma=1.0, size=None):
|
||||
check_types(mean, [types.Float, types.Integer, int, float], 'mean')
|
||||
check_types(sigma, [types.Float, types.Integer, int, float], 'sigma')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, mean=0.0, sigma=1.0, size=None):
|
||||
return random_lognormal(inst.bit_generator, mean, sigma)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, mean=0.0, sigma=1.0, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_lognormal(inst.bit_generator, mean, sigma)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'rayleigh')
|
||||
def NumPyRandomGeneratorType_rayleigh(inst, scale=1.0, size=None):
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, scale=1.0, size=None):
|
||||
return random_rayleigh(inst.bit_generator, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, scale=1.0, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_rayleigh(inst.bit_generator, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'standard_t')
|
||||
def NumPyRandomGeneratorType_standard_t(inst, df, size=None):
|
||||
check_types(df, [types.Float, types.Integer, int, float], 'df')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, df, size=None):
|
||||
return random_standard_t(inst.bit_generator, df)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, df, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_standard_t(inst.bit_generator, df)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'wald')
|
||||
def NumPyRandomGeneratorType_wald(inst, mean, scale, size=None):
|
||||
check_types(mean, [types.Float, types.Integer, int, float], 'mean')
|
||||
check_types(scale, [types.Float, types.Integer, int, float], 'scale')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, mean, scale, size=None):
|
||||
return random_wald(inst.bit_generator, mean, scale)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, mean, scale, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_wald(inst.bit_generator, mean, scale)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'geometric')
|
||||
def NumPyRandomGeneratorType_geometric(inst, p, size=None):
|
||||
check_types(p, [types.Float, types.Integer, int, float], 'p')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, p, size=None):
|
||||
return np.int64(random_geometric(inst.bit_generator, p))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, p, size=None):
|
||||
out = np.empty(size, dtype=np.int64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_geometric(inst.bit_generator, p)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'zipf')
|
||||
def NumPyRandomGeneratorType_zipf(inst, a, size=None):
|
||||
check_types(a, [types.Float, types.Integer, int, float], 'a')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, a, size=None):
|
||||
return np.int64(random_zipf(inst.bit_generator, a))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, a, size=None):
|
||||
out = np.empty(size, dtype=np.int64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_zipf(inst.bit_generator, a)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'triangular')
|
||||
def NumPyRandomGeneratorType_triangular(inst, left, mode, right, size=None):
|
||||
check_types(left, [types.Float, types.Integer, int, float], 'left')
|
||||
check_types(mode, [types.Float, types.Integer, int, float], 'mode')
|
||||
check_types(right, [types.Float, types.Integer, int, float], 'right')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, left, mode, right, size=None):
|
||||
return random_triangular(inst.bit_generator, left, mode, right)
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, left, mode, right, size=None):
|
||||
out = np.empty(size)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_triangular(inst.bit_generator,
|
||||
left, mode, right)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'poisson')
|
||||
def NumPyRandomGeneratorType_poisson(inst, lam , size=None):
|
||||
check_types(lam, [types.Float, types.Integer, int, float], 'lam')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, lam , size=None):
|
||||
return np.int64(random_poisson(inst.bit_generator, lam))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, lam , size=None):
|
||||
out = np.empty(size, dtype=np.int64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_poisson(inst.bit_generator, lam)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'negative_binomial')
|
||||
def NumPyRandomGeneratorType_negative_binomial(inst, n, p, size=None):
|
||||
check_types(n, [types.Float, types.Integer, int, float], 'n')
|
||||
check_types(p, [types.Float, types.Integer, int, float], 'p')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, n, p , size=None):
|
||||
return np.int64(random_negative_binomial(inst.bit_generator, n, p))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, n, p , size=None):
|
||||
out = np.empty(size, dtype=np.int64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_negative_binomial(inst.bit_generator, n, p)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'noncentral_chisquare')
|
||||
def NumPyRandomGeneratorType_noncentral_chisquare(inst, df, nonc, size=None):
|
||||
check_types(df, [types.Float, types.Integer, int, float], 'df')
|
||||
check_types(nonc, [types.Float, types.Integer, int, float], 'nonc')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
@register_jitable
|
||||
def check_arg_bounds(df, nonc):
|
||||
if df <= 0:
|
||||
raise ValueError("df <= 0")
|
||||
if nonc < 0:
|
||||
raise ValueError("nonc < 0")
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, df, nonc, size=None):
|
||||
check_arg_bounds(df, nonc)
|
||||
return np.float64(random_noncentral_chisquare(inst.bit_generator,
|
||||
df, nonc))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, df, nonc, size=None):
|
||||
check_arg_bounds(df, nonc)
|
||||
out = np.empty(size, dtype=np.float64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_noncentral_chisquare(inst.bit_generator,
|
||||
df, nonc)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'noncentral_f')
|
||||
def NumPyRandomGeneratorType_noncentral_f(inst, dfnum, dfden, nonc, size=None):
|
||||
check_types(dfnum, [types.Float, types.Integer, int, float], 'dfnum')
|
||||
check_types(dfden, [types.Float, types.Integer, int, float], 'dfden')
|
||||
check_types(nonc, [types.Float, types.Integer, int, float], 'nonc')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
@register_jitable
|
||||
def check_arg_bounds(dfnum, dfden, nonc):
|
||||
if dfnum <= 0:
|
||||
raise ValueError("dfnum <= 0")
|
||||
if dfden <= 0:
|
||||
raise ValueError("dfden <= 0")
|
||||
if nonc < 0:
|
||||
raise ValueError("nonc < 0")
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, dfnum, dfden, nonc, size=None):
|
||||
check_arg_bounds(dfnum, dfden, nonc)
|
||||
return np.float64(random_noncentral_f(inst.bit_generator,
|
||||
dfnum, dfden, nonc))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, dfnum, dfden, nonc, size=None):
|
||||
check_arg_bounds(dfnum, dfden, nonc)
|
||||
out = np.empty(size, dtype=np.float64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_noncentral_f(inst.bit_generator,
|
||||
dfnum, dfden, nonc)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'logseries')
|
||||
def NumPyRandomGeneratorType_logseries(inst, p, size=None):
|
||||
check_types(p, [types.Float, types.Integer, int, float], 'p')
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
@register_jitable
|
||||
def check_arg_bounds(p):
|
||||
if p < 0 or p >= 1 or np.isnan(p):
|
||||
raise ValueError("p < 0, p >= 1 or p is NaN")
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, p, size=None):
|
||||
check_arg_bounds(p)
|
||||
return np.int64(random_logseries(inst.bit_generator, p))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, p, size=None):
|
||||
check_arg_bounds(p)
|
||||
out = np.empty(size, dtype=np.int64)
|
||||
out_f = out.flat
|
||||
for i in range(out.size):
|
||||
out_f[i] = random_logseries(inst.bit_generator, p)
|
||||
return out
|
||||
return impl
|
||||
|
||||
|
||||
@overload_method(types.NumPyRandomGeneratorType, 'binomial')
|
||||
def NumPyRandomGeneratorType_binomial(inst, n, p, size=None):
|
||||
check_types(n, [types.Float, types.Integer, int, float], 'n')
|
||||
check_types(p, [types.Float, types.Integer, int, float], 'p')
|
||||
|
||||
if isinstance(size, types.Omitted):
|
||||
size = size.value
|
||||
|
||||
if is_nonelike(size):
|
||||
def impl(inst, n, p, size=None):
|
||||
return np.int64(random_binomial(inst.bit_generator, n, p))
|
||||
return impl
|
||||
else:
|
||||
check_size(size)
|
||||
|
||||
def impl(inst, n, p, size=None):
|
||||
out = np.empty(size, dtype=np.int64)
|
||||
for i in np.ndindex(size):
|
||||
out[i] = random_binomial(inst.bit_generator, n, p)
|
||||
return out
|
||||
return impl
|
||||
@@ -0,0 +1,365 @@
|
||||
import numpy as np
|
||||
|
||||
from numba import uint64, uint32, uint16, uint8
|
||||
from numba.core.extending import register_jitable
|
||||
|
||||
from numba.np.random._constants import (UINT32_MAX, UINT64_MAX,
|
||||
UINT16_MAX, UINT8_MAX)
|
||||
from numba.np.random.generator_core import next_uint32, next_uint64
|
||||
|
||||
# All following implementations are direct translations from:
|
||||
# https://github.com/numpy/numpy/blob/7cfef93c77599bd387ecc6a15d186c5a46024dac/numpy/random/src/distributions/distributions.c
|
||||
|
||||
|
||||
@register_jitable
|
||||
def gen_mask(max):
|
||||
mask = uint64(max)
|
||||
mask |= mask >> 1
|
||||
mask |= mask >> 2
|
||||
mask |= mask >> 4
|
||||
mask |= mask >> 8
|
||||
mask |= mask >> 16
|
||||
mask |= mask >> 32
|
||||
return mask
|
||||
|
||||
|
||||
@register_jitable
|
||||
def buffered_bounded_bool(bitgen, off, rng, bcnt, buf):
|
||||
if (rng == 0):
|
||||
return off, bcnt, buf
|
||||
if not bcnt:
|
||||
buf = next_uint32(bitgen)
|
||||
bcnt = 31
|
||||
else:
|
||||
buf >>= 1
|
||||
bcnt -= 1
|
||||
|
||||
return ((buf & 1) != 0), bcnt, buf
|
||||
|
||||
|
||||
@register_jitable
|
||||
def buffered_uint8(bitgen, bcnt, buf):
|
||||
if not bcnt:
|
||||
buf = next_uint32(bitgen)
|
||||
bcnt = 3
|
||||
else:
|
||||
buf >>= 8
|
||||
bcnt -= 1
|
||||
|
||||
return uint8(buf), bcnt, buf
|
||||
|
||||
|
||||
@register_jitable
|
||||
def buffered_uint16(bitgen, bcnt, buf):
|
||||
if not bcnt:
|
||||
buf = next_uint32(bitgen)
|
||||
bcnt = 1
|
||||
else:
|
||||
buf >>= 16
|
||||
bcnt -= 1
|
||||
|
||||
return uint16(buf), bcnt, buf
|
||||
|
||||
|
||||
# The following implementations use Lemire's algorithm:
|
||||
# https://arxiv.org/abs/1805.10941
|
||||
@register_jitable
|
||||
def buffered_bounded_lemire_uint8(bitgen, rng, bcnt, buf):
|
||||
"""
|
||||
Generates a random unsigned 8 bit integer bounded
|
||||
within a given interval using Lemire's rejection.
|
||||
|
||||
The buffer acts as storage for a 32 bit integer
|
||||
drawn from the associated BitGenerator so that
|
||||
multiple integers of smaller bitsize can be generated
|
||||
from a single draw of the BitGenerator.
|
||||
"""
|
||||
# Note: `rng` should not be 0xFF. When this happens `rng_excl` becomes
|
||||
# zero.
|
||||
rng_excl = uint8(rng) + uint8(1)
|
||||
|
||||
assert (rng != 0xFF)
|
||||
|
||||
# Generate a scaled random number.
|
||||
n, bcnt, buf = buffered_uint8(bitgen, bcnt, buf)
|
||||
m = uint16(n * rng_excl)
|
||||
|
||||
# Rejection sampling to remove any bias
|
||||
leftover = m & 0xFF
|
||||
|
||||
if (leftover < rng_excl):
|
||||
# `rng_excl` is a simple upper bound for `threshold`.
|
||||
threshold = ((uint8(UINT8_MAX) - rng) % rng_excl)
|
||||
|
||||
while (leftover < threshold):
|
||||
n, bcnt, buf = buffered_uint8(bitgen, bcnt, buf)
|
||||
m = uint16(n * rng_excl)
|
||||
leftover = m & 0xFF
|
||||
|
||||
return m >> 8, bcnt, buf
|
||||
|
||||
|
||||
@register_jitable
|
||||
def buffered_bounded_lemire_uint16(bitgen, rng, bcnt, buf):
|
||||
"""
|
||||
Generates a random unsigned 16 bit integer bounded
|
||||
within a given interval using Lemire's rejection.
|
||||
|
||||
The buffer acts as storage for a 32 bit integer
|
||||
drawn from the associated BitGenerator so that
|
||||
multiple integers of smaller bitsize can be generated
|
||||
from a single draw of the BitGenerator.
|
||||
"""
|
||||
# Note: `rng` should not be 0xFFFF. When this happens `rng_excl` becomes
|
||||
# zero.
|
||||
rng_excl = uint16(rng) + uint16(1)
|
||||
|
||||
assert (rng != 0xFFFF)
|
||||
|
||||
# Generate a scaled random number.
|
||||
n, bcnt, buf = buffered_uint16(bitgen, bcnt, buf)
|
||||
m = uint32(n * rng_excl)
|
||||
|
||||
# Rejection sampling to remove any bias
|
||||
leftover = m & 0xFFFF
|
||||
|
||||
if (leftover < rng_excl):
|
||||
# `rng_excl` is a simple upper bound for `threshold`.
|
||||
threshold = ((uint16(UINT16_MAX) - rng) % rng_excl)
|
||||
|
||||
while (leftover < threshold):
|
||||
n, bcnt, buf = buffered_uint16(bitgen, bcnt, buf)
|
||||
m = uint32(n * rng_excl)
|
||||
leftover = m & 0xFFFF
|
||||
|
||||
return m >> 16, bcnt, buf
|
||||
|
||||
|
||||
@register_jitable
|
||||
def buffered_bounded_lemire_uint32(bitgen, rng):
|
||||
"""
|
||||
Generates a random unsigned 32 bit integer bounded
|
||||
within a given interval using Lemire's rejection.
|
||||
"""
|
||||
rng_excl = uint32(rng) + uint32(1)
|
||||
|
||||
assert (rng != 0xFFFFFFFF)
|
||||
|
||||
# Generate a scaled random number.
|
||||
m = uint64(next_uint32(bitgen)) * uint64(rng_excl)
|
||||
|
||||
# Rejection sampling to remove any bias
|
||||
leftover = m & 0xFFFFFFFF
|
||||
|
||||
if (leftover < rng_excl):
|
||||
# `rng_excl` is a simple upper bound for `threshold`.
|
||||
threshold = (UINT32_MAX - rng) % rng_excl
|
||||
|
||||
while (leftover < threshold):
|
||||
m = uint64(next_uint32(bitgen)) * uint64(rng_excl)
|
||||
leftover = m & 0xFFFFFFFF
|
||||
|
||||
return (m >> 32)
|
||||
|
||||
|
||||
@register_jitable
|
||||
def bounded_lemire_uint64(bitgen, rng):
|
||||
"""
|
||||
Generates a random unsigned 64 bit integer bounded
|
||||
within a given interval using Lemire's rejection.
|
||||
"""
|
||||
rng_excl = uint64(rng) + uint64(1)
|
||||
|
||||
assert (rng != 0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
x = next_uint64(bitgen)
|
||||
|
||||
leftover = uint64(x) * uint64(rng_excl)
|
||||
|
||||
if (leftover < rng_excl):
|
||||
threshold = (UINT64_MAX - rng) % rng_excl
|
||||
|
||||
while (leftover < threshold):
|
||||
x = next_uint64(bitgen)
|
||||
leftover = uint64(x) * uint64(rng_excl)
|
||||
|
||||
x0 = x & uint64(0xFFFFFFFF)
|
||||
x1 = x >> 32
|
||||
rng_excl0 = rng_excl & uint64(0xFFFFFFFF)
|
||||
rng_excl1 = rng_excl >> 32
|
||||
w0 = x0 * rng_excl0
|
||||
t = x1 * rng_excl0 + (w0 >> 32)
|
||||
w1 = t & uint64(0xFFFFFFFF)
|
||||
w2 = t >> 32
|
||||
w1 += x0 * rng_excl1
|
||||
m1 = x1 * rng_excl1 + w2 + (w1 >> 32)
|
||||
|
||||
return m1
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_bounded_uint64_fill(bitgen, low, rng, size, dtype):
|
||||
"""
|
||||
Returns a new array of given size with 64 bit integers
|
||||
bounded by given interval.
|
||||
"""
|
||||
out = np.empty(size, dtype=dtype)
|
||||
if rng == 0:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low
|
||||
elif rng <= 0xFFFFFFFF:
|
||||
if (rng == 0xFFFFFFFF):
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low + next_uint32(bitgen)
|
||||
else:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low + buffered_bounded_lemire_uint32(bitgen, rng)
|
||||
|
||||
elif (rng == 0xFFFFFFFFFFFFFFFF):
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low + next_uint64(bitgen)
|
||||
else:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low + bounded_lemire_uint64(bitgen, rng)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_bounded_uint32_fill(bitgen, low, rng, size, dtype):
|
||||
"""
|
||||
Returns a new array of given size with 32 bit integers
|
||||
bounded by given interval.
|
||||
"""
|
||||
out = np.empty(size, dtype=dtype)
|
||||
if rng == 0:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low
|
||||
elif rng == 0xFFFFFFFF:
|
||||
# Lemire32 doesn't support rng = 0xFFFFFFFF.
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low + next_uint32(bitgen)
|
||||
else:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low + buffered_bounded_lemire_uint32(bitgen, rng)
|
||||
return out
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_bounded_uint16_fill(bitgen, low, rng, size, dtype):
|
||||
"""
|
||||
Returns a new array of given size with 16 bit integers
|
||||
bounded by given interval.
|
||||
"""
|
||||
buf = 0
|
||||
bcnt = 0
|
||||
|
||||
out = np.empty(size, dtype=dtype)
|
||||
if rng == 0:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low
|
||||
elif rng == 0xFFFF:
|
||||
# Lemire16 doesn't support rng = 0xFFFF.
|
||||
for i in np.ndindex(size):
|
||||
val, bcnt, buf = buffered_uint16(bitgen, bcnt, buf)
|
||||
out[i] = low + val
|
||||
|
||||
else:
|
||||
for i in np.ndindex(size):
|
||||
val, bcnt, buf = \
|
||||
buffered_bounded_lemire_uint16(bitgen, rng,
|
||||
bcnt, buf)
|
||||
out[i] = low + val
|
||||
return out
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_bounded_uint8_fill(bitgen, low, rng, size, dtype):
|
||||
"""
|
||||
Returns a new array of given size with 8 bit integers
|
||||
bounded by given interval.
|
||||
"""
|
||||
buf = 0
|
||||
bcnt = 0
|
||||
|
||||
out = np.empty(size, dtype=dtype)
|
||||
if rng == 0:
|
||||
for i in np.ndindex(size):
|
||||
out[i] = low
|
||||
elif rng == 0xFF:
|
||||
# Lemire8 doesn't support rng = 0xFF.
|
||||
for i in np.ndindex(size):
|
||||
val, bcnt, buf = buffered_uint8(bitgen, bcnt, buf)
|
||||
out[i] = low + val
|
||||
else:
|
||||
for i in np.ndindex(size):
|
||||
val, bcnt, buf = \
|
||||
buffered_bounded_lemire_uint8(bitgen, rng,
|
||||
bcnt, buf)
|
||||
out[i] = low + val
|
||||
return out
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_bounded_bool_fill(bitgen, low, rng, size, dtype):
|
||||
"""
|
||||
Returns a new array of given size with boolean values.
|
||||
"""
|
||||
buf = 0
|
||||
bcnt = 0
|
||||
out = np.empty(size, dtype=dtype)
|
||||
for i in np.ndindex(size):
|
||||
val, bcnt, buf = buffered_bounded_bool(bitgen, low, rng, bcnt, buf)
|
||||
out[i] = low + val
|
||||
return out
|
||||
|
||||
|
||||
@register_jitable
|
||||
def _randint_arg_check(low, high, endpoint, lower_bound, upper_bound):
|
||||
"""
|
||||
Check that low and high are within the bounds
|
||||
for the given datatype.
|
||||
"""
|
||||
|
||||
if low < lower_bound:
|
||||
raise ValueError("low is out of bounds")
|
||||
|
||||
# This is being done to avoid high being accidentally
|
||||
# casted to int64/32 while subtracting 1 before
|
||||
# checking bounds, avoids overflow.
|
||||
if high > 0:
|
||||
high = uint64(high)
|
||||
if not endpoint:
|
||||
high -= uint64(1)
|
||||
upper_bound = uint64(upper_bound)
|
||||
if low > 0:
|
||||
low = uint64(low)
|
||||
if high > upper_bound:
|
||||
raise ValueError("high is out of bounds")
|
||||
if low > high: # -1 already subtracted, closed interval
|
||||
raise ValueError("low is greater than high in given interval")
|
||||
else:
|
||||
if high > upper_bound:
|
||||
raise ValueError("high is out of bounds")
|
||||
if low > high: # -1 already subtracted, closed interval
|
||||
raise ValueError("low is greater than high in given interval")
|
||||
|
||||
|
||||
@register_jitable
|
||||
def random_interval(bitgen, max_val):
|
||||
if (max_val == 0):
|
||||
return 0
|
||||
|
||||
max_val = uint64(max_val)
|
||||
mask = uint64(gen_mask(max_val))
|
||||
|
||||
if (max_val <= 0xffffffff):
|
||||
value = uint64(next_uint32(bitgen)) & mask
|
||||
while value > max_val:
|
||||
value = uint64(next_uint32(bitgen)) & mask
|
||||
else:
|
||||
value = next_uint64(bitgen) & mask
|
||||
while value > max_val:
|
||||
value = next_uint64(bitgen) & mask
|
||||
|
||||
return uint64(value)
|
||||
Reference in New Issue
Block a user