Skip to content

Commit 0c87fb4

Browse files
committed
RLS: UPdate to numpy 1.13 release
Sync upstream changes to be compatible with 1.13 release
1 parent 580c7c8 commit 0c87fb4

File tree

3 files changed

+70
-26
lines changed

3 files changed

+70
-26
lines changed

randomstate/randomstate.pyx

+26-16
Original file line numberDiff line numberDiff line change
@@ -949,33 +949,42 @@ cdef class RandomState:
949949
key = np.dtype(dtype).name
950950
if not key in _randint_type:
951951
raise TypeError('Unsupported dtype "%s" for randint' % key)
952+
952953
lowbnd, highbnd = _randint_type[key]
953954

954-
if low < lowbnd:
955+
# TODO: Do not cast these inputs to Python int
956+
#
957+
# This is a workaround until gh-8851 is resolved (bug in NumPy
958+
# integer comparison and subtraction involving uint64 and non-
959+
# uint64). Afterwards, remove these two lines.
960+
ilow = int(low)
961+
ihigh = int(high)
962+
963+
if ilow < lowbnd:
955964
raise ValueError("low is out of bounds for %s" % (key,))
956-
if high > highbnd:
965+
if ihigh > highbnd:
957966
raise ValueError("high is out of bounds for %s" % (key,))
958-
if low >= high:
967+
if ilow >= ihigh:
959968
raise ValueError("low >= high")
960969

961970
if key == 'int32':
962-
ret = _rand_int32(low, high - 1, size, &self.rng_state, self.lock)
971+
ret = _rand_int32(ilow, ihigh - 1, size, &self.rng_state, self.lock)
963972
elif key == 'int64':
964-
ret = _rand_int64(low, high - 1, size, &self.rng_state, self.lock)
973+
ret = _rand_int64(ilow, ihigh - 1, size, &self.rng_state, self.lock)
965974
elif key == 'int16':
966-
ret = _rand_int16(low, high - 1, size, &self.rng_state, self.lock)
975+
ret = _rand_int16(ilow, ihigh - 1, size, &self.rng_state, self.lock)
967976
elif key == 'int8':
968-
ret = _rand_int8(low, high - 1, size, &self.rng_state, self.lock)
977+
ret = _rand_int8(ilow, ihigh - 1, size, &self.rng_state, self.lock)
969978
elif key == 'uint64':
970-
ret = _rand_uint64(low, high - 1, size, &self.rng_state, self.lock)
979+
ret = _rand_uint64(ilow, ihigh - 1, size, &self.rng_state, self.lock)
971980
elif key == 'uint32':
972-
ret = _rand_uint32(low, high - 1, size, &self.rng_state, self.lock)
981+
ret = _rand_uint32(ilow, ihigh - 1, size, &self.rng_state, self.lock)
973982
elif key == 'uint16':
974-
ret = _rand_uint16(low, high - 1, size, &self.rng_state, self.lock)
983+
ret = _rand_uint16(ilow, ihigh - 1, size, &self.rng_state, self.lock)
975984
elif key == 'uint8':
976-
ret = _rand_uint8(low, high - 1, size, &self.rng_state, self.lock)
985+
ret = _rand_uint8(ilow, ihigh - 1, size, &self.rng_state, self.lock)
977986
elif key == 'bool':
978-
ret = _rand_bool(low, high - 1, size, &self.rng_state, self.lock)
987+
ret = _rand_bool(ilow, ihigh - 1, size, &self.rng_state, self.lock)
979988

