Repository: numpy/numpy

Issue:
finfo results have changed from scalars to arrays
See https://github.com/scipy/scipy/issues/7015

The problem is caused by this change in numpy:

numpy '1.11.2':
```
In [9]: np.finfo(float).machar.xmin
Out[9]: array(2.2250738585072014e-308)
```
numpy '1.13.0.dev0+98b3127':
```
In [18]: np.finfo(float).machar.xmin
Out[18]: array([  2.22507386e-308])
```

Note that in the second case, the value is a one-dimensional array, while in the old numpy it is a 0-dimensional array (i.e. a "scalar array").

That value, called _XMIN in the scipy code, is used as part of a where() expression when genextreme checks its arguments and assigns the values genextreme.a and genextreme.b. Because the new numpy gives a 1-d array, the values assigned to the support limits become 1-d arrays. If these are then combined as they are in the test using x = [genextreme.a, genextreme.b], the result is an array with shape (2, 1).


Discussion:

Resolving patch:
diff --git a/numpy/core/getlimits.py b/numpy/core/getlimits.py
--- a/numpy/core/getlimits.py
+++ b/numpy/core/getlimits.py
@@ -15,13 +15,22 @@
 from . import umath
 
 
-def _frz(a):
+def _fr0(a):
     """fix rank-0 --> rank-1"""
     if a.ndim == 0:
+        a = a.copy()
         a.shape = (1,)
     return a
 
 
+def _fr1(a):
+    """fix rank > 0 --> rank-0"""
+    if a.size == 1:
+        a = a.copy()
+        a.shape = ()
+    return a
+
+
 _convert_to_float = {
     ntypes.csingle: ntypes.single,
     ntypes.complex_: ntypes.float_,
@@ -30,48 +39,46 @@ def _frz(a):
 
 
 # Parameters for creating MachAr / MachAr-like objects
+_title_fmt = 'numpy {} precision floating point number'
 _MACHAR_PARAMS = {
     ntypes.double: dict(
         itype = ntypes.int64,
         fmt = '%24.16e',
-        precname = 'double'),
+        title = _title_fmt.format('double')),
     ntypes.single: dict(
         itype = ntypes.int32,
         fmt = '%15.7e',
-        precname = 'single'),
+        title = _title_fmt.format('single')),
     ntypes.longdouble: dict(
         itype = ntypes.longlong,
         fmt = '%s',
-        precname = 'long double'),
+        title = _title_fmt.format('long double')),
     ntypes.half: dict(
         itype = ntypes.int16,
         fmt = '%12.5e',
-        precname = 'half')}
+        title = _title_fmt.format('half'))}
 
 
 class MachArLike(object):
     """ Object to simulate MachAr instance """
 
-    # These attributes should be of characteristic dtype
-    _native_attrs = ('tiny', 'huge', 'epsneg', 'eps')
-
     def __init__(self,
                  ftype,
                  **kwargs):
         params = _MACHAR_PARAMS[ftype]
         float_conv = lambda v: array([v], ftype)
-        float_to_str = lambda v: params['fmt'] % array(_frz(v)[0], ftype)
-        self.title = 'numpy {} precision floating point number'.format(
-            params['precname'])
-        for key, value in kwargs.items():
-            if key in self._native_attrs:
-                value = float_conv(value)
-            self.__dict__[key] = value
-        self.epsilon = self.eps
-        self.xmax = self.huge
-        self.xmin = self.tiny
+        float_to_float = lambda v : _fr1(float_conv(v))
+        float_to_str = lambda v: (params['fmt'] % array(_fr0(v)[0], ftype))
+        self.title = params['title']
+        # Parameter types same as for discovered MachAr object.
+        self.epsilon = self.eps = float_to_float(kwargs.pop('eps'))
+        self.epsneg = float_to_float(kwargs.pop('epsneg'))
+        self.xmax = self.huge = float_to_float(kwargs.pop('huge'))
+        self.xmin = self.tiny = float_to_float(kwargs.pop('tiny'))
+        self.ibeta = params['itype'](kwargs.pop('ibeta'))
+        self.__dict__.update(kwargs)
         self.precision = int(-log10(self.eps))
-        self.resolution = float_conv(10) ** (-self.precision)
+        self.resolution = float_to_float(float_conv(10) ** (-self.precision))
         self._str_eps = float_to_str(self.eps)
         self._str_epsneg = float_to_str(self.epsneg)
         self._str_xmin = float_to_str(self.xmin)
@@ -268,12 +275,11 @@ def _discovered_machar(ftype):
     """ Create MachAr instance with found information on float types
     """
     params = _MACHAR_PARAMS[ftype]
-    title = 'numpy %s precision floating point number' % params['precname']
     return MachAr(lambda v: array([v], ftype),
-                  lambda v:_frz(v.astype(params['itype']))[0],
-                  lambda v:array(_frz(v)[0], ftype),
-                  lambda v: params['fmt'] % array(_frz(v)[0], ftype),
-                  title)
+                  lambda v:_fr0(v.astype(params['itype']))[0],
+                  lambda v:array(_fr0(v)[0], ftype),
+                  lambda v: params['fmt'] % array(_fr0(v)[0], ftype),
+                  params['title'])
 
 
 class finfo(object):


Test patch:
diff --git a/numpy/core/tests/test_getlimits.py b/numpy/core/tests/test_getlimits.py
--- a/numpy/core/tests/test_getlimits.py
+++ b/numpy/core/tests/test_getlimits.py
@@ -91,8 +91,12 @@ def test_instances():
 
 
 def assert_ma_equal(discovered, ma_like):
+    # Check MachAr-like objects same as calculated MachAr instances
     for key, value in discovered.__dict__.items():
         assert_equal(value, getattr(ma_like, key))
+        if hasattr(value, 'shape'):
+            assert_equal(value.shape, getattr(ma_like, key).shape)
+            assert_equal(value.dtype, getattr(ma_like, key).dtype)
 
 
 def test_known_types():