Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation and test updates to support NumPy 1.25 #9011

Closed
wants to merge 29 commits into from
Closed
Changes from 7 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
614a1cb
Implementation and test updates to support NumPy 1.25
apmasell Jun 12, 2023
7db7e99
Improve implementation mixed sign comparison ufuncs
apmasell Jun 13, 2023
b11bafb
Revert sin/cos changes for NumPy 1.25
apmasell Jun 20, 2023
ac919ca
Add NumPy 1.25 test environment
apmasell Jun 20, 2023
d7162f5
Use conda-forge package only for NumPy 1.25
apmasell Jun 27, 2023
e338e22
Rename mixed signedness code and reference original
apmasell Jun 27, 2023
5e3ff5e
Remove dependency on `umath_tests`
apmasell Jun 27, 2023
0ef226b
Revert version change
apmasell Jun 28, 2023
6d779e5
Switch to Anaconda-built NumPy
apmasell Jul 5, 2023
bde1ec5
Update numba/cpython/numbers.py
apmasell Jul 6, 2023
e8fe800
Update numba/cpython/numbers.py
apmasell Jul 6, 2023
47550a5
Update gpuCI config for NumPy 1.25
apmasell Jul 6, 2023
ccbb814
Remove NumPy 1.21 tests
apmasell Jul 6, 2023
ca6de9e
Remove channel selection for NumPy in Azure
apmasell Jul 6, 2023
1a3b8af
Update installation docs for Numba 0.58
apmasell Jul 6, 2023
3925a82
Merge remote-tracking branch 'origin/main' into numpy_1.25
apmasell Jul 6, 2023
7336691
Restore changes to fancy indexing test
apmasell Jul 7, 2023
0596c21
Change date comparison behaviour to match NumPy 1.25
apmasell Jul 7, 2023
1a1c7c1
Replace `numpy.amin` with `numpy.min` for 1.25
apmasell Jul 10, 2023
56d1da0
Bind deprecated array functions
apmasell Jul 11, 2023
f4cfb3f
Add additional tests for `amin` and `amax`
apmasell Jul 11, 2023
93ac652
Merge remote-tracking branch 'origin/main' into numpy_1.25
apmasell Jul 12, 2023
55855d7
Add mixed signedness ufuncs to CUDA
apmasell Jul 12, 2023
8f47d8c
Change array overloads for NumPy 1.25
apmasell Jul 13, 2023
989e81d
Test signed / unsigned comparisons in basic ufunc tests
gmarkall Jul 26, 2023
eb74738
Merge branch 'main' into numpy_1.25
gmarkall Jul 27, 2023
3f46ed1
Use Python 3.10 for gpuCI
gmarkall Jul 27, 2023
443c2ff
gpuCI: Use Python 3.10 environment in 3.8 image
gmarkall Jul 27, 2023
0c086cf
Use round_
apmasell Jul 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ trigger:

variables:
# Change the following along with adding new TEST_START_INDEX.
TEST_COUNT: 20
TEST_COUNT: 23

jobs:
# Mac and Linux use the same template with different matrixes
@@ -89,36 +89,51 @@ jobs:
NUMPY: '1.24'
CONDA_ENV: azure_ci
TEST_START_INDEX: 11
py39_np125:
PYTHON: '3.9'
NUMPY: '1.25'
CONDA_ENV: azure_ci
TEST_START_INDEX: 12
py310_np121:
PYTHON: '3.10'
NUMPY: '1.21'
CONDA_ENV: azure_ci
TEST_START_INDEX: 12
TEST_START_INDEX: 13
py310_np122:
PYTHON: '3.10'
NUMPY: '1.22'
CONDA_ENV: azure_ci
TEST_START_INDEX: 13
TEST_START_INDEX: 14
py310_np123:
PYTHON: '3.10'
NUMPY: '1.23'
CONDA_ENV: azure_ci
TEST_START_INDEX: 14
TEST_START_INDEX: 15
py310_np124:
PYTHON: '3.10'
NUMPY: '1.24'
CONDA_ENV: azure_ci
TEST_START_INDEX: 15
TEST_START_INDEX: 16
py310_np125:
PYTHON: '3.10'
NUMPY: '1.25'
CONDA_ENV: azure_ci
TEST_START_INDEX: 17
py311_np123:
PYTHON: '3.11'
NUMPY: '1.23'
CONDA_ENV: azure_ci
TEST_START_INDEX: 16
TEST_START_INDEX: 18
py311_np124:
PYTHON: '3.11'
NUMPY: '1.24'
CONDA_ENV: azure_ci
TEST_START_INDEX: 17
TEST_START_INDEX: 19
py311_np125:
PYTHON: '3.11'
NUMPY: '1.25'
CONDA_ENV: azure_ci
TEST_START_INDEX: 20

