Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions randomgen/bounded_integers.pyx.in
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ cdef object _rand_{{nptype}}(object low, object high, object size,
high_arr = <np.ndarray>np.array(high, copy=False)
low_ndim = np.PyArray_NDIM(low_arr)
high_ndim = np.PyArray_NDIM(high_arr)
if ((low_ndim == 0 or (low_ndim==1 and low_arr.size==1 and size is not None)) and
(high_ndim == 0 or (high_ndim==1 and high_arr.size==1 and size is not None))):
if ((low_ndim == 0 or (low_ndim == 1 and low_arr.size == 1 and size is not None))
and (high_ndim == 0 or (high_ndim == 1 and high_arr.size == 1 and size is not None))):
low = int(low_arr)
high = int(high_arr)
# Subtract 1 since internal generator produces on closed interval [low, high]
Expand Down
2 changes: 2 additions & 0 deletions randomgen/common.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ cdef enum ConstraintType:

ctypedef ConstraintType constraint_type

cdef object benchmark(brng_t *brng, object lock, Py_ssize_t cnt, object method)
cdef object random_raw(brng_t *brng, object lock, object size, object output)
cdef int check_constraint(double val, object name, constraint_type cons) except -1
cdef int check_array_constraint(np.ndarray val, object name, constraint_type cons) except -1

Expand Down
73 changes: 73 additions & 0 deletions randomgen/common.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,79 @@ interface = namedtuple('interface', ['state_address', 'state', 'next_uint64',
'next_uint32', 'next_double', 'brng'])


cdef object benchmark(brng_t *brng, object lock, Py_ssize_t cnt, object method):
"""Benchmark command used by BasicRNG"""
cdef Py_ssize_t i
if method==u'uint64':
with lock, nogil:
for i in range(cnt):
brng.next_uint64(brng.state)
elif method==u'double':
with lock, nogil:
for i in range(cnt):
brng.next_double(brng.state)
else:
raise ValueError('Unknown method')


cdef object random_raw(brng_t *brng, object lock, object size, object output):
"""
random_raw(self, size=None)

Return randoms as generated by the underlying PRNG

Parameters
----------
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
output : bool, optional
Output values. Used for performance testing since the generated
values are not returned.

Returns
-------
out : uint or ndarray
Drawn samples.

Notes
-----
This method directly exposes the the raw underlying pseudo-random
number generator. All values are returned as unsigned 64-bit
values irrespective of the number of bits produced by the PRNG.

See the class docstring for the number of bits returned.
"""
cdef np.ndarray randoms
cdef uint64_t *randoms_data
cdef Py_ssize_t i, n

if not output:
if size is None:
with lock:
brng.next_raw(brng.state)
return None
n = np.asarray(size).sum()
with lock, nogil:
for i in range(n):
brng.next_raw(brng.state)
return None

if size is None:
with lock:
return brng.next_raw(brng.state)

randoms = <np.ndarray>np.empty(size, np.uint64)
randoms_data = <uint64_t*>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)

with lock, nogil:
for i in range(n):
randoms_data[i] = brng.next_raw(brng.state)
return randoms


cdef double kahan_sum(double *darr, np.npy_intp n):
cdef double c, y, t, sum
cdef np.npy_intp i
Expand Down
48 changes: 39 additions & 9 deletions randomgen/dsfmt.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import operator
from libc.stdlib cimport malloc, free
from cpython.pycapsule cimport PyCapsule_New

try:
from threading import Lock
except ImportError:
from dummy_threading import Lock

import numpy as np
cimport numpy as np

Expand Down Expand Up @@ -144,6 +149,7 @@ cdef class DSFMT:
cdef public object _cffi
cdef public object _ctypes
cdef public object _generator
cdef public object lock

def __init__(self, seed=None):
self.rng_state = <dsfmt_state *>malloc(sizeof(dsfmt_state))
Expand All @@ -152,6 +158,8 @@ cdef class DSFMT:
self.rng_state.buffer_loc = DSFMT_N64
self._brng = <brng_t *>malloc(sizeof(brng_t))
self.seed(seed)
self.lock = Lock()

self._brng.state = <void *>self.rng_state
self._brng.next_uint64 = &dsfmt_uint64
self._brng.next_uint32 = &dsfmt_uint32
Expand Down Expand Up @@ -185,17 +193,39 @@ cdef class DSFMT:
cdef _reset_state_variables(self):
self.rng_state.buffer_loc = DSFMT_N64

def random_raw(self, size=None, output=True):
"""
random_raw(self, size=None)

Return randoms as generated by the underlying BasicRNG

Parameters
----------
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
output : bool, optional
Output values. Used for performance testing since the generated
values are not returned.

Returns
-------
out : uint or ndarray
Drawn samples.

Notes
-----
This method directly exposes the the raw underlying pseudo-random
number generator. All values are returned as unsigned 64-bit
values irrespective of the number of bits produced by the PRNG.

See the class docstring for the number of bits returned.
"""
return random_raw(self._brng, self.lock, size, output)

