Repository: numpy/numpy

Issue:
np.allclose returns memmap object when comparing a memmap array to a normal array
This is a new behaviour in numpy 1.10 and according to the doc np.allclose is supposed to return a bool. Is it an intended change?

Note that the returned object still has the right truthiness value so it should not be a problem except in conditions like `if np.allclose(...) is True:`. In our case a doctest fails but we could work around the failure if needed.

A snippet reproducing the behaviour:

``` python
import tempfile
import os

import numpy as np

dtype = 'f8'
shape = (3, 4)
array = np.ones(shape, dtype=dtype)

temp_folder = tempfile.mkdtemp()
filename = os.path.join(temp_folder, 'test.mmap')

memmap = np.memmap(filename, mode='w+', shape=shape, dtype=dtype)

memmap[:] = array[:]

print('all close: {!r}'.format(np.allclose(array, memmap)))
```

Output with numpy 1.10.1:

```
all close: memmap(True, dtype=bool)
```

Output with numpy 1.9.3:

```
all close: True
```



Discussion:
After bisection the first bad commit is at 2ae0529.

The source of the problem is in `isclose`, where

```
    x = array(a, copy=False, subok=True, ndmin=1)
    y = array(b, copy=False, subok=True, ndmin=1)
```

The `subok=True` allows `memmap` to pass through, whereas in the original `alltrue` a copy was made. This is probably a good thing on the whole.

So I think the question is whether or not to convert the result from memmap for allclose. An easy way to do that is to use `np.array(result, copy=False)` and I'm tending that way, but not yet convinced we want to do that. @lesteve Is the current behavior causing problems for you?

For the case of allclose specifically there's an argument for just calling
bool on the result.
.
Part of the problem here is the usual issue where we have no consistent
semantics for array subclasses. Returning a memmap object makes no sense,
but that's a more general bug: lots of operations on memmap objects return
memmap objects that shouldn't. (E.g. all ufuncs.) For other subclasses who
knows. Certainly there's an argument that isclose on np.ma objects should
return a np.ma object, and that allclose should match np.all(isclose).
On Nov 4, 2015 11:30 AM, "Charles Harris" notifications@github.com wrote:

> So I think the question is whether or not to convert the result from
> memmap. An easy way to do that is to use np.array(result, copy=False) and
> I'm tending that way, but not yet convinced we want to do that. @lesteve
> https://github.com/lesteve Is the current behavior causing problems for
> you?
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/numpy/numpy/issues/6475#issuecomment-153839087.


Resolving patch:
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -2278,7 +2278,8 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
     True
 
     """
-    return all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
+    res = all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
+    return bool(res)
 
 def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
     """


Test patch:
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -1471,6 +1471,16 @@ def test_equalnan(self):
         x = np.array([1.0, np.nan])
         assert_(np.allclose(x, x, equal_nan=True))
 
+    def test_return_class_is_ndarray(self):
+        # Issue gh-6475
+        # Check that allclose does not preserve subtypes
+        class Foo(np.ndarray):
+            def __new__(cls, *args, **kwargs):
+                return np.array(*args, **kwargs).view(cls)
+
+        a = Foo([1])
+        assert_(type(np.allclose(a, a)) is bool)
+
 
 class TestIsclose(object):
     rtol = 1e-5