Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TST: Add tests to cover discrete broadcasting #387

Merged
merged 4 commits into from
Oct 3, 2024
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 .github/workflows/cron-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ jobs:
fail-fast: false
matrix:
python: [cp312]
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
env:
BUILD_COMMIT: "main"
CIBW_BUILD: ${{ matrix.python }}-*
CIBW_ARCHS_LINUX: "x86_64"
CIBW_ARCHS_MACOS: "arm64"
CIBW_ARCHS_MACOS: "auto"
CIBW_SKIP: "pp* *-musllinux_* *-win32"
CIBW_TEST_REQUIRES: pytest pytest-xdist
CIBW_TEST_COMMAND: python -c "import randomgen; randomgen.test(['--skip-slow','-n','2'])"
Expand Down
2 changes: 2 additions & 0 deletions doc/source/change-log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Change Log

v2.1.0
======
- Fixed a bug in :class:`~randomgen.pcg64.LCG128Mix` that resultsed in ``inc``
not being correctly set when initialized without a user-provided ``inc``.
- Added the :class:`~randomgen.tyche.Tyche` PRNG of Neves and Araujo. Supports
two variants. One is the original implementation in the 2012 paper. The
second matches the version in ``OpenRand``.
Expand Down
2 changes: 1 addition & 1 deletion randomgen/_seed_sequence.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3

cimport numpy as np
from libc.stdint cimport uint32_t

Expand Down
2 changes: 1 addition & 1 deletion randomgen/aes.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3


cimport numpy as np
from libc.stdint cimport uint8_t, uint32_t, uint64_t
Expand Down
5 changes: 1 addition & 4 deletions randomgen/aes.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,7 @@ cdef class AESCounter(BitGenerator):
aesctr_use_aesni(bool(value))

def _seed_from_seq(self, counter=None):
try:
state = self.seed_seq.generate_state(2, np.uint64)
except AttributeError:
state = self._seed_seq.generate_state(2, np.uint64)
state = self._get_seed_seq().generate_state(2, np.uint64)
self.seed(key=state, counter=counter)
self._reset_state_variables()

Expand Down
8 changes: 4 additions & 4 deletions randomgen/bounded_integers.pyx.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!python
#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True
# cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True

import numpy as np