def _benchmark(self, Py_ssize_t cnt, method=u'uint64'):
cdef Py_ssize_t i
if method==u'uint64':
for i in range(cnt):
self._brng.next_uint64(self._brng.state)
elif method==u'double':
for i in range(cnt):
self._brng.next_double(self._brng.state)
else:
raise ValueError('Unknown method')
return benchmark(self._brng, self.lock, cnt, method)

def seed(self, seed=None):
"""
Expand Down
65 changes: 1 addition & 64 deletions randomgen/generator.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ cimport numpy as np
import numpy as np
cimport cython

try:
from threading import Lock
except ImportError:
from dummy_threading import Lock

from randomgen.bounded_integers cimport *
from randomgen.bounded_integers import _randint_types
from randomgen.common cimport *
Expand Down Expand Up @@ -98,7 +93,7 @@ cdef class RandomGenerator:
raise ValueError("Invalid brng. The brng must be instantized.")
self._brng = <brng_t *> PyCapsule_GetPointer(capsule, name)
self._binomial = <binomial_t *>malloc(sizeof(binomial_t))
self.lock = Lock()
self.lock = brng.lock

def __dealloc__(self):
free(self._binomial)
Expand Down Expand Up @@ -238,63 +233,6 @@ cdef class RandomGenerator:

return array

def random_raw(self, size=None, output=True):
"""
random_raw(self, size=None)

Return randoms as generated by the underlying PRNG

Parameters
----------
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
output : bool, optional
Output values. Used for performance testing since the generated
values are not returned.

Returns
-------
out : uint or ndarray
Drawn samples.

Notes
-----
This method directly exposes the the raw underlying pseudo-random
number generator. All values are returned as unsigned 64-bit
values irrespective of the number of bits produced by the PRNG.

See the class docstring for the number of bits returned.
"""
cdef np.ndarray randoms
cdef uint64_t *randoms_data
cdef Py_ssize_t i, n

if not output:
if size is None:
with self.lock:
self._brng.next_raw(self._brng.state)
return None
n = np.asarray(size).sum()
with self.lock, nogil:
for i in range(n):
self._brng.next_raw(self._brng.state)
return None

if size is None:
with self.lock:
return self._brng.next_raw(self._brng.state)

randoms = <np.ndarray>np.empty(size, np.uint64)
randoms_data = <uint64_t*>np.PyArray_DATA(randoms)
n = np.PyArray_SIZE(randoms)

with self.lock, nogil:
for i in range(n):
randoms_data[i] = self._brng.next_raw(self._brng.state)
return randoms

def random_sample(self, size=None, dtype=np.float64, out=None):
"""
random_sample(size=None, dtype='d', out=None)
Expand Down Expand Up @@ -4414,7 +4352,6 @@ rand = _random_generator.rand
randint = _random_generator.randint
randn = _random_generator.randn
random_integers = _random_generator.random_integers
random_raw = _random_generator.random_raw
random_sample = _random_generator.random_sample
random_uintegers = _random_generator.random_uintegers
rayleigh = _random_generator.rayleigh
Expand Down
7 changes: 1 addition & 6 deletions randomgen/legacy/_legacy.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ cimport numpy as np
import numpy as np
cimport cython

try:
from threading import Lock
except ImportError:
from dummy_threading import Lock

from randomgen.bounded_integers cimport *
from randomgen.bounded_integers import _randint_types
from randomgen.common cimport cont, disc, double_fill, CONS_NONE, \
Expand Down Expand Up @@ -104,7 +99,7 @@ cdef class _LegacyGenerator:
self._aug_state = <aug_brng_t *>malloc(sizeof(aug_brng_t))
self._aug_state.basicrng = self._brng
self._reset_gauss()
self.lock = Lock()
self.lock = brng.lock

def __dealloc__(self):
free(self._aug_state)
Expand Down
41 changes: 32 additions & 9 deletions randomgen/mt19937.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,39 @@ cdef class MT19937:
(self.state['brng'],),
self.state)

def random_raw(self, size=None, output=True):
"""
random_raw(self, size=None)

Return randoms as generated by the underlying BasicRNG

Parameters
----------
size : int or tuple of ints, optional
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
``m * n * k`` samples are drawn. Default is None, in which case a
single value is returned.
output : bool, optional
Output values. Used for performance testing since the generated
values are not returned.

Returns
-------
out : uint or ndarray
Drawn samples.

Notes
-----
This method directly exposes the the raw underlying pseudo-random
number generator. All values are returned as unsigned 64-bit
values irrespective of the number of bits produced by the PRNG.

See the class docstring for the number of bits returned.
"""
return random_raw(self._brng, self.lock, size, output)

def _benchmark(self, Py_ssize_t cnt, method=u'uint64'):
cdef Py_ssize_t i
if method==u'uint64':
for i in range(cnt):
self._brng.next_uint64(self._brng.state)
elif method==u'double':
for i in range(cnt):
self._brng.next_double(self._brng.state)
else:
raise ValueError('Unknown method')
return benchmark(self._brng, self.lock, cnt, method)

def seed(self, seed=None):
"""
Expand Down
Loading