Skip to content

Commit cc00aee

Browse files
committed
Merge branch 'main' into clip
2 parents b940c19 + b0cc9dc commit cc00aee

17 files changed

+124
-48
lines changed

.github/workflows/array-api-tests-dask.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,9 @@ jobs:
1010
package-version: '>= 2024.9.0'
1111
module-name: dask.array
1212
extra-requires: numpy
13-
pytest-extra-args: --disable-deadline --max-examples=5
13+
# Dask is substantially slower then other libraries on unit tests.
14+
# Reduce the number of examples to speed up CI, even though this means that this
15+
# workflow is barely more than a smoke test, and one should expect extreme
16+
# flakiness. Before changes to dask-xfails.txt or dask-skips.txt, please run
17+
# the full test suite with at least 200 examples.
18+
pytest-extra-args: --max-examples=5

.github/workflows/array-api-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ on:
3333
description: "Multiline string of environment variables to set for the test run."
3434

3535
env:
36-
PYTEST_ARGS: "--max-examples 200 -v -rxXfE --ci ${{ inputs.pytest-extra-args }} --hypothesis-disable-deadline"
36+
PYTEST_ARGS: "--max-examples 200 -v -rxXfE --ci ${{ inputs.pytest-extra-args }} --hypothesis-disable-deadline --durations 10"
3737

3838
jobs:
3939
tests:

.github/workflows/docs-deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@v4
1515
- name: Download Artifact
16-
uses: dawidd6/action-download-artifact@v8
16+
uses: dawidd6/action-download-artifact@v9
1717
with:
1818
workflow: docs-build.yml
1919
name: docs-build

array_api_compat/cupy/_aliases.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,20 @@ def astype(
125125
return out.copy() if copy and out is x else out
126126

127127

128+
# cupy.count_nonzero does not have keepdims
129+
def count_nonzero(
130+
x: ndarray,
131+
axis=None,
132+
keepdims=False
133+
) -> ndarray:
134+
result = cp.count_nonzero(x, axis)
135+
if keepdims:
136+
if axis is None:
137+
return cp.reshape(result, [1]*x.ndim)
138+
return cp.expand_dims(result, axis)
139+
return result
140+
141+
128142
# These functions are completely new here. If the library already has them
129143
# (i.e., numpy 2.0), use the library version instead of our wrapper.
130144
if hasattr(cp, 'vecdot'):
@@ -146,6 +160,6 @@ def astype(
146160
'acos', 'acosh', 'asin', 'asinh', 'atan',
147161
'atan2', 'atanh', 'bitwise_left_shift',
148162
'bitwise_invert', 'bitwise_right_shift',
149-
'bool', 'concat', 'pow', 'sign']
163+
'bool', 'concat', 'count_nonzero', 'pow', 'sign']
150164

151165
_all_ignore = ['cp', 'get_xp']

