MAINT: fix up `_sputils.get_index_dtype` for NEP 50 casting rules
authorRalf Gommers <ralf.gommers@gmail.com>
Fri, 17 Jun 2022 14:22:40 +0000 (16:22 +0200)
committerDrew Parsons <dparsons@debian.org>
Thu, 19 Jan 2023 13:54:51 +0000 (13:54 +0000)
The issue boiled down to `np.iinfo(np.int32).max` being a Python int,
and comparisons between numpy scalars and Python scalars changing
behavior - so avoid using Python scalars.

Also fix other sparse issues in the test suite turned up by NEP 50
And makes the tests more concise.

Gbp-Pq: Name 0014-MAINT-fix-up-_sputils.get_index_dtype-for-NEP-50-cas.patch

scipy/sparse/_sputils.py
scipy/sparse/linalg/tests/test_matfuncs.py
scipy/sparse/tests/test_base.py
scipy/sparse/tests/test_sputils.py

index 6d93b6f92a083689878bc4e09c43143de25eba16..add718f2d7fa0cc713cd7c4b158a9a8f4a6b05c2 100644 (file)
@@ -150,12 +150,13 @@ def get_index_dtype(arrays=(), maxval=None, check_contents=False):
 
     """
 
-    int32min = np.iinfo(np.int32).min
-    int32max = np.iinfo(np.int32).max
+    int32min = np.int32(np.iinfo(np.int32).min)
+    int32max = np.int32(np.iinfo(np.int32).max)
 
     # not using intc directly due to misinteractions with pythran
     dtype = np.int32 if np.intc().itemsize == 4 else np.int64
     if maxval is not None:
+        maxval = np.int64(maxval)
         if maxval > int32max:
             dtype = np.int64
 
index 2ea5d11ec4d7dabc35d535b9ab5ab96ac8ba125b..8f984553ce4d52eef852619615acc2b1e01c5d9a 100644 (file)
@@ -113,7 +113,7 @@ class TestExpM:
             for scale in [1e-2, 1e-1, 5e-1, 1, 10]:
                 A = scale * eye(3, dtype=dtype)
                 observed = expm(A)
-                expected = exp(scale) * eye(3, dtype=dtype)
+                expected = exp(scale, dtype=dtype) * eye(3, dtype=dtype)
                 assert_array_almost_equal_nulp(observed, expected, nulp=100)
 
     def test_padecases_dtype_complex(self):
@@ -121,7 +121,7 @@ class TestExpM:
             for scale in [1e-2, 1e-1, 5e-1, 1, 10]:
                 A = scale * eye(3, dtype=dtype)
                 observed = expm(A)
-                expected = exp(scale) * eye(3, dtype=dtype)
+                expected = exp(scale, dtype=dtype) * eye(3, dtype=dtype)
                 assert_array_almost_equal_nulp(observed, expected, nulp=100)
 
     def test_padecases_dtype_sparse_float(self):
@@ -129,7 +129,7 @@ class TestExpM:
         dtype = np.float64
         for scale in [1e-2, 1e-1, 5e-1, 1, 10]:
             a = scale * speye(3, 3, dtype=dtype, format='csc')
-            e = exp(scale) * eye(3, dtype=dtype)
+            e = exp(scale, dtype=dtype) * eye(3, dtype=dtype)
             with suppress_warnings() as sup:
                 sup.filter(SparseEfficiencyWarning,
                            "Changing the sparsity structure of a csc_matrix is expensive.")
index 9e2ec874a9897c69512026c08fb09a59177afee9..c6c95897a967366c038e4d3dd11b7d7ab13c4912 100644 (file)
@@ -97,7 +97,11 @@ def with_64bit_maxval_limit(maxval_limit=None, random=False, fixed_dtype=None,
 
     """
     if maxval_limit is None:
-        maxval_limit = 10
+        maxval_limit = np.int64(10)
+    else:
+        # Ensure we use numpy scalars rather than Python scalars (matters for
+        # NEP 50 casting rule changes)
+        maxval_limit = np.int64(maxval_limit)
 
     if assert_32bit:
         def new_get_index_dtype(arrays=(), maxval=None, check_contents=False):
@@ -409,21 +413,15 @@ class _TestCommon:
             assert_array_equal_dtype(dat < dat2, datsp < dat2)
             assert_array_equal_dtype(datcomplex < dat2, datspcomplex < dat2)
             # sparse/scalar
-            assert_array_equal_dtype((datsp < 2).toarray(), dat < 2)
-            assert_array_equal_dtype((datsp < 1).toarray(), dat < 1)
-            assert_array_equal_dtype((datsp < 0).toarray(), dat < 0)
-            assert_array_equal_dtype((datsp < -1).toarray(), dat < -1)
-            assert_array_equal_dtype((datsp < -2).toarray(), dat < -2)
+            for val in [2, 1, 0, -1, -2]:
+                val = np.int64(val)  # avoid Python scalar (due to NEP 50 changes)
+                assert_array_equal_dtype((datsp < val).toarray(), dat < val)
+                assert_array_equal_dtype((val < datsp).toarray(), val < dat)
+
             with np.errstate(invalid='ignore'):
                 assert_array_equal_dtype((datsp < np.nan).toarray(),
                                          dat < np.nan)
 