- template: buildscripts/azure/azure-windows.yml
parameters:
4 changes: 2 additions & 2 deletions buildscripts/azure/azure-windows.yml
Original file line number Diff line number Diff line change
@@ -12,12 +12,12 @@ jobs:
PYTHON: '3.8'
NUMPY: '1.21'
CONDA_ENV: 'testenv'
TEST_START_INDEX: 18
TEST_START_INDEX: 21
py311_np124:
PYTHON: '3.11'
NUMPY: '1.24'
CONDA_ENV: 'testenv'
TEST_START_INDEX: 19
TEST_START_INDEX: 22

steps:
- task: CondaEnvironment@1
4 changes: 2 additions & 2 deletions buildscripts/incremental/setup_conda_environment.cmd
Original file line number Diff line number Diff line change
@@ -14,9 +14,9 @@ cmd /C conda info
set CONDA_INSTALL=cmd /C conda install -q -y
set PIP_INSTALL=pip install -q

@rem Use conda-forge for NumPy 1.24 - at the time of writing it is not available
@rem Use conda-forge for NumPy 1.25 - at the time of writing it is not available
@rem on the defaults channel.
if %NUMPY%==1.24 (set NUMPY_CHANNEL_PKG="conda-forge::numpy") else (set NUMPY_CHANNEL_PKG="numpy")
if %NUMPY%==1.25 (set NUMPY_CHANNEL_PKG="conda-forge::numpy") else (set NUMPY_CHANNEL_PKG="numpy")

@echo on

4 changes: 2 additions & 2 deletions buildscripts/incremental/setup_conda_environment.sh
Original file line number Diff line number Diff line change
@@ -27,10 +27,10 @@ source deactivate
# Display root environment (for debugging)
conda list

# Use conda-forge for NumPy 1.24 - at the time of writing it is not available
# Use conda-forge for NumPy 1.25 - at the time of writing it is not available
# on the defaults channel.

if [ "${NUMPY}" == "1.24" ]; then
if [ "${NUMPY}" == "1.25" ]; then
NUMPY_CHANNEL_PKG=conda-forge::numpy
else
NUMPY_CHANNEL_PKG=numpy
2 changes: 1 addition & 1 deletion numba/__init__.py
Original file line number Diff line number Diff line change
@@ -142,7 +142,7 @@ def test(argv, **kwds):
""".split() + types.__all__ + errors.__all__


_min_llvmlite_version = (0, 41, 0)
_min_llvmlite_version = (0, 40, 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this accidentally added?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. Yes.

_min_llvm_version = (14, 0, 0)

def _ensure_llvm():
33 changes: 33 additions & 0 deletions numba/cpython/numbers.py
Original file line number Diff line number Diff line change
@@ -361,6 +361,39 @@ def int_ne_impl(context, builder, sig, args):
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 entirely too clever. It's taken from the NumPy source.
gmarkall marked this conversation as resolved.
Show resolved Hide resolved
apmasell marked this conversation as resolved.
Show resolved Hide resolved
# 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this link - I appreciate the link to the PR because it also gives the context for the addition to NumPy, which is nice.

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
# This code is entirely too clever. See the sister implementation for
# details
apmasell marked this conversation as resolved.
Show resolved Hide resolved
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)
13 changes: 6 additions & 7 deletions numba/cuda/tests/cudapy/test_gufunc.py
Original file line number Diff line number Diff line change
@@ -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 @@ def test_gufunc_small(self):
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 @@ def test_gufunc_auto_transfer(self):
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 @@ def test_gufunc(self):
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 @@ def test_gufunc_hidim(self):
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 @@ def test_gufunc_new_axis(self):
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 @@ def test_gufunc_stream(self):
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))

24 changes: 24 additions & 0 deletions numba/np/ufunc_db.py
Original file line number Diff line number Diff line change
@@ -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):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: these functions are automatically tested by numba.tests.test_ufuncs as the ufunc_db is parsed to generate those tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is happening - there don't appear to be any tests generated that involve qQ or Qq:

$ python runtests.py numba.tests.test_ufuncs -l | egrep "(qQ|Qq)"
$

(i.e. no tests with signed / unsigned are generated).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, BasicUFuncTest.basic_ufunc_test() isn't set up to test binary functions with inputs of different types - it is set up to assume arguments are homogeneous in type:

for input_tuple in inputs:
input_operand = input_tuple[0]
input_type = input_tuple[1]
is_tuple = isinstance(input_operand, tuple)
if is_tuple:
args = input_operand
else:
args = (input_operand,) * ufunc.nin

(there is only one input_type)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My "egrep" check earlier was run erroneously because I didn't have NumPy 1.25 in my environment. The TestLoopTypes test classes were generated qQ and Qq variants of the tests. However, the BasicUFuncTest class didn't handle these combinations of types, so it was not testing on CUDA.

I tried experimenting with adding testing of these types to the BasicUFuncTest class as well - the commit gmarkall@865cfc6 on the branch https://github.com/gmarkall/numba/tree/numpy_1.25 implements this (and therefore tests these implementations with CUDA too) - feel free to pick it up / modify it if you'd like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cherry-picked.

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,
5 changes: 2 additions & 3 deletions numba/tests/npyufunc/test_gufunc.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
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 @@ def check_matmul_gufunc(self, gufunc):
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)