summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/random/mtrand/mtrand.pyx592
-rw-r--r--numpy/random/mtrand/numpy.pxd8
-rw-r--r--numpy/random/tests/test_random.py40
3 files changed, 383 insertions, 257 deletions
diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx
index fdd82979a..3f9dcb687 100644
--- a/numpy/random/mtrand/mtrand.pyx
+++ b/numpy/random/mtrand/mtrand.pyx
@@ -55,65 +55,66 @@ cdef extern from "randomkit.h":
void rk_seed(unsigned long seed, rk_state *state)
rk_error rk_randomseed(rk_state *state)
unsigned long rk_random(rk_state *state)
- long rk_long(rk_state *state)
- unsigned long rk_ulong(rk_state *state)
- unsigned long rk_interval(unsigned long max, rk_state *state)
- double rk_double(rk_state *state)
- void rk_fill(void *buffer, size_t size, rk_state *state)
+ long rk_long(rk_state *state) nogil
+ unsigned long rk_ulong(rk_state *state) nogil
+ unsigned long rk_interval(unsigned long max, rk_state *state) nogil
+ double rk_double(rk_state *state) nogil
+ void rk_fill(void *buffer, size_t size, rk_state *state) nogil
rk_error rk_devfill(void *buffer, size_t size, int strong)
rk_error rk_altfill(void *buffer, size_t size, int strong,
- rk_state *state)
- double rk_gauss(rk_state *state)
+ rk_state *state) nogil
+ double rk_gauss(rk_state *state) nogil
cdef extern from "distributions.h":
-
- double rk_normal(rk_state *state, double loc, double scale)
- double rk_standard_exponential(rk_state *state)
- double rk_exponential(rk_state *state, double scale)
- double rk_uniform(rk_state *state, double loc, double scale)
- double rk_standard_gamma(rk_state *state, double shape)
- double rk_gamma(rk_state *state, double shape, double scale)
- double rk_beta(rk_state *state, double a, double b)
- double rk_chisquare(rk_state *state, double df)
- double rk_noncentral_chisquare(rk_state *state, double df, double nonc)
- double rk_f(rk_state *state, double dfnum, double dfden)
- double rk_noncentral_f(rk_state *state, double dfnum, double dfden, double nonc)
- double rk_standard_cauchy(rk_state *state)
- double rk_standard_t(rk_state *state, double df)
- double rk_vonmises(rk_state *state, double mu, double kappa)
- double rk_pareto(rk_state *state, double a)
- double rk_weibull(rk_state *state, double a)
- double rk_power(rk_state *state, double a)
- double rk_laplace(rk_state *state, double loc, double scale)
- double rk_gumbel(rk_state *state, double loc, double scale)
- double rk_logistic(rk_state *state, double loc, double scale)
- double rk_lognormal(rk_state *state, double mode, double sigma)
- double rk_rayleigh(rk_state *state, double mode)
- double rk_wald(rk_state *state, double mean, double scale)
- double rk_triangular(rk_state *state, double left, double mode, double right)
-
- long rk_binomial(rk_state *state, long n, double p)
- long rk_binomial_btpe(rk_state *state, long n, double p)
- long rk_binomial_inversion(rk_state *state, long n, double p)
- long rk_negative_binomial(rk_state *state, double n, double p)
- long rk_poisson(rk_state *state, double lam)
- long rk_poisson_mult(rk_state *state, double lam)
- long rk_poisson_ptrs(rk_state *state, double lam)
- long rk_zipf(rk_state *state, double a)
- long rk_geometric(rk_state *state, double p)
- long rk_hypergeometric(rk_state *state, long good, long bad, long sample)
- long rk_logseries(rk_state *state, double p)
-
-ctypedef double (* rk_cont0)(rk_state *state)
-ctypedef double (* rk_cont1)(rk_state *state, double a)
-ctypedef double (* rk_cont2)(rk_state *state, double a, double b)
-ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c)
-
-ctypedef long (* rk_disc0)(rk_state *state)
-ctypedef long (* rk_discnp)(rk_state *state, long n, double p)
-ctypedef long (* rk_discdd)(rk_state *state, double n, double p)
-ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N)
-ctypedef long (* rk_discd)(rk_state *state, double a)
+ # do not need the GIL, but they do need a lock on the state !! */
+
+ double rk_normal(rk_state *state, double loc, double scale) nogil
+ double rk_standard_exponential(rk_state *state) nogil
+ double rk_exponential(rk_state *state, double scale) nogil
+ double rk_uniform(rk_state *state, double loc, double scale) nogil
+ double rk_standard_gamma(rk_state *state, double shape) nogil
+ double rk_gamma(rk_state *state, double shape, double scale) nogil
+ double rk_beta(rk_state *state, double a, double b) nogil
+ double rk_chisquare(rk_state *state, double df) nogil
+ double rk_noncentral_chisquare(rk_state *state, double df, double nonc) nogil
+ double rk_f(rk_state *state, double dfnum, double dfden) nogil
+ double rk_noncentral_f(rk_state *state, double dfnum, double dfden, double nonc) nogil
+ double rk_standard_cauchy(rk_state *state) nogil
+ double rk_standard_t(rk_state *state, double df) nogil
+ double rk_vonmises(rk_state *state, double mu, double kappa) nogil
+ double rk_pareto(rk_state *state, double a) nogil
+ double rk_weibull(rk_state *state, double a) nogil
+ double rk_power(rk_state *state, double a) nogil
+ double rk_laplace(rk_state *state, double loc, double scale) nogil
+ double rk_gumbel(rk_state *state, double loc, double scale) nogil
+ double rk_logistic(rk_state *state, double loc, double scale) nogil
+ double rk_lognormal(rk_state *state, double mode, double sigma) nogil
+ double rk_rayleigh(rk_state *state, double mode) nogil
+ double rk_wald(rk_state *state, double mean, double scale) nogil
+ double rk_triangular(rk_state *state, double left, double mode, double right) nogil
+
+ long rk_binomial(rk_state *state, long n, double p) nogil
+ long rk_binomial_btpe(rk_state *state, long n, double p) nogil
+ long rk_binomial_inversion(rk_state *state, long n, double p) nogil
+ long rk_negative_binomial(rk_state *state, double n, double p) nogil
+ long rk_poisson(rk_state *state, double lam) nogil
+ long rk_poisson_mult(rk_state *state, double lam) nogil
+ long rk_poisson_ptrs(rk_state *state, double lam) nogil
+ long rk_zipf(rk_state *state, double a) nogil
+ long rk_geometric(rk_state *state, double p) nogil
+ long rk_hypergeometric(rk_state *state, long good, long bad, long sample) nogil
+ long rk_logseries(rk_state *state, double p) nogil
+
+ctypedef double (* rk_cont0)(rk_state *state) nogil
+ctypedef double (* rk_cont1)(rk_state *state, double a) nogil
+ctypedef double (* rk_cont2)(rk_state *state, double a, double b) nogil
+ctypedef double (* rk_cont3)(rk_state *state, double a, double b, double c) nogil
+
+ctypedef long (* rk_disc0)(rk_state *state) nogil
+ctypedef long (* rk_discnp)(rk_state *state, long n, double p) nogil
+ctypedef long (* rk_discdd)(rk_state *state, double n, double p) nogil
+ctypedef long (* rk_discnmN)(rk_state *state, long n, long m, long N) nogil
+ctypedef long (* rk_discd)(rk_state *state, double a) nogil
cdef extern from "initarray.h":
@@ -126,8 +127,10 @@ import_array()
import numpy as np
import operator
import warnings
+from threading import Lock
-cdef object cont0_array(rk_state *state, rk_cont0 func, object size):
+cdef object cont0_array(rk_state *state, rk_cont0 func, object size,
+ object lock):
cdef double *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -139,12 +142,14 @@ cdef object cont0_array(rk_state *state, rk_cont0 func, object size):
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
array_data = <double *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state)
return array
-cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a):
+cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a,
+ object lock):
cdef double *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -156,11 +161,13 @@ cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
array_data = <double *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, a)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, a)
return array
-cdef object cont1_array(rk_state *state, rk_cont1 func, object size, ndarray oa):
+cdef object cont1_array(rk_state *state, rk_cont1 func, object size,
+ ndarray oa, object lock):
cdef double *array_data
cdef double *oa_data
cdef ndarray array "arrayObject"
@@ -175,9 +182,10 @@ cdef object cont1_array(rk_state *state, rk_cont1 func, object size, ndarray oa)
length = PyArray_SIZE(array)
array_data = <double *>PyArray_DATA(array)
itera = <flatiter>PyArray_IterNew(<object>oa)
- for i from 0 <= i < length:
- array_data[i] = func(state, (<double *>(itera.dataptr))[0])
- PyArray_ITER_NEXT(itera)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, (<double *>(itera.dataptr))[0])
+ PyArray_ITER_NEXT(itera)
else:
array = <ndarray>np.empty(size, np.float64)
array_data = <double *>PyArray_DATA(array)
@@ -185,14 +193,15 @@ cdef object cont1_array(rk_state *state, rk_cont1 func, object size, ndarray oa)
<void *>oa)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- array_data[i] = func(state, oa_data[0])
- PyArray_MultiIter_NEXTi(multi, 1)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ array_data[i] = func(state, oa_data[0])
+ PyArray_MultiIter_NEXTi(multi, 1)
return array
cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a,
- double b):
+ double b, object lock):
cdef double *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -204,13 +213,14 @@ cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
array_data = <double *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, a, b)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, a, b)
return array
cdef object cont2_array(rk_state *state, rk_cont2 func, object size,
- ndarray oa, ndarray ob):
+ ndarray oa, ndarray ob, object lock):
cdef double *array_data
cdef double *oa_data
cdef double *ob_data
@@ -223,27 +233,29 @@ cdef object cont2_array(rk_state *state, rk_cont2 func, object size,
multi = <broadcast> PyArray_MultiIterNew(2, <void *>oa, <void *>ob)
array = <ndarray> PyArray_SimpleNew(multi.nd, multi.dimensions, NPY_DOUBLE)
array_data = <double *>PyArray_DATA(array)
- for i from 0 <= i < multi.size:
- oa_data = <double *>PyArray_MultiIter_DATA(multi, 0)
- ob_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- array_data[i] = func(state, oa_data[0], ob_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ oa_data = <double *>PyArray_MultiIter_DATA(multi, 0)
+ ob_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ array_data[i] = func(state, oa_data[0], ob_data[0])
+ PyArray_MultiIter_NEXT(multi)
else:
array = <ndarray>np.empty(size, np.float64)
array_data = <double *>PyArray_DATA(array)
multi = <broadcast>PyArray_MultiIterNew(3, <void*>array, <void *>oa, <void *>ob)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- ob_data = <double *>PyArray_MultiIter_DATA(multi, 2)
- array_data[i] = func(state, oa_data[0], ob_data[0])
- PyArray_MultiIter_NEXTi(multi, 1)
- PyArray_MultiIter_NEXTi(multi, 2)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ ob_data = <double *>PyArray_MultiIter_DATA(multi, 2)
+ array_data[i] = func(state, oa_data[0], ob_data[0])
+ PyArray_MultiIter_NEXTi(multi, 1)
+ PyArray_MultiIter_NEXTi(multi, 2)
return array
cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a,
- double b, double c):
+ double b, double c, object lock):
cdef double *array_data
cdef ndarray array "arrayObject"
@@ -256,12 +268,13 @@ cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
array_data = <double *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, a, b, c)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, a, b, c)
return array
-cdef object cont3_array(rk_state *state, rk_cont3 func, object size, ndarray oa,
- ndarray ob, ndarray oc):
+cdef object cont3_array(rk_state *state, rk_cont3 func, object size,
+ ndarray oa, ndarray ob, ndarray oc, object lock):
cdef double *array_data
cdef double *oa_data
@@ -276,12 +289,13 @@ cdef object cont3_array(rk_state *state, rk_cont3 func, object size, ndarray oa,
multi = <broadcast> PyArray_MultiIterNew(3, <void *>oa, <void *>ob, <void *>oc)
array = <ndarray> PyArray_SimpleNew(multi.nd, multi.dimensions, NPY_DOUBLE)
array_data = <double *>PyArray_DATA(array)
- for i from 0 <= i < multi.size:
- oa_data = <double *>PyArray_MultiIter_DATA(multi, 0)
- ob_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- oc_data = <double *>PyArray_MultiIter_DATA(multi, 2)
- array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ oa_data = <double *>PyArray_MultiIter_DATA(multi, 0)
+ ob_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ oc_data = <double *>PyArray_MultiIter_DATA(multi, 2)
+ array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0])
+ PyArray_MultiIter_NEXT(multi)
else:
array = <ndarray>np.empty(size, np.float64)
array_data = <double *>PyArray_DATA(array)
@@ -289,15 +303,16 @@ cdef object cont3_array(rk_state *state, rk_cont3 func, object size, ndarray oa,
<void *>ob, <void *>oc)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- ob_data = <double *>PyArray_MultiIter_DATA(multi, 2)
- oc_data = <double *>PyArray_MultiIter_DATA(multi, 3)
- array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ ob_data = <double *>PyArray_MultiIter_DATA(multi, 2)
+ oc_data = <double *>PyArray_MultiIter_DATA(multi, 3)
+ array_data[i] = func(state, oa_data[0], ob_data[0], oc_data[0])
+ PyArray_MultiIter_NEXT(multi)
return array
-cdef object disc0_array(rk_state *state, rk_disc0 func, object size):
+cdef object disc0_array(rk_state *state, rk_disc0 func, object size, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -309,11 +324,13 @@ cdef object disc0_array(rk_state *state, rk_disc0 func, object size):
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state)
return array
-cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size, long n, double p):
+cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size,
+ long n, double p, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -325,11 +342,13 @@ cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size, long n
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, n, p)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, n, p)
return array
-cdef object discnp_array(rk_state *state, rk_discnp func, object size, ndarray on, ndarray op):
+cdef object discnp_array(rk_state *state, rk_discnp func, object size,
+ ndarray on, ndarray op, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -342,27 +361,30 @@ cdef object discnp_array(rk_state *state, rk_discnp func, object size, ndarray o
multi = <broadcast> PyArray_MultiIterNew(2, <void *>on, <void *>op)
array = <ndarray> PyArray_SimpleNew(multi.nd, multi.dimensions, NPY_LONG)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < multi.size:
- on_data = <long *>PyArray_MultiIter_DATA(multi, 0)
- op_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- array_data[i] = func(state, on_data[0], op_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ on_data = <long *>PyArray_MultiIter_DATA(multi, 0)
+ op_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ array_data[i] = func(state, on_data[0], op_data[0])
+ PyArray_MultiIter_NEXT(multi)
else:
array = <ndarray>np.empty(size, int)
array_data = <long *>PyArray_DATA(array)
multi = <broadcast>PyArray_MultiIterNew(3, <void*>array, <void *>on, <void *>op)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- on_data = <long *>PyArray_MultiIter_DATA(multi, 1)
- op_data = <double *>PyArray_MultiIter_DATA(multi, 2)
- array_data[i] = func(state, on_data[0], op_data[0])
- PyArray_MultiIter_NEXTi(multi, 1)
- PyArray_MultiIter_NEXTi(multi, 2)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ on_data = <long *>PyArray_MultiIter_DATA(multi, 1)
+ op_data = <double *>PyArray_MultiIter_DATA(multi, 2)
+ array_data[i] = func(state, on_data[0], op_data[0])
+ PyArray_MultiIter_NEXTi(multi, 1)
+ PyArray_MultiIter_NEXTi(multi, 2)
return array
-cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size, double n, double p):
+cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size,
+ double n, double p, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -374,11 +396,13 @@ cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size, double
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, n, p)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, n, p)
return array
-cdef object discdd_array(rk_state *state, rk_discdd func, object size, ndarray on, ndarray op):
+cdef object discdd_array(rk_state *state, rk_discdd func, object size,
+ ndarray on, ndarray op, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -391,28 +415,30 @@ cdef object discdd_array(rk_state *state, rk_discdd func, object size, ndarray o
multi = <broadcast> PyArray_MultiIterNew(2, <void *>on, <void *>op)
array = <ndarray> PyArray_SimpleNew(multi.nd, multi.dimensions, NPY_LONG)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < multi.size:
- on_data = <double *>PyArray_MultiIter_DATA(multi, 0)
- op_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- array_data[i] = func(state, on_data[0], op_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ on_data = <double *>PyArray_MultiIter_DATA(multi, 0)
+ op_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ array_data[i] = func(state, on_data[0], op_data[0])
+ PyArray_MultiIter_NEXT(multi)
else:
array = <ndarray>np.empty(size, int)
array_data = <long *>PyArray_DATA(array)
multi = <broadcast>PyArray_MultiIterNew(3, <void*>array, <void *>on, <void *>op)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- on_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- op_data = <double *>PyArray_MultiIter_DATA(multi, 2)
- array_data[i] = func(state, on_data[0], op_data[0])
- PyArray_MultiIter_NEXTi(multi, 1)
- PyArray_MultiIter_NEXTi(multi, 2)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ on_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ op_data = <double *>PyArray_MultiIter_DATA(multi, 2)
+ array_data[i] = func(state, on_data[0], op_data[0])
+ PyArray_MultiIter_NEXTi(multi, 1)
+ PyArray_MultiIter_NEXTi(multi, 2)
return array
cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size,
- long n, long m, long N):
+ long n, long m, long N, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -424,12 +450,13 @@ cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size,
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, n, m, N)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, n, m, N)
return array
cdef object discnmN_array(rk_state *state, rk_discnmN func, object size,
- ndarray on, ndarray om, ndarray oN):
+ ndarray on, ndarray om, ndarray oN, object lock):
cdef long *array_data
cdef long *on_data
cdef long *om_data
@@ -443,12 +470,13 @@ cdef object discnmN_array(rk_state *state, rk_discnmN func, object size,
multi = <broadcast> PyArray_MultiIterNew(3, <void *>on, <void *>om, <void *>oN)
array = <ndarray> PyArray_SimpleNew(multi.nd, multi.dimensions, NPY_LONG)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < multi.size:
- on_data = <long *>PyArray_MultiIter_DATA(multi, 0)
- om_data = <long *>PyArray_MultiIter_DATA(multi, 1)
- oN_data = <long *>PyArray_MultiIter_DATA(multi, 2)
- array_data[i] = func(state, on_data[0], om_data[0], oN_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ on_data = <long *>PyArray_MultiIter_DATA(multi, 0)
+ om_data = <long *>PyArray_MultiIter_DATA(multi, 1)
+ oN_data = <long *>PyArray_MultiIter_DATA(multi, 2)
+ array_data[i] = func(state, on_data[0], om_data[0], oN_data[0])
+ PyArray_MultiIter_NEXT(multi)
else:
array = <ndarray>np.empty(size, int)
array_data = <long *>PyArray_DATA(array)
@@ -456,16 +484,18 @@ cdef object discnmN_array(rk_state *state, rk_discnmN func, object size,
<void *>oN)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- on_data = <long *>PyArray_MultiIter_DATA(multi, 1)
- om_data = <long *>PyArray_MultiIter_DATA(multi, 2)
- oN_data = <long *>PyArray_MultiIter_DATA(multi, 3)
- array_data[i] = func(state, on_data[0], om_data[0], oN_data[0])
- PyArray_MultiIter_NEXT(multi)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ on_data = <long *>PyArray_MultiIter_DATA(multi, 1)
+ om_data = <long *>PyArray_MultiIter_DATA(multi, 2)
+ oN_data = <long *>PyArray_MultiIter_DATA(multi, 3)
+ array_data[i] = func(state, on_data[0], om_data[0], oN_data[0])
+ PyArray_MultiIter_NEXT(multi)
return array
-cdef object discd_array_sc(rk_state *state, rk_discd func, object size, double a):
+cdef object discd_array_sc(rk_state *state, rk_discd func, object size,
+ double a, object lock):
cdef long *array_data
cdef ndarray array "arrayObject"
cdef npy_intp length
@@ -477,11 +507,13 @@ cdef object discd_array_sc(rk_state *state, rk_discd func, object size, double a
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < length:
- array_data[i] = func(state, a)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, a)
return array
-cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa):
+cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa,
+ object lock):
cdef long *array_data
cdef double *oa_data
cdef ndarray array "arrayObject"
@@ -496,19 +528,21 @@ cdef object discd_array(rk_state *state, rk_discd func, object size, ndarray oa)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
itera = <flatiter>PyArray_IterNew(<object>oa)
- for i from 0 <= i < length:
- array_data[i] = func(state, (<double *>(itera.dataptr))[0])
- PyArray_ITER_NEXT(itera)
+ with lock, nogil:
+ for i from 0 <= i < length:
+ array_data[i] = func(state, (<double *>(itera.dataptr))[0])
+ PyArray_ITER_NEXT(itera)
else:
array = <ndarray>np.empty(size, int)
array_data = <long *>PyArray_DATA(array)
multi = <broadcast>PyArray_MultiIterNew(2, <void *>array, <void *>oa)
if (multi.size != PyArray_SIZE(array)):
raise ValueError("size is not compatible with inputs")
- for i from 0 <= i < multi.size:
- oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
- array_data[i] = func(state, oa_data[0])
- PyArray_MultiIter_NEXTi(multi, 1)
+ with lock, nogil:
+ for i from 0 <= i < multi.size:
+ oa_data = <double *>PyArray_MultiIter_DATA(multi, 1)
+ array_data[i] = func(state, oa_data[0])
+ PyArray_MultiIter_NEXTi(multi, 1)
return array
cdef double kahan_sum(double *darr, npy_intp n):
@@ -567,12 +601,14 @@ cdef class RandomState:
"""
cdef rk_state *internal_state
+ cdef object lock
poisson_lam_max = np.iinfo('l').max - np.sqrt(np.iinfo('l').max)*10
def __init__(self, seed=None):
self.internal_state = <rk_state*>PyMem_Malloc(sizeof(rk_state))
self.seed(seed)
+ self.lock = Lock()
def __dealloc__(self):
if self.internal_state != NULL:
@@ -770,7 +806,7 @@ cdef class RandomState:
[-1.23204345, -1.75224494]])
"""
- return cont0_array(self.internal_state, rk_double, size)
+ return cont0_array(self.internal_state, rk_double, size, self.lock)
def tomaxint(self, size=None):
"""
@@ -817,7 +853,7 @@ cdef class RandomState:
[ True, True]]], dtype=bool)
"""
- return disc0_array(self.internal_state, rk_long, size)
+ return disc0_array(self.internal_state, rk_long, size, self.lock)
def randint(self, low, high=None, size=None):
"""
@@ -895,9 +931,10 @@ cdef class RandomState:
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
array_data = <long *>PyArray_DATA(array)
- for i from 0 <= i < length:
- rv = lo + <long>rk_interval(diff, self. internal_state)
- array_data[i] = rv
+ with self.lock, nogil:
+ for i from 0 <= i < length:
+ rv = lo + <long>rk_interval(diff, self. internal_state)
+ array_data[i] = rv
return array
def bytes(self, npy_intp length):
@@ -924,7 +961,8 @@ cdef class RandomState:
"""
cdef void *bytes
bytestring = empty_py_bytes(length, &bytes)
- rk_fill(bytes, length, self.internal_state)
+ with self.lock, nogil:
+ rk_fill(bytes, length, self.internal_state)
return bytestring
@@ -1181,7 +1219,9 @@ cdef class RandomState:
flow = PyFloat_AsDouble(low)
fhigh = PyFloat_AsDouble(high)
if not PyErr_Occurred():
- return cont2_array_sc(self.internal_state, rk_uniform, size, flow, fhigh-flow)
+ return cont2_array_sc(self.internal_state, rk_uniform, size, flow,
+ fhigh-flow, self.lock)
+
PyErr_Clear()
olow = <ndarray>PyArray_FROM_OTF(low, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
ohigh = <ndarray>PyArray_FROM_OTF(high, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
@@ -1189,7 +1229,8 @@ cdef class RandomState:
Py_INCREF(temp) # needed to get around Pyrex's automatic reference-counting
# rules because EnsureArray steals a reference
odiff = <ndarray>PyArray_EnsureArray(temp)
- return cont2_array(self.internal_state, rk_uniform, size, olow, odiff)
+ return cont2_array(self.internal_state, rk_uniform, size, olow, odiff,
+ self.lock)
def rand(self, *args):
"""
@@ -1403,7 +1444,7 @@ cdef class RandomState:
(3, 4, 2)
"""
- return cont0_array(self.internal_state, rk_gauss, size)
+ return cont0_array(self.internal_state, rk_gauss, size, self.lock)
def normal(self, loc=0.0, scale=1.0, size=None):
"""
@@ -1496,7 +1537,8 @@ cdef class RandomState:
if not PyErr_Occurred():
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_normal, size, floc, fscale)
+ return cont2_array_sc(self.internal_state, rk_normal, size, floc,
+ fscale, self.lock)
PyErr_Clear()
@@ -1504,7 +1546,8 @@ cdef class RandomState:
oscale = <ndarray>PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oscale, 0)):
raise ValueError("scale <= 0")
- return cont2_array(self.internal_state, rk_normal, size, oloc, oscale)
+ return cont2_array(self.internal_state, rk_normal, size, oloc, oscale,
+ self.lock)
def beta(self, a, b, size=None):
"""
@@ -1554,7 +1597,8 @@ cdef class RandomState:
raise ValueError("a <= 0")
if fb <= 0:
raise ValueError("b <= 0")
- return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb)
+ return cont2_array_sc(self.internal_state, rk_beta, size, fa, fb,
+ self.lock)
PyErr_Clear()
@@ -1564,7 +1608,8 @@ cdef class RandomState:
raise ValueError("a <= 0")
if np.any(np.less_equal(ob, 0)):
raise ValueError("b <= 0")
- return cont2_array(self.internal_state, rk_beta, size, oa, ob)
+ return cont2_array(self.internal_state, rk_beta, size, oa, ob,
+ self.lock)
def exponential(self, scale=1.0, size=None):
"""
@@ -1612,14 +1657,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont1_array_sc(self.internal_state, rk_exponential, size, fscale)
+ return cont1_array_sc(self.internal_state, rk_exponential, size,
+ fscale, self.lock)
PyErr_Clear()
oscale = <ndarray> PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oscale, 0.0)):
raise ValueError("scale <= 0")
- return cont1_array(self.internal_state, rk_exponential, size, oscale)
+ return cont1_array(self.internal_state, rk_exponential, size, oscale,
+ self.lock)
def standard_exponential(self, size=None):
"""
@@ -1649,7 +1696,8 @@ cdef class RandomState:
>>> n = np.random.standard_exponential((3, 8000))
"""
- return cont0_array(self.internal_state, rk_standard_exponential, size)
+ return cont0_array(self.internal_state, rk_standard_exponential, size,
+ self.lock)
def standard_gamma(self, shape, size=None):
"""
@@ -1726,13 +1774,14 @@ cdef class RandomState:
if not PyErr_Occurred():
if fshape <= 0:
raise ValueError("shape <= 0")
- return cont1_array_sc(self.internal_state, rk_standard_gamma, size, fshape)
+ return cont1_array_sc(self.internal_state, rk_standard_gamma, size, fshape, self.lock)
PyErr_Clear()
oshape = <ndarray> PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oshape, 0.0)):
raise ValueError("shape <= 0")
- return cont1_array(self.internal_state, rk_standard_gamma, size, oshape)
+ return cont1_array(self.internal_state, rk_standard_gamma, size,
+ oshape, self.lock)
def gamma(self, shape, scale=1.0, size=None):
"""
@@ -1815,7 +1864,8 @@ cdef class RandomState:
raise ValueError("shape <= 0")
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_gamma, size, fshape, fscale)
+ return cont2_array_sc(self.internal_state, rk_gamma, size, fshape,
+ fscale, self.lock)
PyErr_Clear()
oshape = <ndarray>PyArray_FROM_OTF(shape, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
@@ -1824,7 +1874,8 @@ cdef class RandomState:
raise ValueError("shape <= 0")
if np.any(np.less_equal(oscale, 0.0)):
raise ValueError("scale <= 0")
- return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale)
+ return cont2_array(self.internal_state, rk_gamma, size, oshape, oscale,
+ self.lock)
def f(self, dfnum, dfden, size=None):
"""
@@ -1916,7 +1967,8 @@ cdef class RandomState:
raise ValueError("shape <= 0")
if fdfden <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_f, size, fdfnum, fdfden)
+ return cont2_array_sc(self.internal_state, rk_f, size, fdfnum,
+ fdfden, self.lock)
PyErr_Clear()
@@ -1926,7 +1978,8 @@ cdef class RandomState:
raise ValueError("dfnum <= 0")
if np.any(np.less_equal(odfden, 0.0)):
raise ValueError("dfden <= 0")
- return cont2_array(self.internal_state, rk_f, size, odfnum, odfden)
+ return cont2_array(self.internal_state, rk_f, size, odfnum, odfden,
+ self.lock)
def noncentral_f(self, dfnum, dfden, nonc, size=None):
"""
@@ -2007,7 +2060,7 @@ cdef class RandomState:
if fnonc < 0:
raise ValueError("nonc < 0")
return cont3_array_sc(self.internal_state, rk_noncentral_f, size,
- fdfnum, fdfden, fnonc)
+ fdfnum, fdfden, fnonc, self.lock)
PyErr_Clear()
@@ -2022,7 +2075,7 @@ cdef class RandomState:
if np.any(np.less(ononc, 0.0)):
raise ValueError("nonc < 0")
return cont3_array(self.internal_state, rk_noncentral_f, size, odfnum,
- odfden, ononc)
+ odfden, ononc, self.lock)
def chisquare(self, df, size=None):
"""
@@ -2094,14 +2147,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fdf <= 0:
raise ValueError("df <= 0")
- return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf)
+ return cont1_array_sc(self.internal_state, rk_chisquare, size, fdf,
+ self.lock)
PyErr_Clear()
odf = <ndarray>PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(odf, 0.0)):
raise ValueError("df <= 0")
- return cont1_array(self.internal_state, rk_chisquare, size, odf)
+ return cont1_array(self.internal_state, rk_chisquare, size, odf,
+ self.lock)
def noncentral_chisquare(self, df, nonc, size=None):
"""
@@ -2184,7 +2239,7 @@ cdef class RandomState:
if fnonc <= 0:
raise ValueError("nonc <= 0")
return cont2_array_sc(self.internal_state, rk_noncentral_chisquare,
- size, fdf, fnonc)
+ size, fdf, fnonc, self.lock)
PyErr_Clear()
@@ -2195,7 +2250,7 @@ cdef class RandomState:
if np.any(np.less_equal(ononc, 0.0)):
raise ValueError("nonc < 0")
return cont2_array(self.internal_state, rk_noncentral_chisquare, size,
- odf, ononc)
+ odf, ononc, self.lock)
def standard_cauchy(self, size=None):
"""
@@ -2258,7 +2313,8 @@ cdef class RandomState:
>>> plt.show()
"""
- return cont0_array(self.internal_state, rk_standard_cauchy, size)
+ return cont0_array(self.internal_state, rk_standard_cauchy, size,
+ self.lock)
def standard_t(self, df, size=None):
"""
@@ -2353,14 +2409,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fdf <= 0:
raise ValueError("df <= 0")
- return cont1_array_sc(self.internal_state, rk_standard_t, size, fdf)
+ return cont1_array_sc(self.internal_state, rk_standard_t, size,
+ fdf, self.lock)
PyErr_Clear()
odf = <ndarray> PyArray_FROM_OTF(df, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(odf, 0.0)):
raise ValueError("df <= 0")
- return cont1_array(self.internal_state, rk_standard_t, size, odf)
+ return cont1_array(self.internal_state, rk_standard_t, size, odf,
+ self.lock)
def vonmises(self, mu, kappa, size=None):
"""
@@ -2447,7 +2505,8 @@ cdef class RandomState:
if not PyErr_Occurred():
if fkappa < 0:
raise ValueError("kappa < 0")
- return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu, fkappa)
+ return cont2_array_sc(self.internal_state, rk_vonmises, size, fmu,
+ fkappa, self.lock)
PyErr_Clear()
@@ -2455,7 +2514,8 @@ cdef class RandomState:
okappa = <ndarray> PyArray_FROM_OTF(kappa, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less(okappa, 0.0)):
raise ValueError("kappa < 0")
- return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa)
+ return cont2_array(self.internal_state, rk_vonmises, size, omu, okappa,
+ self.lock)
def pareto(self, a, size=None):
"""
@@ -2545,14 +2605,15 @@ cdef class RandomState:
if not PyErr_Occurred():
if fa <= 0:
raise ValueError("a <= 0")
- return cont1_array_sc(self.internal_state, rk_pareto, size, fa)
+ return cont1_array_sc(self.internal_state, rk_pareto, size, fa,
+ self.lock)
PyErr_Clear()
oa = <ndarray>PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oa, 0.0)):
raise ValueError("a <= 0")
- return cont1_array(self.internal_state, rk_pareto, size, oa)
+ return cont1_array(self.internal_state, rk_pareto, size, oa, self.lock)
def weibull(self, a, size=None):
"""
@@ -2646,14 +2707,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fa <= 0:
raise ValueError("a <= 0")
- return cont1_array_sc(self.internal_state, rk_weibull, size, fa)
+ return cont1_array_sc(self.internal_state, rk_weibull, size, fa,
+ self.lock)
PyErr_Clear()
oa = <ndarray>PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oa, 0.0)):
raise ValueError("a <= 0")
- return cont1_array(self.internal_state, rk_weibull, size, oa)
+ return cont1_array(self.internal_state, rk_weibull, size, oa,
+ self.lock)
def power(self, a, size=None):
"""
@@ -2756,14 +2819,15 @@ cdef class RandomState:
if not PyErr_Occurred():
if fa <= 0:
raise ValueError("a <= 0")
- return cont1_array_sc(self.internal_state, rk_power, size, fa)
+ return cont1_array_sc(self.internal_state, rk_power, size, fa,
+ self.lock)
PyErr_Clear()
oa = <ndarray>PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oa, 0.0)):
raise ValueError("a <= 0")
- return cont1_array(self.internal_state, rk_power, size, oa)
+ return cont1_array(self.internal_state, rk_power, size, oa, self.lock)
def laplace(self, loc=0.0, scale=1.0, size=None):
"""
@@ -2850,14 +2914,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_laplace, size, floc, fscale)
+ return cont2_array_sc(self.internal_state, rk_laplace, size, floc,
+ fscale, self.lock)
PyErr_Clear()
oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oscale, 0.0)):
raise ValueError("scale <= 0")
- return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale)
+ return cont2_array(self.internal_state, rk_laplace, size, oloc, oscale,
+ self.lock)
def gumbel(self, loc=0.0, scale=1.0, size=None):
"""
@@ -2982,14 +3048,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_gumbel, size, floc, fscale)
+ return cont2_array_sc(self.internal_state, rk_gumbel, size, floc,
+ fscale, self.lock)
PyErr_Clear()
oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oscale, 0.0)):
raise ValueError("scale <= 0")
- return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale)
+ return cont2_array(self.internal_state, rk_gumbel, size, oloc, oscale,
+ self.lock)
def logistic(self, loc=0.0, scale=1.0, size=None):
"""
@@ -3071,14 +3139,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_logistic, size, floc, fscale)
+ return cont2_array_sc(self.internal_state, rk_logistic, size, floc,
+ fscale, self.lock)
PyErr_Clear()
oloc = PyArray_FROM_OTF(loc, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
oscale = PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oscale, 0.0)):
raise ValueError("scale <= 0")
- return cont2_array(self.internal_state, rk_logistic, size, oloc, oscale)
+ return cont2_array(self.internal_state, rk_logistic, size, oloc,
+ oscale, self.lock)
def lognormal(self, mean=0.0, sigma=1.0, size=None):
"""
@@ -3192,7 +3262,8 @@ cdef class RandomState:
if not PyErr_Occurred():
if fsigma <= 0:
raise ValueError("sigma <= 0")
- return cont2_array_sc(self.internal_state, rk_lognormal, size, fmean, fsigma)
+ return cont2_array_sc(self.internal_state, rk_lognormal, size,
+ fmean, fsigma, self.lock)
PyErr_Clear()
@@ -3200,7 +3271,8 @@ cdef class RandomState:
osigma = PyArray_FROM_OTF(sigma, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(osigma, 0.0)):
raise ValueError("sigma <= 0.0")
- return cont2_array(self.internal_state, rk_lognormal, size, omean, osigma)
+ return cont2_array(self.internal_state, rk_lognormal, size, omean,
+ osigma, self.lock)
def rayleigh(self, scale=1.0, size=None):
"""
@@ -3266,14 +3338,16 @@ cdef class RandomState:
if not PyErr_Occurred():
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont1_array_sc(self.internal_state, rk_rayleigh, size, fscale)
+ return cont1_array_sc(self.internal_state, rk_rayleigh, size,
+ fscale, self.lock)
PyErr_Clear()
oscale = <ndarray>PyArray_FROM_OTF(scale, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oscale, 0.0)):
raise ValueError("scale <= 0.0")
- return cont1_array(self.internal_state, rk_rayleigh, size, oscale)
+ return cont1_array(self.internal_state, rk_rayleigh, size, oscale,
+ self.lock)
def wald(self, mean, scale, size=None):
"""
@@ -3349,7 +3423,8 @@ cdef class RandomState:
raise ValueError("mean <= 0")
if fscale <= 0:
raise ValueError("scale <= 0")
- return cont2_array_sc(self.internal_state, rk_wald, size, fmean, fscale)
+ return cont2_array_sc(self.internal_state, rk_wald, size, fmean,
+ fscale, self.lock)
PyErr_Clear()
omean = PyArray_FROM_OTF(mean, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
@@ -3358,7 +3433,8 @@ cdef class RandomState:
raise ValueError("mean <= 0.0")
elif np.any(np.less_equal(oscale,0.0)):
raise ValueError("scale <= 0.0")
- return cont2_array(self.internal_state, rk_wald, size, omean, oscale)
+ return cont2_array(self.internal_state, rk_wald, size, omean, oscale,
+ self.lock)
def triangular(self, left, mode, right, size=None):
"""
@@ -3432,7 +3508,7 @@ cdef class RandomState:
if fleft == fright:
raise ValueError("left == right")
return cont3_array_sc(self.internal_state, rk_triangular, size, fleft,
- fmode, fright)
+ fmode, fright, self.lock)
PyErr_Clear()
oleft = <ndarray>PyArray_FROM_OTF(left, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
@@ -3446,7 +3522,7 @@ cdef class RandomState:
if np.any(np.equal(oleft, oright)):
raise ValueError("left == right")
return cont3_array(self.internal_state, rk_triangular, size, oleft,
- omode, oright)
+ omode, oright, self.lock)
# Complicated, discrete distributions:
def binomial(self, n, p, size=None):
@@ -3546,7 +3622,8 @@ cdef class RandomState:
raise ValueError("p > 1")
elif np.isnan(fp):
raise ValueError("p is nan")
- return discnp_array_sc(self.internal_state, rk_binomial, size, ln, fp)
+ return discnp_array_sc(self.internal_state, rk_binomial, size, ln,
+ fp, self.lock)
PyErr_Clear()
@@ -3558,7 +3635,8 @@ cdef class RandomState:
raise ValueError("p < 0")
if np.any(np.greater(p, 1)):
raise ValueError("p > 1")
- return discnp_array(self.internal_state, rk_binomial, size, on, op)
+ return discnp_array(self.internal_state, rk_binomial, size, on, op,
+ self.lock)
def negative_binomial(self, n, p, size=None):
"""
@@ -3641,7 +3719,7 @@ cdef class RandomState:
elif fp > 1:
raise ValueError("p > 1")
return discdd_array_sc(self.internal_state, rk_negative_binomial,
- size, fn, fp)
+ size, fn, fp, self.lock)
PyErr_Clear()
@@ -3654,7 +3732,7 @@ cdef class RandomState:
if np.any(np.greater(p, 1)):
raise ValueError("p > 1")
return discdd_array(self.internal_state, rk_negative_binomial, size,
- on, op)
+ on, op, self.lock)
def poisson(self, lam=1.0, size=None):
"""
@@ -3717,7 +3795,8 @@ cdef class RandomState:
raise ValueError("lam < 0")
if lam > self.poisson_lam_max:
raise ValueError("lam value too large")
- return discd_array_sc(self.internal_state, rk_poisson, size, flam)
+ return discd_array_sc(self.internal_state, rk_poisson, size, flam,
+ self.lock)
PyErr_Clear()
@@ -3726,7 +3805,7 @@ cdef class RandomState:
raise ValueError("lam < 0")
if np.any(np.greater(olam, self.poisson_lam_max)):
raise ValueError("lam value too large.")
- return discd_array(self.internal_state, rk_poisson, size, olam)
+ return discd_array(self.internal_state, rk_poisson, size, olam, self.lock)
def zipf(self, a, size=None):
"""
@@ -3805,14 +3884,15 @@ cdef class RandomState:
if not PyErr_Occurred():
if fa <= 1.0:
raise ValueError("a <= 1.0")
- return discd_array_sc(self.internal_state, rk_zipf, size, fa)
+ return discd_array_sc(self.internal_state, rk_zipf, size, fa,
+ self.lock)
PyErr_Clear()
oa = <ndarray>PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_ARRAY_ALIGNED)
if np.any(np.less_equal(oa, 1.0)):
raise ValueError("a <= 1.0")
- return discd_array(self.internal_state, rk_zipf, size, oa)
+ return discd_array(self.internal_state, rk_zipf, size, oa, self.lock)
def geometric(self, p, size=None):
"""
@@ -3869,7 +3949,8 @@ cdef class RandomState:
raise ValueError("p < 0.0")
if fp > 1.0:
raise ValueError("p > 1.0")
- return discd_array_sc(self.internal_state, rk_geometric, size, fp)
+ return discd_array_sc(self.internal_state, rk_geometric, size, fp,
+ self.lock)
PyErr_Clear()
@@ -3879,7 +3960,7 @@ cdef class RandomState:
raise ValueError("p < 0.0")
if np.any(np.greater(op, 1.0)):
raise ValueError("p > 1.0")
- return discd_array(self.internal_state, rk_geometric, size, op)
+ return discd_array(self.internal_state, rk_geometric, size, op, self.lock)
def hypergeometric(self, ngood, nbad, nsample, size=None):
"""
@@ -3982,8 +4063,8 @@ cdef class RandomState:
raise ValueError("nsample < 1")
if lngood + lnbad < lnsample:
raise ValueError("ngood + nbad < nsample")
- return discnmN_array_sc(self.internal_state, rk_hypergeometric, size,
- lngood, lnbad, lnsample)
+ return discnmN_array_sc(self.internal_state, rk_hypergeometric,
+ size, lngood, lnbad, lnsample, self.lock)
PyErr_Clear()
@@ -3999,7 +4080,7 @@ cdef class RandomState:
if np.any(np.less(np.add(ongood, onbad),onsample)):
raise ValueError("ngood + nbad < nsample")
return discnmN_array(self.internal_state, rk_hypergeometric, size,
- ongood, onbad, onsample)
+ ongood, onbad, onsample, self.lock)
def logseries(self, p, size=None):
"""
@@ -4085,7 +4166,8 @@ cdef class RandomState:
raise ValueError("p <= 0.0")
if fp >= 1.0:
raise ValueError("p >= 1.0")
- return discd_array_sc(self.internal_state, rk_logseries, size, fp)
+ return discd_array_sc(self.internal_state, rk_logseries, size, fp,
+ self.lock)
PyErr_Clear()
@@ -4094,7 +4176,7 @@ cdef class RandomState:
raise ValueError("p <= 0.0")
if np.any(np.greater_equal(op, 1.0)):
raise ValueError("p >= 1.0")
- return discd_array(self.internal_state, rk_logseries, size, op)
+ return discd_array(self.internal_state, rk_logseries, size, op, self.lock)
# Multivariate distributions:
def multivariate_normal(self, mean, cov, size=None):
@@ -4296,7 +4378,7 @@ cdef class RandomState:
cdef ndarray parr "arrayObject_parr", mnarr "arrayObject_mnarr"
cdef double *pix
cdef long *mnix
- cdef npy_intp i, j, dn
+ cdef npy_intp i, j, dn, sz
cdef double Sum
d = len(pvals)
@@ -4311,20 +4393,22 @@ cdef class RandomState:
multin = np.zeros(shape, int)
mnarr = <ndarray>multin
mnix = <long*>PyArray_DATA(mnarr)
- i = 0
- while i < PyArray_SIZE(mnarr):
- Sum = 1.0
- dn = n
- for j from 0 <= j < d-1:
- mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum)
- dn = dn - mnix[i+j]
- if dn <= 0:
- break
- Sum = Sum - pix[j]
- if dn > 0:
- mnix[i+d-1] = dn
-
- i = i + d
+ sz = PyArray_SIZE(mnarr)
+ with self.lock, nogil:
+ i = 0
+ while i < sz:
+ Sum = 1.0
+ dn = n
+ for j from 0 <= j < d-1:
+ mnix[i+j] = rk_binomial(self.internal_state, dn, pix[j]/Sum)
+ dn = dn - mnix[i+j]
+ if dn <= 0:
+ break
+ Sum = Sum - pix[j]
+ if dn > 0:
+ mnix[i+d-1] = dn
+
+ i = i + d
return multin
@@ -4427,15 +4511,17 @@ cdef class RandomState:
i = 0
totsize = PyArray_SIZE(val_arr)
- while i < totsize:
- acc = 0.0
- for j from 0 <= j < k:
- val_data[i+j] = rk_standard_gamma(self.internal_state, alpha_data[j])
- acc = acc + val_data[i+j]
- invacc = 1/acc
- for j from 0 <= j < k:
- val_data[i+j] = val_data[i+j] * invacc
- i = i + k
+ with self.lock, nogil:
+ while i < totsize:
+ acc = 0.0
+ for j from 0 <= j < k:
+ val_data[i+j] = rk_standard_gamma(self.internal_state,
+ alpha_data[j])
+ acc = acc + val_data[i+j]
+ invacc = 1/acc
+ for j from 0 <= j < k:
+ val_data[i+j] = val_data[i+j] * invacc
+ i = i + k
return diric
diff --git a/numpy/random/mtrand/numpy.pxd b/numpy/random/mtrand/numpy.pxd
index 572b51fdd..6812cc164 100644
--- a/numpy/random/mtrand/numpy.pxd
+++ b/numpy/random/mtrand/numpy.pxd
@@ -114,12 +114,12 @@ cdef extern from "numpy/arrayobject.h":
object PyArray_MultiIterNew(int n, ...)
- char *PyArray_MultiIter_DATA(broadcast multi, int i)
- void PyArray_MultiIter_NEXTi(broadcast multi, int i)
- void PyArray_MultiIter_NEXT(broadcast multi)
+ char *PyArray_MultiIter_DATA(broadcast multi, int i) nogil
+ void PyArray_MultiIter_NEXTi(broadcast multi, int i) nogil
+ void PyArray_MultiIter_NEXT(broadcast multi) nogil
object PyArray_IterNew(object arr)
- void PyArray_ITER_NEXT(flatiter it)
+ void PyArray_ITER_NEXT(flatiter it) nogil
void import_array()
diff --git a/numpy/random/tests/test_random.py b/numpy/random/tests/test_random.py
index db4093ab4..b6c4fe3af 100644
--- a/numpy/random/tests/test_random.py
+++ b/numpy/random/tests/test_random.py
@@ -624,5 +624,45 @@ class TestRandomDist(TestCase):
[ 3, 13]])
np.testing.assert_array_equal(actual, desired)
+
+class TestThread:
+ """ make sure each state produces the same sequence even in threads """
+ def setUp(self):
+ self.seeds = range(4)
+
+ def check_function(self, function, sz):
+ from threading import Thread
+
+ out1 = np.empty((len(self.seeds),) + sz)
+ out2 = np.empty((len(self.seeds),) + sz)
+
+ # threaded generation
+ t = [Thread(target=function, args=(np.random.RandomState(s), o))
+ for s, o in zip(self.seeds, out1)]
+ [x.start() for x in t]
+ [x.join() for x in t]
+
+ # the same serial
+ for s, o in zip(self.seeds, out2):
+ function(np.random.RandomState(s), o)
+
+ np.testing.assert_array_equal(out1, out2)
+
+ def test_normal(self):
+ def gen_random(state, out):
+ out[...] = state.normal(size=10000)
+ self.check_function(gen_random, sz=(10000,))
+
+ def test_exp(self):
+ def gen_random(state, out):
+ out[...] = state.exponential(scale=np.ones((100, 1000)))
+ self.check_function(gen_random, sz=(100, 1000))
+
+ def test_multinomial(self):
+ def gen_random(state, out):
+ out[...] = state.multinomial(10, [1/6.]*6, size=10000)
+ self.check_function(gen_random, sz=(10000,6))
+
+
if __name__ == "__main__":
run_module_suite()