-            assert_array_equal_dtype((2 < datsp).toarray(), 2 < dat)
-            assert_array_equal_dtype((1 < datsp).toarray(), 1 < dat)
-            assert_array_equal_dtype((0 < datsp).toarray(), 0 < dat)
-            assert_array_equal_dtype((-1 < datsp).toarray(), -1 < dat)
-            assert_array_equal_dtype((-2 < datsp).toarray(), -2 < dat)
-
             # data
             dat = self.dat_dtypes[dtype]
             datsp = self.datsp_dtypes[dtype]
@@ -477,21 +475,15 @@ class _TestCommon:
             assert_array_equal_dtype(dat > dat2, datsp > dat2)
             assert_array_equal_dtype(datcomplex > dat2, datspcomplex > dat2)
             # sparse/scalar
-            assert_array_equal_dtype((datsp > 2).toarray(), dat > 2)
-            assert_array_equal_dtype((datsp > 1).toarray(), dat > 1)
-            assert_array_equal_dtype((datsp > 0).toarray(), dat > 0)
-            assert_array_equal_dtype((datsp > -1).toarray(), dat > -1)
-            assert_array_equal_dtype((datsp > -2).toarray(), dat > -2)
+            for val in [2, 1, 0, -1, -2]:
+                val = np.int64(val)  # avoid Python scalar (due to NEP 50 changes)
+                assert_array_equal_dtype((datsp > val).toarray(), dat > val)
+                assert_array_equal_dtype((val > datsp).toarray(), val > dat)
+
             with np.errstate(invalid='ignore'):
                 assert_array_equal_dtype((datsp > np.nan).toarray(),
                                          dat > np.nan)
 
-            assert_array_equal_dtype((2 > datsp).toarray(), 2 > dat)
-            assert_array_equal_dtype((1 > datsp).toarray(), 1 > dat)
-            assert_array_equal_dtype((0 > datsp).toarray(), 0 > dat)
-            assert_array_equal_dtype((-1 > datsp).toarray(), -1 > dat)
-            assert_array_equal_dtype((-2 > datsp).toarray(), -2 > dat)
-
             # data
             dat = self.dat_dtypes[dtype]
             datsp = self.datsp_dtypes[dtype]
@@ -545,15 +537,10 @@ class _TestCommon:
             assert_array_equal_dtype(datsp <= dat2, dat <= dat2)
             assert_array_equal_dtype(datspcomplex <= dat2, datcomplex <= dat2)
             # sparse/scalar
-            assert_array_equal_dtype((datsp <= 2).toarray(), dat <= 2)
-            assert_array_equal_dtype((datsp <= 1).toarray(), dat <= 1)
-            assert_array_equal_dtype((datsp <= -1).toarray(), dat <= -1)
-            assert_array_equal_dtype((datsp <= -2).toarray(), dat <= -2)
-
-            assert_array_equal_dtype((2 <= datsp).toarray(), 2 <= dat)
-            assert_array_equal_dtype((1 <= datsp).toarray(), 1 <= dat)
-            assert_array_equal_dtype((-1 <= datsp).toarray(), -1 <= dat)
-            assert_array_equal_dtype((-2 <= datsp).toarray(), -2 <= dat)
+            for val in [2, 1, -1, -2]:
+                val = np.int64(val)  # avoid Python scalar (due to NEP 50 changes)
+                assert_array_equal_dtype((datsp <= val).toarray(), dat <= val)
+                assert_array_equal_dtype((val <= datsp).toarray(), val <= dat)
 
             # data
             dat = self.dat_dtypes[dtype]
@@ -608,15 +595,10 @@ class _TestCommon:
             assert_array_equal_dtype(datsp >= dat2, dat >= dat2)
             assert_array_equal_dtype(datspcomplex >= dat2, datcomplex >= dat2)
             # sparse/scalar
-            assert_array_equal_dtype((datsp >= 2).toarray(), dat >= 2)
-            assert_array_equal_dtype((datsp >= 1).toarray(), dat >= 1)
-            assert_array_equal_dtype((datsp >= -1).toarray(), dat >= -1)
-            assert_array_equal_dtype((datsp >= -2).toarray(), dat >= -2)
-
-            assert_array_equal_dtype((2 >= datsp).toarray(), 2 >= dat)
-            assert_array_equal_dtype((1 >= datsp).toarray(), 1 >= dat)
-            assert_array_equal_dtype((-1 >= datsp).toarray(), -1 >= dat)
-            assert_array_equal_dtype((-2 >= datsp).toarray(), -2 >= dat)
+            for val in [2, 1, -1, -2]:
+                val = np.int64(val)  # avoid Python scalar (due to NEP 50 changes)
+                assert_array_equal_dtype((datsp >= val).toarray(), dat >= val)
+                assert_array_equal_dtype((val >= datsp).toarray(), val >= dat)
 
             # dense data
             dat = self.dat_dtypes[dtype]
index 0eaf573f3b6b661f4a13cbc442d8863d3f5a4b74..fadce9e2fdc980b34c315e6a4da48c2f0b068c18 100644 (file)
@@ -94,7 +94,7 @@ class TestSparseUtils:
             sputils.validateaxis(axis)
 
     def test_get_index_dtype(self):
-        imax = np.iinfo(np.int32).max
+        imax = np.int64(np.iinfo(np.int32).max)
         too_big = imax + 1
 
         # Check that uint32's with no values too large doesn't return