Repository: cupy/cupy

Issue:
Different behaviour of argmax
I found the behaviour of `argmax` is different between `numpy` and `cupy` if the array has `0` in its shape and `axis` argument is used. I don't know whether this behaviour is intended or not.

```
np.empty((0, 1)).argmax(axis=1)  # array([], dtype=int64)
cupy.empty((0, 1)).argmax(axis=1)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-9-a5737d72bcba> in <module>()
----> 1 cupy.empty((0, 1)).argmax(axis=1)

cupy/core/core.pyx in cupy.core.core.ndarray.argmax (cupy/core/core.cpp:17701)()

cupy/core/core.pyx in cupy.core.core.ndarray.argmax (cupy/core/core.cpp:17556)()

cupy/core/reduction.pxi in cupy.core.core.simple_reduction_function.__call__ (cupy/core/core.cpp:52697)()

ValueError: zero-size array to reduction operation cupy_argmax which has no identity
```

I used cupy 2.0.0a1.


Discussion:

Resolving patch:
diff --git a/cupy/logic/truth.py b/cupy/logic/truth.py
--- a/cupy/logic/truth.py
+++ b/cupy/logic/truth.py
@@ -1,8 +1,11 @@
+import cupy
+
+
 def all(a, axis=None, out=None, keepdims=False):
-    # TODO(okuta): check type
+    assert isinstance(a, cupy.ndarray)
     return a.all(axis=axis, out=out, keepdims=keepdims)
 
 
 def any(a, axis=None, out=None, keepdims=False):
-    # TODO(okuta): check type
+    assert isinstance(a, cupy.ndarray)
     return a.any(axis=axis, out=out, keepdims=keepdims)


Test patch:
diff --git a/tests/cupy_tests/logic_tests/test_truth.py b/tests/cupy_tests/logic_tests/test_truth.py
--- a/tests/cupy_tests/logic_tests/test_truth.py
+++ b/tests/cupy_tests/logic_tests/test_truth.py
@@ -29,7 +29,9 @@ def _calc_out_shape(shape, axis, keepdims):
         {'f': ['all', 'any'],
          'x': [numpy.arange(24).reshape(2, 3, 4) - 10,
                numpy.zeros((2, 3, 4)),
-               numpy.ones((2, 3, 4))],
+               numpy.ones((2, 3, 4)),
+               numpy.zeros((0, 3, 4)),
+               numpy.ones((0, 3, 4))],
          'axis': [None, (0, 1, 2), 0, 1, 2, (0, 1)],
          'keepdims': [False, True]}))
 @testing.gpu
diff --git a/tests/cupy_tests/sorting_tests/test_search.py b/tests/cupy_tests/sorting_tests/test_search.py
--- a/tests/cupy_tests/sorting_tests/test_search.py
+++ b/tests/cupy_tests/sorting_tests/test_search.py
@@ -58,6 +58,24 @@ def test_argmax_axis2(self, xp, dtype):
         a = testing.shaped_random((2, 3, 4), xp, dtype)
         return a.argmax(axis=2)
 
+    @testing.for_all_dtypes(no_complex=True)
+    @testing.numpy_cupy_raises(accept_error=ValueError)
+    def test_argmax_zero_size(self, xp, dtype):
+        a = testing.shaped_random((0, 1), xp, dtype)
+        return a.argmax()
+
+    @testing.for_all_dtypes(no_complex=True)
+    @testing.numpy_cupy_raises(accept_error=ValueError)
+    def test_argmax_zero_size_axis0(self, xp, dtype):
+        a = testing.shaped_random((0, 1), xp, dtype)
+        return a.argmax(axis=0)
+
+    @testing.for_all_dtypes(no_complex=True)
+    @testing.numpy_cupy_allclose()
+    def test_argmax_zero_size_axis1(self, xp, dtype):
+        a = testing.shaped_random((0, 1), xp, dtype)
+        return a.argmax(axis=1)
+
     @testing.for_all_dtypes(no_complex=True)
     @testing.numpy_cupy_allclose()
     def test_argmin_all(self, xp, dtype):
@@ -106,6 +124,24 @@ def test_argmin_axis2(self, xp, dtype):
         a = testing.shaped_random((2, 3, 4), xp, dtype)
         return a.argmin(axis=2)
 
+    @testing.for_all_dtypes(no_complex=True)
+    @testing.numpy_cupy_raises(accept_error=ValueError)
+    def test_argmin_zero_size(self, xp, dtype):
+        a = testing.shaped_random((0, 1), xp, dtype)
+        return a.argmin()
+
+    @testing.for_all_dtypes(no_complex=True)
+    @testing.numpy_cupy_raises(accept_error=ValueError)
+    def test_argmin_zero_size_axis0(self, xp, dtype):
+        a = testing.shaped_random((0, 1), xp, dtype)
+        return a.argmin(axis=0)
+
+    @testing.for_all_dtypes(no_complex=True)
+    @testing.numpy_cupy_allclose()
+    def test_argmin_zero_size_axis1(self, xp, dtype):
+        a = testing.shaped_random((0, 1), xp, dtype)
+        return a.argmin(axis=1)
+
 
 @testing.parameterize(
     {'cond_shape': (2, 3, 4), 'x_shape': (2, 3, 4), 'y_shape': (2, 3, 4)},