Repository: numpy/numpy

Issue:
ufunc.reduce hides warnings
Arguments that would cause `ufunc.__call__` to throw a warning seem to not do so when passed to `ufunc.reduce`:

Bug or feature?
```python
In [24]: np.minimum(*[1, np.nan])
RuntimeWarning: invalid value encountered in minimum
Out[24]: nan

In [25]: np.minimum.reduce([1, np.nan])
Out[25]: nan

# not just minimum
In [28]: np.divide(*[1, 0])
RuntimeWarning: divide by zero encountered in true_divide
Out[28]: inf

In [29]: np.divide.reduce([1, 0])
Out[29]: inf
```


Discussion:
Looks like a bug to me. I suppose it could be an intentional optimization
to not check the fp flags.

On Apr 17, 2017 1:37 PM, "Eric Wieser" <notifications@github.com> wrote:

> Bug or feature?
>
> In [24]: np.minimum(*[1, np.nan])
> C:\Program Files\Python 3.5\Scripts\ipython:1: RuntimeWarning: invalid value encountered in minimum
> Out[24]: nan
>
> In [25]: np.minimum.reduce([1, np.nan])
> Out[25]: nan
>
> In [28]: np.divide(*[1, 0])
> C:\Program Files\Python 3.5\Scripts\ipython:1: RuntimeWarning: divide by zero encountered in true_divide
> Out[28]: inf
>
> In [29]: np.divide.reduce([1, 0])
> Out[29]: inf
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/numpy/numpy/issues/8954>, or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAlOaF3_NC4NeuRuVOeSakHlD-m6vLTsks5rw82jgaJpZM4M_i0x>
> .
>

This would be quite a user visible change, as `min` would all start warning on nans
Yeah. You could check on the list I guess if you're worried. But adding new useful warnings isn't generally a compatibility break, and numpy already provides good tools to control these particular warnings if people don't like the chatter.
This is a bit of a pain - `_check_ufunc_fperr` is not visible inside `reduction.c`

Resolving patch:
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -874,6 +874,7 @@ def generate_umath_c(ext, build_dir):
             join('src', 'umath', 'loops.h.src'),
             join('src', 'umath', 'loops.c.src'),
             join('src', 'umath', 'ufunc_object.c'),
+            join('src', 'umath', 'extobj.c'),
             join('src', 'umath', 'scalarmath.c.src'),
             join('src', 'umath', 'ufunc_type_resolution.c'),
             join('src', 'umath', 'override.c'),


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
@@ -3423,8 +3423,13 @@ def test_all(self):
 
     def test_combinations(self):
         for arr, pos in self.nan_arr:
+            with suppress_warnings() as sup:
+                sup.filter(RuntimeWarning,
+                           "invalid value encountered in reduce")
+                max_val = np.max(arr)
+
             assert_equal(np.argmax(arr), pos, err_msg="%r" % arr)
-            assert_equal(arr[np.argmax(arr)], np.max(arr), err_msg="%r" % arr)
+            assert_equal(arr[np.argmax(arr)], max_val, err_msg="%r" % arr)
 
     def test_output_shape(self):
         # see also gh-616
@@ -3552,8 +3557,13 @@ def test_all(self):
 
     def test_combinations(self):
         for arr, pos in self.nan_arr:
+            with suppress_warnings() as sup:
+                sup.filter(RuntimeWarning,
+                           "invalid value encountered in reduce")
+                min_val = np.min(arr)
+
             assert_equal(np.argmin(arr), pos, err_msg="%r" % arr)
-            assert_equal(arr[np.argmin(arr)], np.min(arr), err_msg="%r" % arr)
+            assert_equal(arr[np.argmin(arr)], min_val, err_msg="%r" % arr)
 
     def test_minimum_signed_integers(self):
 
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -10,6 +10,7 @@
     assert_no_warnings
 )
 
+import warnings
 
 class TestUfuncKwargs(TestCase):
     def test_kwarg_exact(self):
@@ -375,8 +376,17 @@ def test_sum(self):
                       128, 1024, 1235):
                 tgt = dt(v * (v + 1) / 2)
                 d = np.arange(1, v + 1, dtype=dt)
-                assert_almost_equal(np.sum(d), tgt)
-                assert_almost_equal(np.sum(d[::-1]), tgt)
+
+                # warning if sum overflows, which it does in float16
+                overflow = not np.isfinite(tgt)
+
+                with warnings.catch_warnings(record=True) as w:
+                    warnings.simplefilter("always")
+                    assert_almost_equal(np.sum(d), tgt)
+                    assert_equal(len(w), 1 * overflow)
+
+                    assert_almost_equal(np.sum(d[::-1]), tgt)
+                    assert_equal(len(w), 2 * overflow)
 
             d = np.ones(500, dtype=dt)
             assert_almost_equal(np.sum(d[::2]), 250.)
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -1299,8 +1299,11 @@ def test_minmax_blocked(self):
                     inp[:] = np.arange(inp.size, dtype=dt)
                     inp[i] = np.nan
                     emsg = lambda: '%r\n%s' % (inp, msg)
-                    assert_(np.isnan(inp.max()), msg=emsg)
-                    assert_(np.isnan(inp.min()), msg=emsg)
+                    with suppress_warnings() as sup:
+                        sup.filter(RuntimeWarning,
+                                   "invalid value encountered in reduce")
+                        assert_(np.isnan(inp.max()), msg=emsg)
+                        assert_(np.isnan(inp.min()), msg=emsg)
 
                     inp[i] = 1e10
                     assert_equal(inp.max(), 1e10, err_msg=msg)