[SciPy-Dev] Generate random variates using Cython
Andrew Nelson
andyfaff at gmail.com
Wed Jan 22 16:09:09 EST 2020
>
> After upgrading to Numpy 1.18, I could indeed compile the code
> https://docs.scipy.org/doc/numpy-1.17.0/reference/random/extending.html
> and it gives a substantial speedup.
> I am still wondering how to integrate such an approach into SciPy. To
> generate uniform samples in the _rvs method of a continuous distribution i
> scipy.stats, I would write:
>
> self._random_state.random_sample
>
`np.random.Generator` doesn't have a `random_sample` method. But it does
have a `uniform` method. So if `_random_state` is either a `RandomState` or
a `Generator` instance you should use the `uniform` method for it to work
across both.
If I want to use Cython, how can I ensure that it relies on the same random
> state?
>
`Generator` and `RandomState` will produce different streams of random
numbers from the same seed. In the PR linked to issue #11402 I'm trying to
ensure that the `rvs` methods will work with both `Generator` and
`RandomState`. The latter is current default, and one would want to use
that to retain back compatibility of random numbers. If you're trying to
use Cython to speedup a particular rvs method you'll need to have two
branches. One branch is given a RandomState instance, the other a Generator
instance.
import numpy as np
> cimport numpy as np
> cimport cython
> from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer
> from numpy.random cimport bitgen_t
> from numpy.random import PCG64
>
> @cython.boundscheck(False)
> @cython.wraparound(False)
> def rvs(Py_ssize_t n):
> cdef Py_ssize_t i
> cdef bitgen_t *rng
> cdef const char *capsule_name = "BitGenerator"
> cdef double u, v
> cdef double[::1] random_values
> x = PCG64()
> capsule = x.capsule
> # Optional check that the capsule if from a BitGenerator
> if not PyCapsule_IsValid(capsule, capsule_name):
> raise ValueError("Invalid pointer to anon_func_state")
> # Cast the pointer
> rng = <bitgen_t *> PyCapsule_GetPointer(capsule, capsule_name)
> random_values = np.empty(n, dtype='float64')
> with x.lock, nogil:
> for i in range(n):
> while (1):
> u = rng.next_double(rng.state)
> v = rng.next_double(rng.state)
> if u <= v*v:
> break
> random_values[i] = v
> randoms = np.asarray(random_values)
> return randoms
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/scipy-dev/attachments/20200123/049dc42a/attachment.html>
More information about the SciPy-Dev
mailing list