Expand Down Expand Up @@ -44,7 +44,7 @@ cdef object _rand_{{nptype}}_broadcast(np.ndarray low, np.ndarray high, object s
this type for checking and the recast to {{nptype}} when producing the
random integers.
"""
cdef {{utype}}_t rng, last_rng, off, val, mask, out_val, is_open
cdef {{utype}}_t rng, last_rng, off, mask, is_open
cdef uint32_t buf
cdef {{utype}}_t *out_data
cdef {{nptype_up}}_t low_v, high_v
Expand Down Expand Up @@ -131,7 +131,7 @@ cdef object _rand_{{nptype}}_broadcast(object low, object high, object size,
cdef uint64_t *out_data
cdef {{nptype}}_t *highm1_data
cdef {{nptype}}_t low_v, high_v
cdef uint64_t rng, last_rng, val, mask, off, out_val
cdef uint64_t rng, last_rng, mask, off

low_arr = <np.ndarray>low
high_arr = <np.ndarray>high
Expand Down Expand Up @@ -264,7 +264,7 @@ cdef object _rand_{{nptype}}(object low, object high, object size,
cdef np.ndarray out_arr, low_arr, high_arr
cdef {{utype}}_t rng, off, out_val
cdef {{utype}}_t *out_data
cdef np.npy_intp i, n, cnt
cdef np.npy_intp cnt

if size is not None:
if (np.prod(size) == 0):
Expand Down
13 changes: 8 additions & 5 deletions randomgen/broadcasting.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ cdef int check_array_constraint(np.ndarray val, object name, constraint_type con


cdef int check_constraint(double val, object name, constraint_type cons) except -1:
cdef bint is_nan
if cons == CONS_NON_NEGATIVE:
if not np.isnan(val) and np.signbit(val):
raise ValueError(name + " < 0")
Expand Down Expand Up @@ -81,7 +80,6 @@ cdef int check_constraint(double val, object name, constraint_type cons) except
cdef validate_output_shape(iter_shape, np.ndarray output):
cdef np.npy_intp *dims
cdef np.npy_intp ndim, i
cdef bint error
dims = np.PyArray_DIMS(output)
ndim = np.PyArray_NDIM(output)
output_shape = tuple((dims[i] for i in range(ndim)))
Expand Down Expand Up @@ -135,7 +133,7 @@ cdef object double_fill(void *func, bitgen_t *state, object size, object lock, o
cdef double out_val
cdef double *out_array_data
cdef np.ndarray out_array
cdef np.npy_intp i, n
cdef np.npy_intp n

if size is None and out is None:
with lock:
Expand Down Expand Up @@ -515,7 +513,7 @@ cdef object discrete_broadcast_di(void *func, void *state, object size, object l
for i in range(n):
a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0]
b_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 2))[0]
(<int64_t*>np.PyArray_MultiIter_DATA(it, 0))[0] = f(state, a_val, b_val)
randoms_data[i] = f(state, a_val, b_val)

np.PyArray_MultiIter_NEXT(it)

Expand Down Expand Up @@ -641,6 +639,11 @@ cdef object disc(void *func, void *state, object size, object lock,
return discrete_broadcast_di(func, state, size, lock,
a_arr, a_name, a_constraint,
b_arr, b_name, b_constraint)
elif narg_int64 == 3:
return discrete_broadcast_iii(func, state, size, lock,
a_arr, a_name, a_constraint,
b_arr, b_name, b_constraint,
c_arr, c_name, c_constraint)
else:
raise NotImplementedError("No vector path available")

Expand Down Expand Up @@ -773,7 +776,7 @@ cdef object cont_f(void *func, bitgen_t *state, object size, object lock,
object a, object a_name, constraint_type a_constraint,
object out):

cdef np.ndarray a_arr, b_arr, c_arr
cdef np.ndarray a_arr
cdef float _a
cdef bint is_scalar = True
cdef int requirements = api.NPY_ARRAY_ALIGNED | api.NPY_ARRAY_FORCECAST
Expand Down
2 changes: 1 addition & 1 deletion randomgen/chacha.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3


cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t
Expand Down
5 changes: 1 addition & 4 deletions randomgen/chacha.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,7 @@ cdef class ChaCha(BitGenerator):
PyArray_free_aligned(self.rng_state)

def _seed_from_seq(self, counter=None):
try:
state = self.seed_seq.generate_state(4, np.uint64)
except AttributeError:
state = self._seed_seq.generate_state(4, np.uint64)
state = self._get_seed_seq().generate_state(4, np.uint64)
self.seed(key=state, counter=counter)

@property
Expand Down
7 changes: 7 additions & 0 deletions randomgen/common.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ cdef class BitGenerator(_BitGenerator):
def _supported_modes(self):
return ("sequence",)

def _get_seed_seq(self):
try:
return self.seed_seq
except AttributeError:
# Older versions of numpy have _seed_seq
return self._seed_seq

def _seed_from_seq(self):
raise NotImplementedError("Subclass must override")

Expand Down
2 changes: 1 addition & 1 deletion randomgen/distributions.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#cython: language_level=3
# cython: language_level=3

from libc.stdint cimport (
int8_t,
Expand Down
2 changes: 1 addition & 1 deletion randomgen/dsfmt.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3

cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t

Expand Down
5 changes: 1 addition & 4 deletions randomgen/dsfmt.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,7 @@ cdef class DSFMT(BitGenerator):
self.rng_state.buffer_loc = DSFMT_N64

def _seed_from_seq(self):
try:
state = self.seed_seq.generate_state(2 * DSFMT_N64, np.uint32)
except AttributeError:
state = self._seed_seq.generate_state(2 * DSFMT_N64, np.uint32)
state = self._get_seed_seq().generate_state(2 * DSFMT_N64, np.uint32)

dsfmt_init_by_array(self.rng_state.state,
<uint32_t *>np.PyArray_DATA(state),
Expand Down
2 changes: 1 addition & 1 deletion randomgen/efiix64.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3


cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t
Expand Down
5 changes: 1 addition & 4 deletions randomgen/efiix64.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,7 @@ cdef class EFIIX64(BitGenerator):
def _seed_from_seq(self):
cdef uint64_t *state_arr

try:
state = self.seed_seq.generate_state(4, np.uint64)
except AttributeError:
state = self._seed_seq.generate_state(4, np.uint64)
state = self._get_seed_seq().generate_state(4, np.uint64)
state_arr = <np.uint64_t *>np.PyArray_DATA(state)
efiix64_seed(&self.rng_state, state_arr)
self._reset_state_variables()
Expand Down
2 changes: 1 addition & 1 deletion randomgen/entropy.pyx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!python
# cython: binding=True, language_level=3


cimport numpy as np
import numpy as np
Expand Down
2 changes: 1 addition & 1 deletion randomgen/examples/cython/extending.pyx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#cython: language_level=3
# cython: language_level=3
from cpython.pycapsule cimport PyCapsule_GetPointer, PyCapsule_IsValid
from libc.stdint cimport uint32_t

Expand Down
2 changes: 1 addition & 1 deletion randomgen/examples/cython/extending_distributions.pyx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#cython: language_level=3
# cython: language_level=3
import numpy as np

cimport cython
Expand Down
2 changes: 1 addition & 1 deletion randomgen/examples/cython/low_level.pyx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#cython: language_level=3, boundscheck=False, wraparound=False
# cython: language_level=3, boundscheck=False, wraparound=False
from cpython.pycapsule cimport PyCapsule_GetPointer, PyCapsule_IsValid
from libc.stdint cimport uint32_t

Expand Down
12 changes: 7 additions & 5 deletions randomgen/generator.pyx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!python
#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3, binding=True
# cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True
import warnings

from libc.math cimport sqrt
Expand Down Expand Up @@ -336,8 +336,8 @@ cdef class ExtendedGenerator:
0.47108547995356098 # random
>>> type(randomgen.generator.random())
<class 'float'>
>>> randomgen.generator.random((5,))
array([ 0.30220482, 0.86820401, 0.1654503 , 0.11659149, 0.54323428]) # random
>>> randomgen.generator.random((3,))
array([ 0.30220482, 0.86820401, 0.1654503]) # random

Three-by-two array of random numbers from [-5, 0):

Expand Down Expand Up @@ -628,7 +628,9 @@ cdef class ExtendedGenerator:
relation, np.NPY_COMPLEX128, api.NPY_ARRAY_ALIGNED
)

if np.PyArray_NDIM(ogamma) == np.PyArray_NDIM(orelation) == np.PyArray_NDIM(oloc) == 0:
if (np.PyArray_NDIM(ogamma) ==
np.PyArray_NDIM(orelation) ==
np.PyArray_NDIM(oloc) == 0):
floc_r = PyComplex_RealAsDouble(loc)
floc_i = PyComplex_ImagAsDouble(loc)
fgamma_r = PyComplex_RealAsDouble(gamma)
Expand Down Expand Up @@ -727,7 +729,7 @@ cdef class ExtendedGenerator:
self, int64_t df, np.npy_intp dim, np.npy_intp num, object n
):
double_fill(&random_standard_normal_fill, &self._bitgen, None, self.lock, n)
return np.matmul(np.transpose(n,(0, 2, 1)), n)
return np.matmul(np.transpose(n, (0, 2, 1)), n)

def standard_wishart(self, int64_t df, np.npy_intp dim, size=None, rescale=True):
"""
Expand Down
2 changes: 1 addition & 1 deletion randomgen/hc128.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3

# coding=utf-8
cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t
Expand Down
5 changes: 1 addition & 4 deletions randomgen/hc128.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,7 @@ cdef class HC128(BitGenerator):
self._bitgen.next_raw = &hc128_uint64

def _seed_from_seq(self):
try:
state = self.seed_seq.generate_state(4, np.uint64)
except AttributeError:
state = self._seed_seq.generate_state(4, np.uint64)
state = self._get_seed_seq().generate_state(4, np.uint64)
self.seed(key=state)

def seed(self, seed=None, key=None):
Expand Down
2 changes: 1 addition & 1 deletion randomgen/jsf.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3


cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t
Expand Down
5 changes: 1 addition & 4 deletions randomgen/jsf.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,7 @@ cdef class JSF(BitGenerator):

def _seed_from_seq(self):
dtype = np.uint64 if self.size == 64 else np.uint32
try:
state = self.seed_seq.generate_state(self.seed_size, dtype)
except AttributeError:
state = self._seed_seq.generate_state(self.seed_size, dtype)
state = self._get_seed_seq().generate_state(self.seed_size, dtype)
if self.size == 64:
jsf64_seed(&self.rng_state,
<uint64_t*>np.PyArray_DATA(state),
Expand Down
2 changes: 1 addition & 1 deletion randomgen/legacy/bounded_integers.pyx.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!python
#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True
# cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True

import numpy as np

Expand Down
2 changes: 1 addition & 1 deletion randomgen/legacy/distributions.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#cython: language_level=3
# cython: language_level=3

from libc.stdint cimport (
int8_t,
Expand Down
2 changes: 1 addition & 1 deletion randomgen/lxm.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3


cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t
Expand Down
7 changes: 1 addition & 6 deletions randomgen/lxm.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,10 @@ cdef class LXM(BitGenerator):
def _seed_from_seq(self):
cdef int i
cdef uint64_t bits = 0
cdef uint64_t *state_arr

# Protect against negligible prob of all 0 in Xorshift
while bits == 0:
try:
state = self.seed_seq.generate_state(5, np.uint64)
except:
state = self._seed_seq.generate_state(5, np.uint64)
state_arr = <np.uint64_t *>np.PyArray_DATA(state)
state = self._get_seed_seq().generate_state(5, np.uint64)
for i in range(4):
self.rng_state.x[i] = state[i]
bits |= <uint64_t>state[i]
Expand Down
13 changes: 2 additions & 11 deletions randomgen/mt19937.pyx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#!python
#cython: binding=True
# coding=utf-8

import operator

import numpy as np

from randomgen._deprecated_value import _DeprecatedValue
Expand Down Expand Up @@ -133,20 +130,14 @@ cdef class MT19937(BitGenerator):
return "sequence", "numpy"

def _seed_from_seq(self):
try:
state = self.seed_seq.generate_state(RK_STATE_LEN, np.uint32)
except AttributeError:
state = self._seed_seq.generate_state(RK_STATE_LEN, np.uint32)
state = self._get_seed_seq().generate_state(RK_STATE_LEN, np.uint32)
mt19937_init_by_array(&self.rng_state,
<uint32_t*>np.PyArray_DATA(state),
RK_STATE_LEN)

def _seed_from_seq_numpy_compat(self, inc=None):
# MSB is 1; assuring non-zero initial array
try:
val = self.seed_seq.generate_state(RK_STATE_LEN, np.uint32)
except AttributeError:
val = self._seed_seq.generate_state(RK_STATE_LEN, np.uint32)
val = self._get_seed_seq().generate_state(RK_STATE_LEN, np.uint32)
# MSB is 1; assuring non-zero initial array
self.rng_state.key[0] = 0x80000000UL
for i in range(1, RK_STATE_LEN):
Expand Down
2 changes: 1 addition & 1 deletion randomgen/mt64.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cython: binding=True, language_level=3


cimport numpy as np
from libc.stdint cimport uint32_t, uint64_t
Expand Down
Loading
Loading