array_api_compat/dask/array/_aliases.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,21 @@ def argsort(
335335
return restore(x)
336336

337337

338+
# dask.array.count_nonzero does not have keepdims
339+
def count_nonzero(
340+
x: Array,
341+
axis=None,
342+
keepdims=False
343+
) -> Array:
344+
result = da.count_nonzero(x, axis)
345+
if keepdims:
346+
if axis is None:
347+
return da.reshape(result, [1]*x.ndim)
348+
return da.expand_dims(result, axis)
349+
return result
350+
351+
352+
338353
__all__ = _aliases.__all__ + [
339354
'__array_namespace_info__', 'asarray', 'astype', 'acos',
340355
'acosh', 'asin', 'asinh', 'atan', 'atan2',
@@ -343,6 +358,6 @@ def argsort(
343358
'result_type', 'bool', 'float32', 'float64', 'int8', 'int16', 'int32', 'int64',
344359
'uint8', 'uint16', 'uint32', 'uint64',
345360
'complex64', 'complex128', 'iinfo', 'finfo',
346-
'can_cast', 'result_type']
361+
'can_cast', 'count_nonzero', 'result_type']
347362

348363
_all_ignore = ["Callable", "array_namespace", "get_xp", "da", "np"]

array_api_compat/numpy/_aliases.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,19 @@ def astype(
127127
return x.astype(dtype=dtype, copy=copy)
128128

129129

130+
# count_nonzero returns a python int for axis=None and keepdims=False
131+
# https://github.com/numpy/numpy/issues/17562
132+
def count_nonzero(
133+
x : ndarray,
134+
axis=None,
135+
keepdims=False
136+
) -> ndarray:
137+
result = np.count_nonzero(x, axis=axis, keepdims=keepdims)
138+
if axis is None and not keepdims:
139+
return np.asarray(result)
140+
return result
141+
142+
130143
# These functions are completely new here. If the library already has them
131144
# (i.e., numpy 2.0), use the library version instead of our wrapper.
132145
if hasattr(np, 'vecdot'):
@@ -148,6 +161,6 @@ def astype(
148161
'acos', 'acosh', 'asin', 'asinh', 'atan',
149162
'atan2', 'atanh', 'bitwise_left_shift',
150163
'bitwise_invert', 'bitwise_right_shift',
151-
'bool', 'concat', 'pow']
164+
'bool', 'concat', 'count_nonzero', 'pow']
152165

153166
_all_ignore = ['np', 'get_xp']

array_api_compat/torch/_aliases.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@
33
from functools import wraps as _wraps
44
from builtins import all as _builtin_all, any as _builtin_any
55

6-
from ..common._aliases import (matrix_transpose as _aliases_matrix_transpose,
7-
vecdot as _aliases_vecdot,
8-
clip as _aliases_clip,
9-
unstack as _aliases_unstack,
10-
cumulative_sum as _aliases_cumulative_sum,
11-
cumulative_prod as _aliases_cumulative_prod,
12-
)
6+
from ..common import _aliases
137
from .._internal import get_xp
148

159
from ._info import __array_namespace_info__
@@ -215,10 +209,10 @@ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep
215209
return torch.clone(x)
216210
return torch.amin(x, axis, keepdims=keepdims)
217211

218-
clip = get_xp(torch)(_aliases_clip)
219-
unstack = get_xp(torch)(_aliases_unstack)
220-
cumulative_sum = get_xp(torch)(_aliases_cumulative_sum)
221-
cumulative_prod = get_xp(torch)(_aliases_cumulative_prod)
212+
clip = get_xp(torch)(_aliases.clip)
213+
unstack = get_xp(torch)(_aliases.unstack)
214+
cumulative_sum = get_xp(torch)(_aliases.cumulative_sum)
215+
cumulative_prod = get_xp(torch)(_aliases.cumulative_prod)
222216

223217
# torch.sort also returns a tuple
224218
# https://github.com/pytorch/pytorch/issues/70921
@@ -527,15 +521,22 @@ def diff(
527521
return torch.diff(x, dim=axis, n=n, prepend=prepend, append=append)
528522

529523

530-
# torch uses `dim` instead of `axis`
524+
# torch uses `dim` instead of `axis`, does not have keepdims
531525
def count_nonzero(
532526
x: array,
533527
/,
534528
*,
535529
axis: Optional[Union[int, Tuple[int, ...]]] = None,
536530
keepdims: bool = False,
537531
) -> array:
538-
return torch.count_nonzero(x, dim=axis, keepdims=keepdims)
532+
result = torch.count_nonzero(x, dim=axis)
533+
if keepdims:
534+
if axis is not None:
535+
return result.unsqueeze(axis)
536+
return _axis_none_keepdims(result, x.ndim, keepdims)
537+
else:
538+
return result
539+
539540

540541

541542
def where(condition: array, x1: array, x2: array, /) -> array:
@@ -710,8 +711,8 @@ def matmul(x1: array, x2: array, /, **kwargs) -> array:
710711
x1, x2 = _fix_promotion(x1, x2, only_scalar=False)
711712
return torch.matmul(x1, x2, **kwargs)
712713

713-
matrix_transpose = get_xp(torch)(_aliases_matrix_transpose)
714-
_vecdot = get_xp(torch)(_aliases_vecdot)
714+
matrix_transpose = get_xp(torch)(_aliases.matrix_transpose)
715+
_vecdot = get_xp(torch)(_aliases.vecdot)
715716

716717
def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array:
717718
x1, x2 = _fix_promotion(x1, x2, only_scalar=False)

cupy-xfails.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,5 +191,4 @@ array_api_tests/test_signatures.py::test_func_signature[bitwise_or]
191191
array_api_tests/test_signatures.py::test_func_signature[bitwise_right_shift]
192192
array_api_tests/test_signatures.py::test_func_signature[bitwise_xor]
193193
array_api_tests/test_special_cases.py::test_binary[nextafter(x1_i is +0 and x2_i is -0) -> -0]
194-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
195194

dask-skips.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
# slow and not implemented in dask
2-
array_api_tests/test_linalg.py::test_matrix_power
1+
# NOTE: dask tests run on a very small number of examples in CI due to
2+
# slowness. This causes very high flakiness in the tests.
3+
# Before changing this file, please run with at least 200 examples.
34

4-
# hangs on 2024.12
5+
# Passes, but extremely slow
6+
array_api_tests/test_linalg.py::test_outer
7+
8+
# Hangs
59
array_api_tests/test_creation_functions.py::test_eye

dask-xfails.txt

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# NOTE: dask tests run on a very small number of examples in CI due to
2+
# slowness. This causes very high flakiness in the tests.
3+
# Before changing this file, please run with at least 200 examples.
4+
5+
# Broken edge case with shape 0
6+
# https://github.com/dask/dask/issues/11800
7+
array_api_tests/test_array_object.py::test_setitem
8+
19
# Various indexing errors
210
array_api_tests/test_array_object.py::test_getitem_masking
311

@@ -11,6 +19,9 @@ array_api_tests/test_data_type_functions.py::test_finfo[float32]
1119
# (I think the test is not forcing the op to be computed?)
1220
array_api_tests/test_creation_functions.py::test_linspace
1321

22+
# Shape mismatch
23+
array_api_tests/test_indexing_functions.py::test_take
24+
1425
# Array methods and attributes not already on da.Array cannot be wrapped
1526
array_api_tests/test_has_names.py::test_has_names[array_method-__array_namespace__]
1627
array_api_tests/test_has_names.py::test_has_names[array_method-to_device]
@@ -31,7 +42,7 @@ array_api_tests/test_set_functions.py::test_unique_values
3142
# fails for ndim > 2
3243
array_api_tests/test_linalg.py::test_svdvals
3344

34-
# dtype mismatch got uint64, but should be uint8, NPY_PROMOTION_STATE=weak doesn't help :(
45+
# dtype mismatch got uint64, but should be uint8; NPY_PROMOTION_STATE=weak doesn't help
3546
array_api_tests/test_linalg.py::test_tensordot
3647

3748
# AssertionError: out.dtype=uint64, but should be uint8 [tensordot(uint8, uint8)]
@@ -89,29 +100,29 @@ array_api_tests/meta/test_hypothesis_helpers.py::test_symmetric_matrices
89100
# https://github.com/dask/dask/issues/11706
90101
array_api_tests/test_creation_functions.py::test_arange
91102

103+
# da.searchsorted with a sorter argument is not supported
104+
array_api_tests/test_searching_functions.py::test_searchsorted
105+
92106
# 2023.12 support
93107
array_api_tests/test_manipulation_functions.py::test_repeat
94108

95109
# 2024.12 support
96-
array_api_tests/test_array_object.py::test_setitem
97110
array_api_tests/test_array_object.py::test_getitem_arrays_and_ints_1[1]
98111
array_api_tests/test_array_object.py::test_getitem_arrays_and_ints_1[None]
99112
array_api_tests/test_array_object.py::test_getitem_arrays_and_ints_2[1]
100113
array_api_tests/test_array_object.py::test_getitem_arrays_and_ints_2[None]
101114
array_api_tests/test_has_names.py::test_has_names[indexing-take_along_axis]
115+
array_api_tests/test_signatures.py::test_func_signature[count_nonzero]
102116
array_api_tests/test_signatures.py::test_func_signature[take_along_axis]
103117

104118
array_api_tests/test_linalg.py::test_cholesky
105119
array_api_tests/test_linalg.py::test_linalg_matmul
120+
array_api_tests/test_linalg.py::test_matmul
106121
array_api_tests/test_linalg.py::test_matrix_norm
107122
array_api_tests/test_linalg.py::test_qr
108-
array_api_tests/test_manipulation_functions.py::test_concat
109123
array_api_tests/test_manipulation_functions.py::test_roll
110-
array_api_tests/test_operators_and_elementwise_functions.py::test_add[add(x1, x2)]
111-
array_api_tests/test_operators_and_elementwise_functions.py::test_bitwise_left_shift[bitwise_left_shift(x1, x2)]
112-
array_api_tests/test_operators_and_elementwise_functions.py::test_bitwise_right_shift[bitwise_right_shift(x1, x2)]
113-
array_api_tests/test_operators_and_elementwise_functions.py::test_greater[__gt__(x1, x2)]
114-
array_api_tests/test_signatures.py::test_func_signature[count_nonzero]
124+
125+
# Stubs have a comment: (**note**: libraries may return ``NaN`` to match Python behavior.)
115126
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
116127
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
117128
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]
@@ -130,6 +141,3 @@ array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity
130141
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(x1_i is -infinity and isfinite(x2_i) and x2_i < 0) -> +infinity]
131142
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i > 0 and x2_i is -infinity) -> -0]
132143
array_api_tests/test_special_cases.py::test_iop[__ifloordiv__(isfinite(x1_i) and x1_i < 0 and x2_i is +infinity) -> -0]
133-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
134-
135-

