From 405c20513ba08cfe2a67f92822ed1f4ed9579a64 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 18 Jan 2024 17:05:24 -0700 Subject: [PATCH 1/8] Add changelog entries for 1.4.1 release --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e107a63f..ddc173b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +# 1.4.1 (2024-01-18) + +## Minor Changes + +- Add support for the upcoming NumPy 2.0 release. + +- Added a torch wrapper for `trace` (`torch.trace` doesn't support the + `offset` argument or stacking) + +- Wrap numpy, cupy, and torch `nonzero` to raise an error for zero-dimensional + input arrays. + +- Add torch wrapper for `newaxis`. + +- Improve error message for `array_namespace` + +- Fix linalg.cholesky returning the conjugate of the expected upper + decomposition for numpy and cupy. + # 1.4 (2023-09-13) ## Major Changes From fb3bb9d0bdf44972f69931890a54a77cdb8d7140 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 18 Jan 2024 18:37:33 -0700 Subject: [PATCH 2/8] Don't wrap vecdot, isdtype, and vector_norm if they are already defined --- array_api_compat/cupy/_aliases.py | 13 +++++++++++-- array_api_compat/cupy/linalg.py | 8 +++++++- array_api_compat/numpy/_aliases.py | 13 +++++++++++-- array_api_compat/numpy/linalg.py | 8 +++++++- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/array_api_compat/cupy/_aliases.py b/array_api_compat/cupy/_aliases.py index da2ebf03..90a82cf4 100644 --- a/array_api_compat/cupy/_aliases.py +++ b/array_api_compat/cupy/_aliases.py @@ -61,8 +61,17 @@ matmul = get_xp(cp)(_aliases.matmul) matrix_transpose = get_xp(cp)(_aliases.matrix_transpose) tensordot = get_xp(cp)(_aliases.tensordot) -vecdot = get_xp(cp)(_aliases.vecdot) -isdtype = get_xp(cp)(_aliases.isdtype) + +# These functions are completely new here. If the library already has them +# (i.e., numpy 2.0), use the library version instead of our wrapper. +if hasattr(cp, 'vecdot'): + vecdot = get_xp(cp)(_aliases.vecdot) +else: + vecdot = cp.vecdot +if hasattr(cp, 'isdtype'): + isdtype = cp.isdtype +else: + isdtype = get_xp(cp)(_aliases.isdtype) __all__ = _aliases.__all__ + ['asarray', 'asarray_cupy', 'bool', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', diff --git a/array_api_compat/cupy/linalg.py b/array_api_compat/cupy/linalg.py index 99c4cc68..84752e1a 100644 --- a/array_api_compat/cupy/linalg.py +++ b/array_api_compat/cupy/linalg.py @@ -29,10 +29,16 @@ pinv = get_xp(cp)(_linalg.pinv) matrix_norm = get_xp(cp)(_linalg.matrix_norm) svdvals = get_xp(cp)(_linalg.svdvals) -vector_norm = get_xp(cp)(_linalg.vector_norm) diagonal = get_xp(cp)(_linalg.diagonal) trace = get_xp(cp)(_linalg.trace) +# These functions are completely new here. If the library already has them +# (i.e., numpy 2.0), use the library version instead of our wrapper. +if hasattr(cp.linalg, 'vector_norm'): + vector_norm = cp.linalg.vector_norm +else: + vector_norm = get_xp(cp)(_linalg.vector_norm) + __all__ = linalg_all + _linalg.__all__ del get_xp diff --git a/array_api_compat/numpy/_aliases.py b/array_api_compat/numpy/_aliases.py index 633b2f62..e65c7124 100644 --- a/array_api_compat/numpy/_aliases.py +++ b/array_api_compat/numpy/_aliases.py @@ -61,8 +61,17 @@ matmul = get_xp(np)(_aliases.matmul) matrix_transpose = get_xp(np)(_aliases.matrix_transpose) tensordot = get_xp(np)(_aliases.tensordot) -vecdot = get_xp(np)(_aliases.vecdot) -isdtype = get_xp(np)(_aliases.isdtype) + +# These functions are completely new here. If the library already has them +# (i.e., numpy 2.0), use the library version instead of our wrapper. +if hasattr(np, 'vecdot'): + vecdot = get_xp(np)(_aliases.vecdot) +else: + vecdot = np.vecdot +if hasattr(np, 'isdtype'): + isdtype = np.isdtype +else: + isdtype = get_xp(np)(_aliases.isdtype) __all__ = _aliases.__all__ + ['asarray', 'asarray_numpy', 'bool', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', diff --git a/array_api_compat/numpy/linalg.py b/array_api_compat/numpy/linalg.py index 26d6e88e..39997df8 100644 --- a/array_api_compat/numpy/linalg.py +++ b/array_api_compat/numpy/linalg.py @@ -22,10 +22,16 @@ pinv = get_xp(np)(_linalg.pinv) matrix_norm = get_xp(np)(_linalg.matrix_norm) svdvals = get_xp(np)(_linalg.svdvals) -vector_norm = get_xp(np)(_linalg.vector_norm) diagonal = get_xp(np)(_linalg.diagonal) trace = get_xp(np)(_linalg.trace) +# These functions are completely new here. If the library already has them +# (i.e., numpy 2.0), use the library version instead of our wrapper. +if hasattr(np.linalg, 'vector_norm'): + vector_norm = np.linalg.vector_norm +else: + vector_norm = get_xp(np)(_linalg.vector_norm) + __all__ = linalg_all + _linalg.__all__ del get_xp From 2bcc8e624a61133b506b6a20ccef0e478af0ffc9 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 18 Jan 2024 18:44:42 -0700 Subject: [PATCH 3/8] Fix inverted logic typo --- array_api_compat/cupy/_aliases.py | 4 ++-- array_api_compat/numpy/_aliases.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/array_api_compat/cupy/_aliases.py b/array_api_compat/cupy/_aliases.py index 90a82cf4..d1d3cda9 100644 --- a/array_api_compat/cupy/_aliases.py +++ b/array_api_compat/cupy/_aliases.py @@ -65,9 +65,9 @@ # These functions are completely new here. If the library already has them # (i.e., numpy 2.0), use the library version instead of our wrapper. if hasattr(cp, 'vecdot'): - vecdot = get_xp(cp)(_aliases.vecdot) -else: vecdot = cp.vecdot +else: + vecdot = get_xp(cp)(_aliases.vecdot) if hasattr(cp, 'isdtype'): isdtype = cp.isdtype else: diff --git a/array_api_compat/numpy/_aliases.py b/array_api_compat/numpy/_aliases.py index e65c7124..e7d4a1be 100644 --- a/array_api_compat/numpy/_aliases.py +++ b/array_api_compat/numpy/_aliases.py @@ -65,9 +65,9 @@ # These functions are completely new here. If the library already has them # (i.e., numpy 2.0), use the library version instead of our wrapper. if hasattr(np, 'vecdot'): - vecdot = get_xp(np)(_aliases.vecdot) -else: vecdot = np.vecdot +else: + vecdot = get_xp(np)(_aliases.vecdot) if hasattr(np, 'isdtype'): isdtype = np.isdtype else: From 58098ec92eb38e6b91d4cf73cede8bca21339908 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 18 Jan 2024 22:30:54 -0700 Subject: [PATCH 4/8] Disable the deadline for the cupy tests --- test_cupy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_cupy.sh b/test_cupy.sh index a8f61a8c..1f832d2e 100755 --- a/test_cupy.sh +++ b/test_cupy.sh @@ -12,7 +12,7 @@ tmpdir=$(mktemp -d) SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) export PYTHONPATH=$SCRIPT_DIR -PYTEST_ARGS="--max-examples 200 -v -rxXfE --ci" +PYTEST_ARGS="--max-examples 200 -v -rxXfE --ci --hypothesis-disable-deadline" cd $tmpdir git clone https://github.com/data-apis/array-api-tests From 787b14f020aac9def9230975c10aa5b1f878e5cb Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 19 Jan 2024 14:47:03 -0700 Subject: [PATCH 5/8] Remove xfail for test_square https://github.com/data-apis/array-api-tests/issues/190 has been fixed. --- cupy-xfails.txt | 4 ---- numpy-1-21-xfails.txt | 28 ++++++++++++---------------- numpy-xfails.txt | 4 ---- torch-xfails.txt | 4 ---- 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/cupy-xfails.txt b/cupy-xfails.txt index 6e34c650..5fcc9d23 100644 --- a/cupy-xfails.txt +++ b/cupy-xfails.txt @@ -56,10 +56,6 @@ array_api_tests/test_statistical_functions.py::test_max # (https://github.com/data-apis/array-api-tests/issues/171) array_api_tests/test_signatures.py::test_func_signature[meshgrid] -# testsuite issue with test_square -# https://github.com/data-apis/array-api-tests/issues/190 -array_api_tests/test_operators_and_elementwise_functions.py::test_square - # We cannot add array attributes array_api_tests/test_signatures.py::test_array_method_signature[__array_namespace__] array_api_tests/test_signatures.py::test_array_method_signature[__index__] diff --git a/numpy-1-21-xfails.txt b/numpy-1-21-xfails.txt index 4cebd0f7..9a0d2827 100644 --- a/numpy-1-21-xfails.txt +++ b/numpy-1-21-xfails.txt @@ -50,9 +50,18 @@ array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -infinity and x array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] array_api_tests/meta/test_hypothesis_helpers.py::test_symmetric_matrices -# testsuite issue with test_square -# https://github.com/data-apis/array-api-tests/issues/190 -array_api_tests/test_operators_and_elementwise_functions.py::test_square +# fft functions are not yet supported +# (https://github.com/data-apis/array-api-compat/issues/67) +array_api_tests/test_fft.py::test_fft +array_api_tests/test_fft.py::test_ifft +array_api_tests/test_fft.py::test_fftn +array_api_tests/test_fft.py::test_ifftn +array_api_tests/test_fft.py::test_rfft +array_api_tests/test_fft.py::test_irfft +array_api_tests/test_fft.py::test_rfftn +array_api_tests/test_fft.py::test_irfftn +array_api_tests/test_fft.py::test_hfft +array_api_tests/test_fft.py::test_ihfft # NumPy 1.21 specific XFAILS ############################ @@ -236,16 +245,3 @@ array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is +0 and x2_i array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is -0 and x2_i < 0) -> -0] array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is -0 and x2_i > 0) -> +0] array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is -0 and x2_i is -0) -> -0] - -# fft functions are not yet supported -# (https://github.com/data-apis/array-api-compat/issues/67) -array_api_tests/test_fft.py::test_fft -array_api_tests/test_fft.py::test_ifft -array_api_tests/test_fft.py::test_fftn -array_api_tests/test_fft.py::test_ifftn -array_api_tests/test_fft.py::test_rfft -array_api_tests/test_fft.py::test_irfft -array_api_tests/test_fft.py::test_rfftn -array_api_tests/test_fft.py::test_irfftn -array_api_tests/test_fft.py::test_hfft -array_api_tests/test_fft.py::test_ihfft diff --git a/numpy-xfails.txt b/numpy-xfails.txt index 1de2f755..c541602b 100644 --- a/numpy-xfails.txt +++ b/numpy-xfails.txt @@ -40,10 +40,6 @@ array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0] array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0] -# testsuite issue with test_square -# https://github.com/data-apis/array-api-tests/issues/190 -array_api_tests/test_operators_and_elementwise_functions.py::test_square - # https://github.com/numpy/numpy/issues/21213 array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -infinity and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] diff --git a/torch-xfails.txt b/torch-xfails.txt index 69932f2a..caf1aa65 100644 --- a/torch-xfails.txt +++ b/torch-xfails.txt @@ -171,10 +171,6 @@ array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is +0 and x2_i < 0 array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is -0 and x2_i > 0) -> +0] array_api_tests/test_special_cases.py::test_unary[sign(x_i is NaN) -> NaN] -# testsuite issue with test_square -# https://github.com/data-apis/array-api-tests/issues/190 -array_api_tests/test_operators_and_elementwise_functions.py::test_square - # Float correction is not supported by pytorch # (https://github.com/data-apis/array-api-tests/issues/168) array_api_tests/test_special_cases.py::test_empty_arrays[std] From 9755c26f75d6448df2d8c1531d5451988e7ca8de Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 19 Jan 2024 14:48:17 -0700 Subject: [PATCH 6/8] Add sign(NaN) XFAIL for cupy --- cupy-xfails.txt | 179 ++++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 89 deletions(-) diff --git a/cupy-xfails.txt b/cupy-xfails.txt index 5fcc9d23..ab4ba62f 100644 --- a/cupy-xfails.txt +++ b/cupy-xfails.txt @@ -63,8 +63,96 @@ array_api_tests/test_signatures.py::test_array_method_signature[to_device] # We do not attempt to workaround special cases (and the operator method ones -array_api_tests/test_special_cases.py::test_unary[abs(x_i is -0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__add__(isfinite(x1_i) and x1_i != 0 and x2_i == -x1_i) -> +0] +array_api_tests/test_special_cases.py::test_binary[__add__(x1_i is +0 and x2_i is -0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__add__(x1_i is -0 and x2_i is +0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__add__(x1_i is -0 and x2_i is -0) -> -0] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i < 0 and x2_i is -0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i > 0 and x2_i is -0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -0 and x2_i < 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -0 and x2_i > 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> x2_i] +array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i < 0 and x2_i is -infinity) -> x1_i] +array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i > 0 and x2_i is +infinity) -> x1_i] +array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> x2_i] +array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i < 0 and x2_i is -0) -> NaN] +array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i > 0 and x2_i is -0) -> NaN] +array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is +0 and x2_i < 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is +0 and x2_i > 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is -0 and x2_i < 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is -0 and x2_i > 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i < 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i < 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] +array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i > 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -0] +array_api_tests/test_special_cases.py::test_binary[__pow__(x2_i is -0) -> 1] +array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i < 0 and x2_i is -0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i > 0 and x2_i is -0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i is -0 and x2_i < 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i is -0 and x2_i > 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[add(isfinite(x1_i) and x1_i != 0 and x2_i == -x1_i) -> +0] +array_api_tests/test_special_cases.py::test_binary[add(x1_i is +0 and x2_i is -0) -> +0] +array_api_tests/test_special_cases.py::test_binary[add(x1_i is -0 and x2_i is +0) -> +0] +array_api_tests/test_special_cases.py::test_binary[add(x1_i is -0 and x2_i is -0) -> -0] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i < 0 and x2_i is -0) -> roughly -pi/2] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i > 0 and x2_i is -0) -> roughly +pi/2] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is +0 and x2_i is -0) -> roughly +pi] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i < 0) -> roughly -pi] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i > 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i is +0) -> -0] +array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i is -0) -> roughly -pi] +array_api_tests/test_special_cases.py::test_binary[divide(x1_i < 0 and x2_i is -0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[divide(x1_i > 0 and x2_i is -0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[divide(x1_i is -0 and x2_i < 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[divide(x1_i is -0 and x2_i > 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i < 0 and x2_i is -0) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i > 0 and x2_i is -0) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -0 and x2_i < 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -0 and x2_i > 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i < 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] +array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i < 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -infinity] +array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] +array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i > 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -0] +array_api_tests/test_special_cases.py::test_binary[pow(x2_i is -0) -> 1] +array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> x2_i] +array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i < 0 and x2_i is -infinity) -> x1_i] +array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i > 0 and x2_i is +infinity) -> x1_i] +array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> x2_i] +array_api_tests/test_special_cases.py::test_binary[remainder(x1_i < 0 and x2_i is -0) -> NaN] +array_api_tests/test_special_cases.py::test_binary[remainder(x1_i > 0 and x2_i is -0) -> NaN] +array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is +0 and x2_i < 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is +0 and x2_i > 0) -> +0] +array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is -0 and x2_i < 0) -> -0] +array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is -0 and x2_i > 0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__iadd__(isfinite(x1_i) and x1_i != 0 and x2_i == -x1_i) -> +0] +array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is +0 and x2_i is -0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is -0 and x2_i is +0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is -0 and x2_i is -0) -> -0] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i < 0 and x2_i is -0) -> +infinity] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i > 0 and x2_i is -0) -> -infinity] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -0 and x2_i < 0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -0 and x2_i > 0) -> -0] +array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> x2_i] +array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i < 0 and x2_i is -infinity) -> x1_i] +array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i > 0 and x2_i is +infinity) -> x1_i] +array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> x2_i] +array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i < 0 and x2_i is -0) -> NaN] +array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i > 0 and x2_i is -0) -> NaN] +array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is +0 and x2_i < 0) -> -0] +array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is +0 and x2_i > 0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is -0 and x2_i < 0) -> -0] +array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is -0 and x2_i > 0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i < 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i < 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -infinity] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i > 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -0] +array_api_tests/test_special_cases.py::test_iop[__ipow__(x2_i is -0) -> 1] +array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i < 0 and x2_i is -0) -> +infinity] +array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i > 0 and x2_i is -0) -> -infinity] +array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i is -0 and x2_i < 0) -> +0] +array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i is -0 and x2_i > 0) -> -0] array_api_tests/test_special_cases.py::test_unary[__abs__(x_i is -0) -> +0] +array_api_tests/test_special_cases.py::test_unary[abs(x_i is -0) -> +0] array_api_tests/test_special_cases.py::test_unary[asin(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[asinh(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[atan(x_i is -0) -> -0] @@ -77,100 +165,13 @@ array_api_tests/test_special_cases.py::test_unary[expm1(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[floor(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[log1p(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[round(x_i is -0) -> -0] +array_api_tests/test_special_cases.py::test_unary[sign(x_i is NaN) -> NaN] array_api_tests/test_special_cases.py::test_unary[sin(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[sinh(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[sqrt(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[tan(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[tanh(x_i is -0) -> -0] array_api_tests/test_special_cases.py::test_unary[trunc(x_i is -0) -> -0] -array_api_tests/test_special_cases.py::test_binary[add(x1_i is -0 and x2_i is -0) -> -0] -array_api_tests/test_special_cases.py::test_binary[add(x1_i is -0 and x2_i is +0) -> +0] -array_api_tests/test_special_cases.py::test_binary[add(x1_i is +0 and x2_i is -0) -> +0] -array_api_tests/test_special_cases.py::test_binary[add(isfinite(x1_i) and x1_i != 0 and x2_i == -x1_i) -> +0] -array_api_tests/test_special_cases.py::test_binary[__add__(x1_i is -0 and x2_i is -0) -> -0] -array_api_tests/test_special_cases.py::test_binary[__add__(x1_i is -0 and x2_i is +0) -> +0] -array_api_tests/test_special_cases.py::test_binary[__add__(x1_i is +0 and x2_i is -0) -> +0] -array_api_tests/test_special_cases.py::test_binary[__add__(isfinite(x1_i) and x1_i != 0 and x2_i == -x1_i) -> +0] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i > 0 and x2_i is -0) -> roughly +pi/2] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is +0 and x2_i is -0) -> roughly +pi] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i is +0) -> -0] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i is -0) -> roughly -pi] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i is -0 and x2_i < 0) -> roughly -pi] -array_api_tests/test_special_cases.py::test_binary[atan2(x1_i < 0 and x2_i is -0) -> roughly -pi/2] -array_api_tests/test_special_cases.py::test_binary[divide(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[divide(x1_i is -0 and x2_i < 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[divide(x1_i > 0 and x2_i is -0) -> -infinity] -array_api_tests/test_special_cases.py::test_binary[divide(x1_i < 0 and x2_i is -0) -> +infinity] -array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i is -0 and x2_i < 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i > 0 and x2_i is -0) -> -infinity] -array_api_tests/test_special_cases.py::test_binary[__truediv__(x1_i < 0 and x2_i is -0) -> +infinity] -array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -0 and x2_i < 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i > 0 and x2_i is -0) -> -infinity] -array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i < 0 and x2_i is -0) -> +infinity] -array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i is -0 and x2_i < 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i > 0 and x2_i is -0) -> -infinity] -array_api_tests/test_special_cases.py::test_binary[__floordiv__(x1_i < 0 and x2_i is -0) -> +infinity] -array_api_tests/test_special_cases.py::test_binary[pow(x2_i is -0) -> 1] -array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i > 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -0] -array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] -array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i < 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -infinity] -array_api_tests/test_special_cases.py::test_binary[pow(x1_i is -0 and x2_i < 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] -array_api_tests/test_special_cases.py::test_binary[__pow__(x2_i is -0) -> 1] -array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i > 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -0] -array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] -array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i < 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -infinity] -array_api_tests/test_special_cases.py::test_binary[__pow__(x1_i is -0 and x2_i < 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] -array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is +0 and x2_i > 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is -0 and x2_i > 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is +0 and x2_i < 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[remainder(x1_i is -0 and x2_i < 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[remainder(x1_i > 0 and x2_i is -0) -> NaN] -array_api_tests/test_special_cases.py::test_binary[remainder(x1_i < 0 and x2_i is -0) -> NaN] -array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i > 0 and x2_i is +infinity) -> x1_i] -array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> x2_i] -array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> x2_i] -array_api_tests/test_special_cases.py::test_binary[remainder(isfinite(x1_i) and x1_i < 0 and x2_i is -infinity) -> x1_i] -array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is +0 and x2_i > 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is -0 and x2_i > 0) -> +0] -array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is +0 and x2_i < 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i is -0 and x2_i < 0) -> -0] -array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i > 0 and x2_i is -0) -> NaN] -array_api_tests/test_special_cases.py::test_binary[__mod__(x1_i < 0 and x2_i is -0) -> NaN] -array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i > 0 and x2_i is +infinity) -> x1_i] -array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> x2_i] -array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> x2_i] -array_api_tests/test_special_cases.py::test_binary[__mod__(isfinite(x1_i) and x1_i < 0 and x2_i is -infinity) -> x1_i] -array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is -0 and x2_i is -0) -> -0] -array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is -0 and x2_i is +0) -> +0] -array_api_tests/test_special_cases.py::test_iop[__iadd__(x1_i is +0 and x2_i is -0) -> +0] -array_api_tests/test_special_cases.py::test_iop[__iadd__(isfinite(x1_i) and x1_i != 0 and x2_i == -x1_i) -> +0] -array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i is -0 and x2_i < 0) -> +0] -array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i > 0 and x2_i is -0) -> -infinity] -array_api_tests/test_special_cases.py::test_iop[__itruediv__(x1_i < 0 and x2_i is -0) -> +infinity] -array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -0 and x2_i > 0) -> -0] -array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -0 and x2_i < 0) -> +0] -array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i > 0 and x2_i is -0) -> -infinity] -array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i < 0 and x2_i is -0) -> +infinity] -array_api_tests/test_special_cases.py::test_iop[__ipow__(x2_i is -0) -> 1] -array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i > 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -0] -array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i > 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +0] -array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i < 0 and x2_i.is_integer() and x2_i % 2 == 1) -> -infinity] -array_api_tests/test_special_cases.py::test_iop[__ipow__(x1_i is -0 and x2_i < 0 and not (x2_i.is_integer() and x2_i % 2 == 1)) -> +infinity] -array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is +0 and x2_i > 0) -> +0] -array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is -0 and x2_i > 0) -> +0] -array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is +0 and x2_i < 0) -> -0] -array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i is -0 and x2_i < 0) -> -0] -array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i > 0 and x2_i is -0) -> NaN] -array_api_tests/test_special_cases.py::test_iop[__imod__(x1_i < 0 and x2_i is -0) -> NaN] -array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i > 0 and x2_i is +infinity) -> x1_i] -array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> x2_i] -array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> x2_i] -array_api_tests/test_special_cases.py::test_iop[__imod__(isfinite(x1_i) and x1_i < 0 and x2_i is -infinity) -> x1_i] # fft functions are not yet supported # (https://github.com/data-apis/array-api-compat/issues/67) From 05548f0281f13e7cb6a293a422ef8c1a90021413 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 19 Jan 2024 16:00:19 -0700 Subject: [PATCH 7/8] Bump version to 1.4.1 --- array_api_compat/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/array_api_compat/__init__.py b/array_api_compat/__init__.py index b60dd0d5..28ffc7e7 100644 --- a/array_api_compat/__init__.py +++ b/array_api_compat/__init__.py @@ -17,6 +17,6 @@ this implementation for the default when working with NumPy arrays. """ -__version__ = '1.4' +__version__ = '1.4.1' from .common import * From ad2d852a29f7d797908a879d2b0c7ab47c1a2a47 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 19 Jan 2024 16:08:53 -0700 Subject: [PATCH 8/8] Add releasing instructions to the README --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/README.md b/README.md index b4077747..2c0ce59a 100644 --- a/README.md +++ b/README.md @@ -300,3 +300,54 @@ corresponding document does not yet exist for PyTorch, but you can examine the various comments in the [implementation](https://github.com/data-apis/array-api-compat/blob/main/array_api_compat/torch/_aliases.py) to see what functions and behaviors have been wrapped. + + +## Releasing + +To release, first note that CuPy must be tested manually (it isn't tested on +CI). Use the script + +``` +./test_cupy.sh +``` + +on a machine with a CUDA GPU. + +Once you are ready to release, create a PR with a release branch, so that you +can verify that CI is passing. You must edit + +``` +array_api_compat/__init__.py +``` + +and update the version (the version is not computed from the tag because that +would break vendorability). You should also edit + +``` +CHANGELOG.md +``` + +with the changes for the release. + +Then create a tag + +``` +git tag -a +``` + +and push it to GitHub + +``` +git push origin +``` + +Check that the `publish distributions` action works. Note that this action +will run even if the other CI fails, so you must make sure that CI is passing +*before* tagging. + +This does mean you can ignore CI failures, but ideally you should fix any +failures or update the `*-xfails.txt` files before tagging, so that CI and the +cupy tests pass. Otherwise it will be hard to tell what things are breaking in +the future. It's also a good idea to remove any xpasses from those files (but +be aware that some xfails are from flaky failures, so unless you know the +underlying issue has been fixed, a xpass test is probably still xfail).