summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2013-02-15 22:11:48 +0100
committerSebastian Berg <sebastian@sipsolutions.net>2013-03-04 14:12:34 +0100
commita530098e816e1164efdb356ac2280ba25bfb1c7f (patch)
tree95ec811ef8a50dd9d91a9567297451e2e4d2aa67 /numpy
parent4bf5a3feb00fe1d63e7d8fcf852cbf34e22fd60b (diff)
downloadnumpy-a530098e816e1164efdb356ac2280ba25bfb1c7f.tar.gz
BUG: fix random.choice scalar object result and disallow 0-d arrays
Object arrays failed due to bad check for finding out if the result should be a scalar type and not an array when size=None. Also in this case the creation of the new array was wrong. This should be fixed with this. The second fix is to forbid 0-d arrays. Allowing 0-d arrays does not make much sense. But it is dangerous because for example floats will be interpreted as 1-d arrays, while one may expect that they are interpreted as integers. This also saves the trouble of reliably detecting all integers...
Diffstat (limited to 'numpy')
-rw-r--r--numpy/random/mtrand/mtrand.pyx50
-rw-r--r--numpy/random/tests/test_random.py13
2 files changed, 45 insertions, 18 deletions
diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx
index f115dccdd..2d4d904bd 100644
--- a/numpy/random/mtrand/mtrand.pyx
+++ b/numpy/random/mtrand/mtrand.pyx
@@ -124,6 +124,7 @@ cdef extern from "initarray.h":
import_array()
import numpy as np
+import operator
cdef object cont0_array(rk_state *state, rk_cont0 func, object size):
cdef double *array_data
@@ -994,21 +995,24 @@ cdef class RandomState:
"""
# Format and Verify input
- if isinstance(a, int):
- if a > 0:
- pop_size = a #population size
- else:
+ a = np.array(a, copy=False)
+ if a.ndim == 0:
+ try:
+ # __index__ must return an integer by python rules.
+ pop_size = operator.index(a.item())
+ except TypeError:
+ raise ValueError("a must be 1-dimensional or an integer")
+ if pop_size <= 0:
raise ValueError("a must be greater than 0")
+ elif a.ndim != 1:
+ raise ValueError("a must be 1-dimensional")
else:
- a = np.array(a, ndmin=1, copy=0)
- if a.ndim != 1:
- raise ValueError("a must be 1-dimensional")
- pop_size = a.size
+ pop_size = a.shape[0]
if pop_size is 0:
raise ValueError("a must be non-empty")
if None != p:
- p = np.array(p, dtype=np.double, ndmin=1, copy=0)
+ p = np.array(p, dtype=np.double, ndmin=1, copy=False)
if p.ndim != 1:
raise ValueError("p must be 1-dimensional")
if p.size != pop_size:
@@ -1019,7 +1023,10 @@ cdef class RandomState:
raise ValueError("probabilities do not sum to 1")
shape = size
- size = 1 if shape is None else np.prod(shape, dtype=np.intp)
+ if shape is not None:
+ size = np.prod(shape, dtype=np.intp)
+ else:
+ size = 1
# Actual sampling
if replace:
@@ -1060,18 +1067,27 @@ cdef class RandomState:
idx = self.permutation(pop_size)[:size]
if shape is not None:
idx.shape = shape
+
if shape is None and isinstance(idx, np.ndarray):
# In most cases a scalar will have been made an array
idx = idx.item(0)
+
#Use samples as indices for a if a is array-like
- if isinstance(a, int):
+ if a.ndim == 0:
return idx
- res = a[idx]
- # Note when introducing an axis argument a copy should be ensured.
- if res.ndim == 0 and shape is not None:
- # the result here is not a scalar but an array.
- return np.array(res)
- return res
+
+ if shape is not None and idx.ndim == 0:
+ # If size == () then the user requested a 0-d array as opposed to
+ # a scalar object when size is None. However a[idx] is always a
+ # scalar and not an array. So this makes sure the result is an
+ # array, taking into account that np.array(item) may not work
+ # for object arrays.
+ res = np.empty((), dtype=a.dtype)
+ res[()] = a[idx]
+ return res
+
+ return a[idx]
+
def uniform(self, low=0.0, high=1.0, size=None):
"""
diff --git a/numpy/random/tests/test_random.py b/numpy/random/tests/test_random.py
index e8875e578..1621637d0 100644
--- a/numpy/random/tests/test_random.py
+++ b/numpy/random/tests/test_random.py
@@ -149,7 +149,8 @@ class TestRandomDist(TestCase):
def test_choice_exceptions(self):
sample = np.random.choice
- assert_raises(ValueError, sample, -1,3)
+ assert_raises(ValueError, sample, -1, 3)
+ assert_raises(ValueError, sample, 3., 3)
assert_raises(ValueError, sample, [[1,2],[3,4]], 3)
assert_raises(ValueError, sample, [], 3)
assert_raises(ValueError, sample, [1,2,3,4], 3,
@@ -169,6 +170,11 @@ class TestRandomDist(TestCase):
assert_(np.isscalar(np.random.choice(2, replace=True, p=p)))
assert_(np.isscalar(np.random.choice(2, replace=False, p=p)))
assert_(np.isscalar(np.random.choice([1,2], replace=True)))
+ assert_(np.random.choice([None], replace=True) is None)
+ a = np.array([1, 2])
+ arr = np.empty(1, dtype=object)
+ arr[0] = a
+ assert_(np.random.choice(arr, replace=True) is a)
# Check 0-d array
s = tuple()
@@ -177,6 +183,11 @@ class TestRandomDist(TestCase):
assert_(not np.isscalar(np.random.choice(2, s, replace=True, p=p)))
assert_(not np.isscalar(np.random.choice(2, s, replace=False, p=p)))
assert_(not np.isscalar(np.random.choice([1,2], s, replace=True)))
+ assert_(np.random.choice([None], s, replace=True).ndim == 0)
+ a = np.array([1, 2])
+ arr = np.empty(1, dtype=object)
+ arr[0] = a
+ assert_(np.random.choice(arr, s, replace=True).item() is a)
# Check multi dimensional array
s = (2,3)