Skip to content

Commit

Permalink
RLS: Update to numpy 1.13 release
Browse files Browse the repository at this point in the history
Sync upstream changes to be compatible with 1.13 release
  • Loading branch information
bashtage committed May 22, 2017
1 parent 580c7c8 commit 3398079
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 27 deletions.
42 changes: 26 additions & 16 deletions randomstate/randomstate.pyx
Expand Up @@ -949,33 +949,42 @@ cdef class RandomState:
key = np.dtype(dtype).name
if not key in _randint_type:
raise TypeError('Unsupported dtype "%s" for randint' % key)

lowbnd, highbnd = _randint_type[key]

if low < lowbnd:
# TODO: Do not cast these inputs to Python int
#
# This is a workaround until gh-8851 is resolved (bug in NumPy
# integer comparison and subtraction involving uint64 and non-
# uint64). Afterwards, remove these two lines.
ilow = int(low)
ihigh = int(high)

if ilow < lowbnd:
raise ValueError("low is out of bounds for %s" % (key,))
if high > highbnd:
if ihigh > highbnd:
raise ValueError("high is out of bounds for %s" % (key,))
if low >= high:
if ilow >= ihigh:
raise ValueError("low >= high")

if key == 'int32':
ret = _rand_int32(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_int32(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'int64':
ret = _rand_int64(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_int64(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'int16':
ret = _rand_int16(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_int16(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'int8':
ret = _rand_int8(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_int8(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'uint64':
ret = _rand_uint64(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_uint64(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'uint32':
ret = _rand_uint32(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_uint32(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'uint16':
ret = _rand_uint16(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_uint16(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'uint8':
ret = _rand_uint8(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_uint8(ilow, ihigh - 1, size, &self.rng_state, self.lock)
elif key == 'bool':
ret = _rand_bool(low, high - 1, size, &self.rng_state, self.lock)
ret = _rand_bool(ilow, ihigh - 1, size, &self.rng_state, self.lock)

if size is None:
if dtype in (np.bool, np.int, np.long):
Expand Down Expand Up @@ -1021,7 +1030,7 @@ cdef class RandomState:
----------
a : 1-D array-like or int
If an ndarray, a random sample is generated from its elements.
If an int, the random sample is generated as if a was np.arange(n)
If an int, the random sample is generated as if a were np.arange(a)
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
Expand All @@ -1035,7 +1044,7 @@ cdef class RandomState:

Returns
-------
samples : 1-D ndarray, shape (size,)
samples : single item or ndarray
The generated random samples

Raises
Expand Down Expand Up @@ -4094,8 +4103,8 @@ cdef class RandomState:
Instead of specifying the full covariance matrix, popular
approximations include:

- Spherical covariance (*cov* is a multiple of the identity matrix)
- Diagonal covariance (*cov* has non-negative elements, and only on
- Spherical covariance (`cov` is a multiple of the identity matrix)
- Diagonal covariance (`cov` has non-negative elements, and only on
the diagonal)

This geometrical property can be seen in two dimensions by plotting
Expand Down Expand Up @@ -4507,6 +4516,7 @@ cdef class RandomState:
with self.lock:
for i in reversed(range(1, n)):
j = random_interval(&self.rng_state, i)
if i == j : continue # i == j is not needed and memcpy is undefined.
buf[...] = x[j]
x[j] = x[i]
x[i] = buf
Expand Down
45 changes: 44 additions & 1 deletion randomstate/tests/test_numpy_mt19937.py
Expand Up @@ -158,22 +158,42 @@ def test_rng_zero_and_extremes(self):
for dt in self.itype:
lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min
ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1

tgt = ubnd - 1
assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt)

tgt = lbnd
assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt)

tgt = (lbnd + ubnd) // 2
assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt)

def test_full_range(self):
# Test for ticket #1690

for dt in self.itype:
lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min
ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1

try:
self.rfunc(lbnd, ubnd, dtype=dt)
except Exception as e:
raise AssertionError("No error should have been raised, "
"but one was with the following "
"message:\n\n%s" % str(e))

def test_in_bounds_fuzz(self):
# Don't use fixed seed
mt19937.seed()

for dt in self.itype[1:]:
for ubnd in [4, 8, 16]:
vals = self.rfunc(2, ubnd, size=2**16, dtype=dt)
assert_(vals.max() < ubnd)
assert_(vals.min() >= 2)
vals = self.rfunc(0, 2, size=2**16, dtype=np.bool)

vals = self.rfunc(0, 2, size=2 ** 16, dtype=np.bool_)

assert_(vals.max() < 2)
assert_(vals.min() >= 0)

Expand Down Expand Up @@ -210,6 +230,29 @@ def test_repeatability(self):
res = hashlib.md5(val).hexdigest()
assert_(tgt[np.dtype(np.bool).name] == res)

def test_int64_uint64_corner_case(self):
# When stored in Numpy arrays, `lbnd` is casted
# as np.int64, and `ubnd` is casted as np.uint64.
# Checking whether `lbnd` >= `ubnd` used to be
# done solely via direct comparison, which is incorrect
# because when Numpy tries to compare both numbers,
# it casts both to np.float64 because there is
# no integer superset of np.int64 and np.uint64. However,
# `ubnd` is too large to be represented in np.float64,
# causing it be round down to np.iinfo(np.int64).max,
# leading to a ValueError because `lbnd` now equals
# the new `ubnd`.

dt = np.int64
tgt = np.iinfo(np.int64).max
lbnd = np.int64(np.iinfo(np.int64).max)
ubnd = np.uint64(np.iinfo(np.int64).max + 1)

# None of these function calls should
# generate a ValueError now.
actual = mt19937.randint(lbnd, ubnd, dtype=dt)
assert_equal(actual, tgt)

def test_respect_dtype_singleton(self):
# See gh-7203
for dt in self.itype:
Expand Down
9 changes: 0 additions & 9 deletions randomstate/tests/test_numpy_mt19937_regressions.py
Expand Up @@ -55,15 +55,6 @@ def test_permutation_longs(self):
b = mt19937.permutation(long(12))
assert_array_equal(a, b)

def test_randint_range(self):
# Test for ticket #1690
lmax = np.iinfo('l').max
lmin = np.iinfo('l').min
try:
mt19937.randint(lmin, lmax)
except:
raise AssertionError

def test_shuffle_mixed_dimension(self):
# Test for trac ticket #2074
for t in [[1, 2, 3, None],
Expand Down
6 changes: 5 additions & 1 deletion setup.py
Expand Up @@ -173,7 +173,11 @@ def is_pure(self):


try:
subprocess.call(['pandoc', '--from=markdown', '--to=rst', '--output=README.rst', 'README.md'])
import os
readme_orig_time = os.path.getmtime('README.md')
readme_mod_time = os.path.getmtime('README.rst')
if readme_orig_time > readme_mod_time:
subprocess.call(['pandoc', '--from=markdown', '--to=rst', '--output=README.rst', 'README.md'])
except:
pass
# Generate files and extensions
Expand Down

0 comments on commit 3398079

Please sign in to comment.