docs/changelog.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
# Changelog
22

3-
## 1.11.0 (2025-XX-XX)
3+
## 1.11.1 (2025-03-04)
4+
5+
This is a bugfix release with no new features compared to version 1.11.
6+
7+
### Major Changes
8+
9+
- fix `count_nonzero` wrappers: work around the lack of the `keepdims` argument in
10+
several array libraries (torch, dask, cupy); work around numpy returning python
11+
ints in for some input combinations.
12+
13+
### Minor Changes
14+
15+
- runnings self-tests does not require all array libraries. Missing libraries are
16+
skipped.
17+
18+
The following users contributed to this release:
19+
20+
Evgeni Burovski
21+
Guido Imperiale
22+
23+
24+
## 1.11.0 (2025-02-27)
425

526
### Major Changes
627

numpy-1-21-xfails.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,13 @@ array_api_tests/test_signatures.py::test_array_method_signature[__dlpack__]
187187
array_api_tests/test_manipulation_functions.py::test_repeat
188188

189189
# 2024.12 support
190-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
191-
192190
array_api_tests/test_signatures.py::test_func_signature[bitwise_and]
193191
array_api_tests/test_signatures.py::test_func_signature[bitwise_left_shift]
194192
array_api_tests/test_signatures.py::test_func_signature[bitwise_or]
195193
array_api_tests/test_signatures.py::test_func_signature[bitwise_right_shift]
196194
array_api_tests/test_signatures.py::test_func_signature[bitwise_xor]
195+
196+
# Stubs have a comment: (**note**: libraries may return ``NaN`` to match Python behavior.); Apparently,NumPy does just that
197197
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
198198
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
199199
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]

