Skip to content
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Extended the `memcpy`-based fast path of `shuffle` to multi-dimensional `ndarray` inputs whose first-axis items are contiguous, which is also much faster than the previous buffered path [gh-159](https://github.com/IntelPython/mkl_random/pull/159)

### Fixed
* Fixed an out-of-range integer `brng` indexing `brng_list` past its end, which returned uninitialized memory as random values; it now warns and falls back to `MT19937`
* Fixed `brng=0` being treated as unset, which left the state unseeded
* Fixed `uniform` to return a Python `float` for scalar bounds with `size=None` instead of a 0-d array [gh-167](https://github.com/IntelPython/mkl_random/pull/167)
* Fixed `randint` returning `high` for `int64`, `uint64` and the default `int` dtype when the range is at or above `INT_MAX` [gh-172](https://github.com/IntelPython/mkl_random/pull/172)
* Fixed the integer fills silently under-filling requests larger than two `MKL_INT_MAX` chunks [gh-172](https://github.com/IntelPython/mkl_random/pull/172)
Expand Down
15 changes: 12 additions & 3 deletions mkl_random/mklrand.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ cdef extern from "numpy_multiiter_workaround.h":

cdef extern from "randomkit.h":

int BRNG_KINDS

ctypedef struct irk_state:
pass

Expand Down Expand Up @@ -1575,7 +1577,12 @@ cdef irk_brng_t _parse_brng_token_(brng):
else:
brng_token = tmp
elif isinstance(brng, int):
brng_token = operator.index(brng)
# Out of range would index brng_list past its end in the seeding routines.
tmp = operator.index(brng)
if 0 <= tmp < BRNG_KINDS:
brng_token = tmp
else:
brng_token = _default_fallback_brng_token_(brng)
else:
brng_token = _default_fallback_brng_token_(brng)

Expand Down Expand Up @@ -1643,8 +1650,10 @@ cdef class _MKLRandomState:
cdef unsigned int stream_id
cdef cnp.ndarray obj "arrayObject_obj"
cdef bint use_array = False
# Not truthiness: 0 is falsy but is MT19937.
cdef bint brng_given = brng is not None

if (brng):
if brng_given:
# Parse before the lock to avoid warn
brng_token, stream_id = _parse_brng_argument(brng)

Expand All @@ -1670,7 +1679,7 @@ cdef class _MKLRandomState:
obj = obj.astype("uint32", casting="unsafe", order="C")

with self.lock:
if not brng:
if not brng_given:
# Reads state->stream, which a concurrent seed can free.
brng_token = <irk_brng_t> irk_get_brng_and_stream_mkl(
self.internal_state, &stream_id
Expand Down
18 changes: 18 additions & 0 deletions mkl_random/tests/test_random.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,24 @@ def test_non_deterministic_brng():
assert isinstance(v, int)


@pytest.mark.parametrize("brng", [11, 15, 99, -1, -100])
def test_out_of_range_integer_brng_falls_back(brng):
with pytest.warns(UserWarning, match="not recognized"):
rs = rnd.MKLRandomState(1, brng=brng)

expected = rnd.MKLRandomState(1, brng="MT19937").randint(0, 100, 8)
assert_equal(rs.randint(0, 100, 8), expected)


@pytest.mark.parametrize("brng_id,name", [(0, "MT19937"), (10, "ARS5")])
def test_boundary_integer_brng_accepted(brng_id, name):
with assert_no_warnings():
rs = rnd.MKLRandomState(1, brng=brng_id)

expected = rnd.MKLRandomState(1, brng=name).randint(0, 100, 8)
assert_equal(rs.randint(0, 100, 8), expected)


def test_binomial_n_zero():
zeros = np.zeros(2, dtype="int32")
for p in [0, 0.5, 1]:
Expand Down
Loading