Repository: numpy/numpy

Issue:
Wrong output in take function
I encountered an error when i use the numpy.take function. 
test : 2D array (20000x128) with double values
P: integer vector 128 values in the range of [0...127] none are the same.
if i execute the following code everything works fine and as intended, no error.
`np.take(test, P, axis=1, mode='raise', out=test)`

if i execute
` np.take(test, P, axis=1, mode='wrap', out=test) ` 
 my output should be the same as in the other code, since i do not have any out-of-bounds indices. However, the output is different. Values are scrambled and appear multiple times although they are all different.  

if executed as `test =  np.take(test, P, axis=1, mode='wrap') ` the output is correct. 

same for: mode = 'clip'

numpy version 1.12.1
python version 2.7.13



Discussion:
You are working on the array in place in those two modes, while the raise mode works on a copy (I guess as a trick to be consistent on error, even though there are other corner cases where we can't guarantee this too).

I think this issue is open elsewhere, don't know what the discussion result was there. If you don't want it to be in-place (which will cause this), you need to work on a copy anyway, so using the `out` keyword has no real use in any case if out is the same as the input (or has overlap with it).

I suppose we could add an overlap guard here, or so, since we started doing that for ufuncs, and a bit other things now.

Resolving patch:
diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py
--- a/numpy/core/fromnumeric.py
+++ b/numpy/core/fromnumeric.py
@@ -130,7 +130,8 @@ def take(a, indices, axis=None, out=None, mode='raise'):
         input array is used.
     out : ndarray, optional (Ni..., Nj..., Nk...)
         If provided, the result will be placed in this array. It should
-        be of the appropriate shape and dtype.
+        be of the appropriate shape and dtype. Note that `out` is always
+        buffered if `mode='raise'`; use other modes for better performance.
     mode : {'raise', 'wrap', 'clip'}, optional
         Specifies how out-of-bounds indices will behave.
 
@@ -355,7 +356,8 @@ def choose(a, choices, out=None, mode='raise'):
         ``choices.shape[0]``) is taken as defining the "sequence".
     out : array, optional
         If provided, the result will be inserted into this array. It should
-        be of the appropriate shape and dtype.
+        be of the appropriate shape and dtype. Note that `out` is always
+        buffered if `mode='raise'`; use other modes for better performance.
     mode : {'raise' (default), 'wrap', 'clip'}, optional
         Specifies how indices outside `[0, n-1]` will be treated:
 
@@ -512,7 +514,8 @@ def put(a, ind, v, mode='raise'):
 
         'clip' mode means that all indices that are too large are replaced
         by the index that addresses the last element along that axis. Note
-        that this disables indexing with negative numbers.
+        that this disables indexing with negative numbers. In 'raise' mode,
+        if an exception occurs the target array may still be modified.
 
     See Also
     --------


Test patch:
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -1491,6 +1491,11 @@ def test_choose(self):
         # gh-12031, caused SEGFAULT
         assert_raises(TypeError, oned.choose,np.void(0), [oned])
 
+        # gh-6272 check overlap on out
+        x = np.arange(5)
+        y = np.choose([0,0,0], [x[:3], x[:3], x[:3]], out=x[1:4], mode='wrap')
+        assert_equal(y, np.array([0, 1, 2]))
+
     def test_prod(self):
         ba = [1, 2, 10, 11, 6, 5, 4]
         ba2 = [[1, 2, 3, 4], [5, 6, 7, 9], [10, 3, 4, 5]]
@@ -4377,6 +4382,16 @@ def test_record_array(self):
         assert_array_equal(rec['y'], [11, 4])
         assert_array_equal(rec['z'], [3, 3])
 
+    def test_overlaps(self):
+        # gh-6272 check overlap
+        x = np.array([True, False, True, False])
+        np.putmask(x[1:4], [True, True, True], x[:3])
+        assert_equal(x, np.array([True, True, False, True]))
+
+        x = np.array([True, False, True, False])
+        np.putmask(x[1:4], x[:3], [True, False, True])
+        assert_equal(x, np.array([True, True, True, True]))
+
 
 class TestTake(object):
     def tst_basic(self, x):
@@ -4425,6 +4440,11 @@ def test_record_array(self):
         rec1 = rec.take([1])
         assert_(rec1['x'] == 5.0 and rec1['y'] == 4.0)
 
+    def test_out_overlap(self):
+        # gh-6272 check overlap on out
+        x = np.arange(5)
+        y = np.take(x, [1, 2, 3], out=x[2:5], mode='wrap')
+        assert_equal(y, np.array([1, 2, 3]))
 
 class TestLexsort(object):
     def test_basic(self):