numpy-1-26-xfails.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ array_api_tests/test_signatures.py::test_array_method_signature[__dlpack__]
4141
array_api_tests/test_manipulation_functions.py::test_repeat
4242

4343
# 2024.12 support
44-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
45-
4644
array_api_tests/test_signatures.py::test_func_signature[bitwise_and]
4745
array_api_tests/test_signatures.py::test_func_signature[bitwise_left_shift]
4846
array_api_tests/test_signatures.py::test_func_signature[bitwise_or]
4947
array_api_tests/test_signatures.py::test_func_signature[bitwise_right_shift]
5048
array_api_tests/test_signatures.py::test_func_signature[bitwise_xor]
49+
50+
# Stubs have a comment: (**note**: libraries may return ``NaN`` to match Python behavior.); Apparently, NumPy does just that
5151
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
5252
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
5353
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]

numpy-dev-xfails.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ array_api_tests/test_signatures.py::test_extension_func_signature[linalg.vecdot]
1111
array_api_tests/test_manipulation_functions.py::test_repeat
1212

1313
# 2024.12 support
14-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
15-
1614
array_api_tests/test_signatures.py::test_func_signature[bitwise_and]
1715
array_api_tests/test_signatures.py::test_func_signature[bitwise_left_shift]
1816
array_api_tests/test_signatures.py::test_func_signature[bitwise_or]
1917
array_api_tests/test_signatures.py::test_func_signature[bitwise_right_shift]
2018
array_api_tests/test_signatures.py::test_func_signature[bitwise_xor]
19+
20+
# Stubs have a comment: (**note**: libraries may return ``NaN`` to match Python behavior.); Apparently, NumPy does just that
2121
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i > 0) -> +infinity]
2222
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is +infinity and isfinite(x2_i) and x2_i < 0) -> -infinity]
2323
array_api_tests/test_special_cases.py::test_binary[floor_divide(x1_i is -infinity and isfinite(x2_i) and x2_i > 0) -> -infinity]

numpy-xfails.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ array_api_tests/test_signatures.py::test_array_method_signature[__dlpack__]
1313
array_api_tests/test_manipulation_functions.py::test_repeat
1414

1515
# 2024.12 support
16-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]
17-
1816
array_api_tests/test_signatures.py::test_func_signature[bitwise_and]
1917
array_api_tests/test_signatures.py::test_func_signature[bitwise_left_shift]
2018
array_api_tests/test_signatures.py::test_func_signature[bitwise_or]

tests/_helpers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
]
99

1010
def import_(library, wrapper=False):
11-
if library in ('cupy', 'ndonnx'):
12-
pytest.importorskip(library)
11+
pytest.importorskip(library)
1312
if wrapper:
1413
if 'jax' in library:
1514
# JAX v0.4.32 implements the array API directly in jax.numpy

torch-xfails.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,3 @@ array_api_tests/test_signatures.py::test_array_method_signature[__lshift__]
136136
array_api_tests/test_signatures.py::test_array_method_signature[__or__]
137137
array_api_tests/test_signatures.py::test_array_method_signature[__rshift__]
138138
array_api_tests/test_signatures.py::test_array_method_signature[__xor__]
139-
array_api_tests/test_special_cases.py::test_nan_propagation[cumulative_prod]

0 commit comments

Comments
 (0)