980989
if size is None:
981990
if dtype in (np.bool, np.int, np.long):
@@ -1021,7 +1030,7 @@ cdef class RandomState:
10211030
----------
10221031
a : 1-D array-like or int
10231032
If an ndarray, a random sample is generated from its elements.
1024-
If an int, the random sample is generated as if a was np.arange(n)
1033+
If an int, the random sample is generated as if a were np.arange(a)
10251034
size : int or tuple of ints, optional
10261035
Output shape. If the given shape is, e.g., ``(m, n, k)``, then
10271036
``m * n * k`` samples are drawn. Default is None, in which case a
@@ -1035,7 +1044,7 @@ cdef class RandomState:
10351044
10361045
Returns
10371046
-------
1038-
samples : 1-D ndarray, shape (size,)
1047+
samples : single item or ndarray
10391048
The generated random samples
10401049
10411050
Raises
@@ -4094,8 +4103,8 @@ cdef class RandomState:
40944103
Instead of specifying the full covariance matrix, popular
40954104
approximations include:
40964105
4097-
- Spherical covariance (*cov* is a multiple of the identity matrix)
4098-
- Diagonal covariance (*cov* has non-negative elements, and only on
4106+
- Spherical covariance (`cov` is a multiple of the identity matrix)
4107+
- Diagonal covariance (`cov` has non-negative elements, and only on
40994108
the diagonal)
41004109
41014110
This geometrical property can be seen in two dimensions by plotting
@@ -4507,6 +4516,7 @@ cdef class RandomState:
45074516
with self.lock:
45084517
for i in reversed(range(1, n)):
45094518
j = random_interval(&self.rng_state, i)
4519+
if i == j : continue # i == j is not needed and memcpy is undefined.
45104520
buf[...] = x[j]
45114521
x[j] = x[i]
45124522
x[i] = buf

randomstate/tests/test_numpy_mt19937.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -158,22 +158,42 @@ def test_rng_zero_and_extremes(self):
158158
for dt in self.itype:
159159
lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min
160160
ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1
161+
161162
tgt = ubnd - 1
162163
assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt)
164+
163165
tgt = lbnd
164166
assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt)
167+
165168
tgt = (lbnd + ubnd) // 2
166169
assert_equal(self.rfunc(tgt, tgt + 1, size=1000, dtype=dt), tgt)
167170

171+
def test_full_range(self):
172+
# Test for ticket #1690
173+
174+
for dt in self.itype:
175+
lbnd = 0 if dt is np.bool_ else np.iinfo(dt).min
176+
ubnd = 2 if dt is np.bool_ else np.iinfo(dt).max + 1
177+
178+
try:
179+
self.rfunc(lbnd, ubnd, dtype=dt)
180+
except Exception as e:
181+
raise AssertionError("No error should have been raised, "
182+
"but one was with the following "
183+
"message:\n\n%s" % str(e))
184+
168185
def test_in_bounds_fuzz(self):
169186
# Don't use fixed seed
170187
mt19937.seed()
188+
171189
for dt in self.itype[1:]:
172190
for ubnd in [4, 8, 16]:
173191
vals = self.rfunc(2, ubnd, size=2**16, dtype=dt)
174192
assert_(vals.max() < ubnd)
175193
assert_(vals.min() >= 2)
176-
vals = self.rfunc(0, 2, size=2**16, dtype=np.bool)
194+
195+
vals = self.rfunc(0, 2, size=2 ** 16, dtype=np.bool_)
196+
177197
assert_(vals.max() < 2)
178198
assert_(vals.min() >= 0)
179199

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

233+
def test_int64_uint64_corner_case(self):
234+
# When stored in Numpy arrays, `lbnd` is casted
235+
# as np.int64, and `ubnd` is casted as np.uint64.
236+
# Checking whether `lbnd` >= `ubnd` used to be
237+
# done solely via direct comparison, which is incorrect
238+
# because when Numpy tries to compare both numbers,
239+
# it casts both to np.float64 because there is
240+
# no integer superset of np.int64 and np.uint64. However,
241+
# `ubnd` is too large to be represented in np.float64,
242+
# causing it be round down to np.iinfo(np.int64).max,
243+
# leading to a ValueError because `lbnd` now equals
244+
# the new `ubnd`.
245+
246+
dt = np.int64
247+
tgt = np.iinfo(np.int64).max
248+
lbnd = np.int64(np.iinfo(np.int64).max)
249+
ubnd = np.uint64(np.iinfo(np.int64).max + 1)
250+
251+
# None of these function calls should
252+
# generate a ValueError now.
253+
actual = mt19937.randint(lbnd, ubnd, dtype=dt)
254+
assert_equal(actual, tgt)
255+
213256
def test_respect_dtype_singleton(self):
214257
# See gh-7203
215258
for dt in self.itype:

randomstate/tests/test_numpy_mt19937_regressions.py

-9
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,6 @@ def test_permutation_longs(self):
5555
b = mt19937.permutation(long(12))
5656
assert_array_equal(a, b)
5757

58-
def test_randint_range(self):
59-
# Test for ticket #1690
60-
lmax = np.iinfo('l').max
61-
lmin = np.iinfo('l').min
62-
try:
63-
mt19937.randint(lmin, lmax)
64-
except:
65-
raise AssertionError
66-
6758
def test_shuffle_mixed_dimension(self):
6859
# Test for trac ticket #2074
6960
for t in [[1, 2, 3, None],

0 commit comments

Comments
 (0)