Index: numba-0.57.1/docs/source/user/installing.rst =================================================================== --- numba-0.57.1.orig/docs/source/user/installing.rst +++ numba-0.57.1/docs/source/user/installing.rst @@ -262,6 +262,8 @@ information. +----------++--------------+---------------------------+----------------------------+------------------------------+-------------------+-----------------------------+ | Numba | Release date | Python | NumPy | llvmlite | LLVM | TBB | +===========+==============+===========================+============================+==============================+===================+=============================+ +| 0.58.0 | UNRELEASED | 3.8.x <= version < 3.12 | 1.21 <= version < 1.26 | 0.41.x | 14.x | 2021.6 <= version | ++-----------+--------------+---------------------------+----------------------------+------------------------------+-------------------+-----------------------------+ | 0.57.1 | 2023-06-21 | 3.8.x <= version < 3.12 | 1.21 <= version < 1.25 | 0.40.x | 14.x | 2021.6 <= version | +-----------+--------------+---------------------------+----------------------------+------------------------------+-------------------+-----------------------------+ | 0.57.0 | 2023-05-01 | 3.8.x <= version < 3.12 | 1.21 <= version < 1.25 | 0.40.x | 14.x | 2021.6 <= version | Index: numba-0.57.1/docs/upcoming_changes/9011.np_support.rst =================================================================== --- /dev/null +++ numba-0.57.1/docs/upcoming_changes/9011.np_support.rst @@ -0,0 +1,5 @@ + +Add support for NumPy 1.25 +========================== + +Extend Numba to support new and changed features released in NumPy 1.25. Index: numba-0.57.1/numba/core/typing/npdatetime.py =================================================================== --- numba-0.57.1.orig/numba/core/typing/npdatetime.py +++ numba-0.57.1/numba/core/typing/npdatetime.py @@ -11,6 +11,7 @@ from numba.core.typing.templates import AbstractTemplate, infer_global, infer, infer_getattr, signature) from numba.np import npdatetime_helpers +from numba.np.numpy_support import numpy_version # timedelta64-only operations @@ -144,13 +145,22 @@ class TimedeltaTrueDiv(TimedeltaDivOp): class TimedeltaFloorDiv(TimedeltaDivOp): key = operator.floordiv -@infer_global(operator.eq) -class TimedeltaCmpEq(TimedeltaCmpOp): - key = operator.eq - -@infer_global(operator.ne) -class TimedeltaCmpNe(TimedeltaCmpOp): - key = operator.ne +if numpy_version >= (1, 25): + @infer_global(operator.eq) + class TimedeltaCmpEq(TimedeltaOrderedCmpOp): + key = operator.eq + + @infer_global(operator.ne) + class TimedeltaCmpNe(TimedeltaOrderedCmpOp): + key = operator.ne +else: + @infer_global(operator.eq) + class TimedeltaCmpEq(TimedeltaCmpOp): + key = operator.eq + + @infer_global(operator.ne) + class TimedeltaCmpNe(TimedeltaCmpOp): + key = operator.ne @infer_global(operator.lt) class TimedeltaCmpLt(TimedeltaOrderedCmpOp): @@ -228,7 +238,6 @@ class DatetimeMinusDatetime(AbstractTemp left, right = args if isinstance(left, types.NPDatetime) and isinstance(right, types.NPDatetime): - # All units compatible... unit = npdatetime_helpers.get_best_unit(left.unit, right.unit) return signature(types.NPTimedelta(unit), left, right) Index: numba-0.57.1/numba/cpython/numbers.py =================================================================== --- numba-0.57.1.orig/numba/cpython/numbers.py +++ numba-0.57.1/numba/cpython/numbers.py @@ -361,6 +361,38 @@ def int_ne_impl(context, builder, sig, a return impl_ret_untracked(context, builder, sig.return_type, res) +def int_signed_unsigned_cmp(op): + def impl(context, builder, sig, args): + (left, right) = args + # This code is translated from the NumPy source. + # What we're going to do is divide the range of a signed value at zero. + # If the signed value is less than zero, then we can treat zero as the + # unsigned value since the unsigned value is necessarily zero or larger + # and any signed comparison between a negative value and zero/infinity + # will yield the same result. If the signed value is greater than or + # equal to zero, then we can safely cast it to an unsigned value and do + # the expected unsigned-unsigned comparison operation. + # Original: https://github.com/numpy/numpy/pull/23713 + cmp_zero = builder.icmp_signed('<', left, Constant(left.type, 0)) + lt_zero = builder.icmp_signed(op, left, Constant(left.type, 0)) + ge_zero = builder.icmp_unsigned(op, left, right) + res = builder.select(cmp_zero, lt_zero, ge_zero) + return impl_ret_untracked(context, builder, sig.return_type, res) + return impl + + +def int_unsigned_signed_cmp(op): + def impl(context, builder, sig, args): + (left, right) = args + # See the function `int_signed_unsigned_cmp` for implementation notes. + cmp_zero = builder.icmp_signed('<', right, Constant(right.type, 0)) + lt_zero = builder.icmp_signed(op, Constant(right.type, 0), right) + ge_zero = builder.icmp_unsigned(op, left, right) + res = builder.select(cmp_zero, lt_zero, ge_zero) + return impl_ret_untracked(context, builder, sig.return_type, res) + return impl + + def int_abs_impl(context, builder, sig, args): [x] = args ZERO = Constant(x.type, None) Index: numba-0.57.1/numba/cuda/tests/cudapy/test_gufunc.py =================================================================== --- numba-0.57.1.orig/numba/cuda/tests/cudapy/test_gufunc.py +++ numba-0.57.1/numba/cuda/tests/cudapy/test_gufunc.py @@ -1,5 +1,4 @@ import numpy as np -import numpy.core.umath_tests as ut from collections import namedtuple from numba import void, int32, float32, float64 @@ -42,7 +41,7 @@ class TestCUDAGufunc(CUDATestCase): 5) C = gufunc(A, B) - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) self.assertTrue(np.allclose(C, Gold)) def test_gufunc_auto_transfer(self): @@ -58,7 +57,7 @@ class TestCUDAGufunc(CUDATestCase): dB = cuda.to_device(B) C = gufunc(A, dB).copy_to_host() - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) self.assertTrue(np.allclose(C, Gold)) def test_gufunc(self): @@ -72,7 +71,7 @@ class TestCUDAGufunc(CUDATestCase): 5) C = gufunc(A, B) - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) self.assertTrue(np.allclose(C, Gold)) def test_gufunc_hidim(self): @@ -84,7 +83,7 @@ class TestCUDAGufunc(CUDATestCase): B = np.arange(matrix_ct * 4 * 5, dtype=np.float32).reshape(4, 25, 4, 5) C = gufunc(A, B) - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) self.assertTrue(np.allclose(C, Gold)) def test_gufunc_new_axis(self): @@ -94,7 +93,7 @@ class TestCUDAGufunc(CUDATestCase): X = np.random.randn(10, 3, 3) Y = np.random.randn(3, 3) - gold = ut.matrix_multiply(X, Y) + gold = np.matmul(X, Y) res1 = gufunc(X, Y) np.testing.assert_allclose(gold, res1) @@ -122,7 +121,7 @@ class TestCUDAGufunc(CUDATestCase): C = dC.copy_to_host(stream=stream) stream.synchronize() - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) self.assertTrue(np.allclose(C, Gold)) Index: numba-0.57.1/numba/cuda/ufuncs.py =================================================================== --- numba-0.57.1.orig/numba/cuda/ufuncs.py +++ numba-0.57.1/numba/cuda/ufuncs.py @@ -25,6 +25,7 @@ def ufunc_db(): from numba.np.npyfuncs import _check_arity_and_homogeneity from numba.np.npyfuncs import (np_complex_acosh_impl, np_complex_cos_impl, np_complex_sin_impl) + from numba.np.numpy_support import numpy_version def np_unary_impl(fn, context, builder, sig, args): _check_arity_and_homogeneity(sig, args, 1) @@ -269,6 +270,10 @@ def ufunc_db(): 'f->f': mathimpl.degrees_float_impl, 'd->d': mathimpl.degrees_float_impl, } + if numpy_version >= (1, 25): + db[np.greater].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('>'), + 'Qq->?': numbers.int_unsigned_signed_cmp('>')}) db[np.degrees] = db[np.rad2deg] Index: numba-0.57.1/numba/np/arraymath.py =================================================================== --- numba-0.57.1.orig/numba/np/arraymath.py +++ numba-0.57.1/numba/np/arraymath.py @@ -490,6 +490,7 @@ def return_false(a): @overload(np.min) +@overload(np.amin) @overload_method(types.Array, "min") def npy_min(a): if not isinstance(a, types.Array): @@ -539,6 +540,7 @@ def npy_min(a): @overload(np.max) +@overload(np.amax) @overload_method(types.Array, "max") def npy_max(a): if not isinstance(a, types.Array): @@ -3124,6 +3126,7 @@ def round_ndigits(x, ndigits): @overload(np.around) @overload(np.round) +@overload(np.round_) def impl_np_round(a, decimals=0, out=None): if not type_can_asarray(a): raise TypingError('The argument "a" must be array-like') Index: numba-0.57.1/numba/np/ufunc_db.py =================================================================== --- numba-0.57.1.orig/numba/np/ufunc_db.py +++ numba-0.57.1/numba/np/ufunc_db.py @@ -620,6 +620,10 @@ def _fill_ufunc_db(ufunc_db): 'FF->?': npyfuncs.np_complex_gt_impl, 'DD->?': npyfuncs.np_complex_gt_impl, } + if numpy_version >= (1, 25): + ufunc_db[np.greater].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('>'), + 'Qq->?': numbers.int_unsigned_signed_cmp('>')}) ufunc_db[np.greater_equal] = { '??->?': numbers.int_uge_impl, @@ -638,6 +642,10 @@ def _fill_ufunc_db(ufunc_db): 'FF->?': npyfuncs.np_complex_ge_impl, 'DD->?': npyfuncs.np_complex_ge_impl, } + if numpy_version >= (1, 25): + ufunc_db[np.greater_equal].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('>='), + 'Qq->?': numbers.int_unsigned_signed_cmp('>=')}) ufunc_db[np.less] = { '??->?': numbers.int_ult_impl, @@ -656,6 +664,10 @@ def _fill_ufunc_db(ufunc_db): 'FF->?': npyfuncs.np_complex_lt_impl, 'DD->?': npyfuncs.np_complex_lt_impl, } + if numpy_version >= (1, 25): + ufunc_db[np.less].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('<'), + 'Qq->?': numbers.int_unsigned_signed_cmp('<')}) ufunc_db[np.less_equal] = { '??->?': numbers.int_ule_impl, @@ -674,6 +686,10 @@ def _fill_ufunc_db(ufunc_db): 'FF->?': npyfuncs.np_complex_le_impl, 'DD->?': npyfuncs.np_complex_le_impl, } + if numpy_version >= (1, 25): + ufunc_db[np.less_equal].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('<='), + 'Qq->?': numbers.int_unsigned_signed_cmp('<=')}) ufunc_db[np.not_equal] = { '??->?': numbers.int_ne_impl, @@ -692,6 +708,10 @@ def _fill_ufunc_db(ufunc_db): 'FF->?': npyfuncs.np_complex_ne_impl, 'DD->?': npyfuncs.np_complex_ne_impl, } + if numpy_version >= (1, 25): + ufunc_db[np.not_equal].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('!='), + 'Qq->?': numbers.int_unsigned_signed_cmp('!=')}) ufunc_db[np.equal] = { '??->?': numbers.int_eq_impl, @@ -710,6 +730,10 @@ def _fill_ufunc_db(ufunc_db): 'FF->?': npyfuncs.np_complex_eq_impl, 'DD->?': npyfuncs.np_complex_eq_impl, } + if numpy_version >= (1, 25): + ufunc_db[np.equal].update({ + 'qQ->?': numbers.int_signed_unsigned_cmp('=='), + 'Qq->?': numbers.int_unsigned_signed_cmp('==')}) ufunc_db[np.logical_and] = { '??->?': npyfuncs.np_logical_and_impl, Index: numba-0.57.1/numba/tests/npyufunc/test_gufunc.py =================================================================== --- numba-0.57.1.orig/numba/tests/npyufunc/test_gufunc.py +++ numba-0.57.1/numba/tests/npyufunc/test_gufunc.py @@ -2,7 +2,6 @@ import unittest import pickle import numpy as np -import numpy.core.umath_tests as ut from numba import void, float32, int64, jit, guvectorize from numba.np.ufunc import GUVectorize @@ -33,7 +32,7 @@ class TestGUFunc(TestCase): B = np.arange(matrix_ct * 4 * 5, dtype=np.float32).reshape(matrix_ct, 4, 5) C = gufunc(A, B) - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) np.testing.assert_allclose(C, Gold, rtol=1e-5, atol=1e-8) @@ -108,7 +107,7 @@ class TestDynamicGUFunc(TestCase): def test_dynamic_matmul(self): def check_matmul_gufunc(gufunc, A, B, C): - Gold = ut.matrix_multiply(A, B) + Gold = np.matmul(A, B) gufunc(A, B, C) np.testing.assert_allclose(C, Gold, rtol=1e-5, atol=1e-8) Index: numba-0.57.1/numba/tests/test_array_methods.py =================================================================== --- numba-0.57.1.orig/numba/tests/test_array_methods.py +++ numba-0.57.1/numba/tests/test_array_methods.py @@ -31,6 +31,9 @@ def np_around_unary(val): def np_round_array(arr, decimals, out): np.round(arr, decimals, out) +def np_round__array(arr, decimals, out): + np.round_(arr, decimals, out) + def np_round_binary(val, decimals): return np.round(val, decimals) @@ -366,6 +369,9 @@ class TestArrayMethods(MemoryLeakMixin, def test_around_array(self): self.check_round_array(np_around_array) + def test_round__array(self): + self.check_round_array(np_round__array) + def test_around_bad_array(self): for pyfunc in (np_round_unary, np_around_unary): cfunc = jit(nopython=True)(pyfunc) @@ -374,7 +380,7 @@ class TestArrayMethods(MemoryLeakMixin, cfunc(None) def test_around_bad_out(self): - for py_func in (np_round_array, np_around_array): + for py_func in (np_round_array, np_around_array, np_round__array): cfunc = jit(nopython=True)(py_func) msg = '.*The argument "out" must be an array if it is provided.*' with self.assertRaisesRegex(TypingError, msg): Index: numba-0.57.1/numba/tests/test_array_reductions.py =================================================================== --- numba-0.57.1.orig/numba/tests/test_array_reductions.py +++ numba-0.57.1/numba/tests/test_array_reductions.py @@ -75,12 +75,18 @@ def array_min(arr): def array_min_global(arr): return np.min(arr) +def array_amin(arr): + return np.amin(arr) + def array_max(arr): return arr.max() def array_max_global(arr): return np.max(arr) +def array_amax(arr): + return np.amax(arr) + def array_argmin(arr): return arr.argmin() @@ -1110,6 +1116,7 @@ class TestArrayReductions(MemoryLeakMixi array_all, array_all_global, array_any, array_any_global, array_min, array_min_global, + array_amax, array_amin, array_max, array_max_global, array_nanmax, array_nanmin, array_nansum, Index: numba-0.57.1/numba/tests/test_fancy_indexing.py =================================================================== --- numba-0.57.1.orig/numba/tests/test_fancy_indexing.py +++ numba-0.57.1/numba/tests/test_fancy_indexing.py @@ -406,7 +406,7 @@ class TestFancyIndexingMultiDim(MemoryLe expected = get_item(arr, index) got = numba_get_item(arr, index) # Sanity check: In advanced indexing, the result is always a copy. - self.assertNotIn(expected.base, orig_base) + self.assertIsNot(expected.base, orig_base) # Note: Numba may not return the same array strides and # contiguity as NumPy Index: numba-0.57.1/numba/tests/test_npdatetime.py =================================================================== --- numba-0.57.1.orig/numba/tests/test_npdatetime.py +++ numba-0.57.1/numba/tests/test_npdatetime.py @@ -411,10 +411,18 @@ class TestTimedeltaArithmetic(TestCase): check(TD('Nat', 'ms'), TD('Nat', 's'), True) check(TD('Nat'), TD(1), False) # Incompatible units => timedeltas compare unequal - check(TD(1, 'Y'), TD(365, 'D'), False) - check(TD(1, 'Y'), TD(366, 'D'), False) - # ... except when both are NaT! - check(TD('NaT', 'W'), TD('NaT', 'D'), True) + if numpy_version < (1, 25): + check(TD(1, 'Y'), TD(365, 'D'), False) + check(TD(1, 'Y'), TD(366, 'D'), False) + # ... except when both are NaT! + check(TD('NaT', 'W'), TD('NaT', 'D'), True) + else: + # incompatible units raise + # The exception is different depending on Python mode + with self.assertRaises((TypeError, TypingError)): + eq(TD(1, 'Y'), TD(365, 'D')) + with self.assertRaises((TypeError, TypingError)): + ne(TD(1, 'Y'), TD(365, 'D')) def test_lt_ge(self): lt = self.jit(lt_usecase) Index: numba-0.57.1/numba/tests/test_ufuncs.py =================================================================== --- numba-0.57.1.orig/numba/tests/test_ufuncs.py +++ numba-0.57.1/numba/tests/test_ufuncs.py @@ -256,6 +256,56 @@ class BasicUFuncTest(BaseUFuncTest): else: raise + def signed_unsigned_cmp_test(self, comparison_ufunc): + self.basic_ufunc_test(comparison_ufunc) + + if numpy_support.numpy_version < (1, 25): + return + + # Test additional implementations that specifically handle signed / + # unsigned comparisons added in NumPy 1.25: + # https://github.com/numpy/numpy/pull/23713 + additional_inputs = ( + (np.int64(-1), np.uint64(0)), + (np.int64(-1), np.uint64(1)), + (np.int64(0), np.uint64(0)), + (np.int64(0), np.uint64(1)), + (np.int64(1), np.uint64(0)), + (np.int64(1), np.uint64(1)), + + (np.uint64(0), np.int64(-1)), + (np.uint64(0), np.int64(0)), + (np.uint64(0), np.int64(1)), + (np.uint64(1), np.int64(-1)), + (np.uint64(1), np.int64(0)), + (np.uint64(1), np.int64(1)), + + (np.array([-1, -1, 0, 0, 1, 1], dtype=np.int64), + np.array([0, 1, 0, 1, 0, 1], dtype=np.uint64)), + + (np.array([0, 1, 0, 1, 0, 1], dtype=np.uint64), + np.array([-1, -1, 0, 0, 1, 1], dtype=np.int64)) + ) + + pyfunc = self._make_ufunc_usecase(comparison_ufunc) + + for a, b in additional_inputs: + input_types = (typeof(a), typeof(b)) + output_type = types.Array(types.bool_, 1, 'C') + argtys = input_types + (output_type,) + cfunc = self._compile(pyfunc, argtys) + + if isinstance(a, np.ndarray): + result = np.zeros(a.shape, dtype=np.bool_) + else: + result = np.zeros(1, dtype=np.bool_) + + expected = np.zeros_like(result) + + pyfunc(a, b, expected) + cfunc(a, b, result) + np.testing.assert_equal(expected, result) + class TestUFuncs(BasicUFuncTest, TestCase): def basic_int_ufunc_test(self, name=None): @@ -505,22 +555,22 @@ class TestUFuncs(BasicUFuncTest, TestCas ############################################################################ # Comparison functions def test_greater_ufunc(self): - self.basic_ufunc_test(np.greater) + self.signed_unsigned_cmp_test(np.greater) def test_greater_equal_ufunc(self): - self.basic_ufunc_test(np.greater_equal) + self.signed_unsigned_cmp_test(np.greater_equal) def test_less_ufunc(self): - self.basic_ufunc_test(np.less) + self.signed_unsigned_cmp_test(np.less) def test_less_equal_ufunc(self): - self.basic_ufunc_test(np.less_equal) + self.signed_unsigned_cmp_test(np.less_equal) def test_not_equal_ufunc(self): - self.basic_ufunc_test(np.not_equal) + self.signed_unsigned_cmp_test(np.not_equal) def test_equal_ufunc(self): - self.basic_ufunc_test(np.equal) + self.signed_unsigned_cmp_test(np.equal) def test_logical_and_ufunc(self): self.basic_ufunc_test(np.logical_and) Index: numba-0.57.1/numba/__init__.py =================================================================== --- numba-0.57.1.orig/numba/__init__.py +++ numba-0.57.1/numba/__init__.py @@ -38,8 +38,9 @@ def _ensure_critical_deps(): msg = (f"Numba needs NumPy 1.21 or greater. Got NumPy " f"{numpy_version[0]}.{numpy_version[1]}.") raise ImportError(msg) - elif numpy_version > (1, 24): - raise ImportError("Numba needs NumPy 1.24 or less") + elif numpy_version > (1, 25): + # https://github.com/numba/numba/pull/9138 + raise ImportError("Numba needs NumPy 1.25 or less") try: import scipy except ImportError: Index: numba-0.57.1/setup.py =================================================================== --- numba-0.57.1.orig/setup.py +++ numba-0.57.1/setup.py @@ -23,7 +23,8 @@ min_python_version = "3.8" max_python_version = "3.12" # exclusive min_numpy_build_version = "1.11" min_numpy_run_version = "1.21" -max_numpy_run_version = "1.25" +# https://github.com/numba/numba/pull/9138 +max_numpy_run_version = "1.26" min_llvmlite_version = "0.40.0dev0" max_llvmlite_version = "0.41"