Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
strategy:
fail-fast: false
matrix:
environment: [tests-py310, tests-py313, tests-backends]
environment: [tests-py310, tests-py313, tests-numpy1, tests-backends]
runs-on: [ubuntu-latest]

steps:
Expand Down
1,147 changes: 1,143 additions & 4 deletions pixi.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ python = "~=3.10.0"
[tool.pixi.feature.py313.dependencies]
python = "~=3.13.0"

[tool.pixi.feature.numpy1.dependencies]
numpy = "<2"

# Backends that can run on CPU-only hosts
[tool.pixi.feature.backends.dependencies]
pytorch = "*"
Expand Down Expand Up @@ -167,6 +170,8 @@ tests = { features = ["tests"], solve-group = "default" }
docs = { features = ["docs"], solve-group = "default" }
dev = { features = ["lint", "tests", "docs", "dev", "backends"], solve-group = "default" }
dev-cuda = { features = ["lint", "tests", "docs", "dev", "backends", "cuda-backends"] }
dev-numpy1 = { features = ["lint", "tests", "dev", "numpy1"] }
tests-numpy1 = ["py310", "tests", "numpy1"]
tests-py310 = ["py310", "tests"]
tests-py313 = ["py313", "tests"]
# CUDA not available on free github actions and on some developers' PCs
Expand Down
9 changes: 4 additions & 5 deletions src/array_api_extra/_lib/_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,11 @@ def isclose(
if rtol == 0:
return xp.abs(a - b) <= atol

try:
nrtol = xp.asarray(int(1.0 / rtol), dtype=b.dtype)
except OverflowError:
# rtol * max_int(dtype) < 1, so it's inconsequential
# Don't rely on OverflowError, as it is not guaranteed by the Array API.
nrtol = int(1.0 / rtol)
if nrtol > xp.iinfo(b.dtype).max:
# rtol * max_int < 1, so it's inconsequential
Comment on lines +568 to +571
Copy link
Contributor Author

@crusaderky crusaderky Mar 19, 2025

Choose a reason for hiding this comment

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

In practice, this impacts only array-api-strict wrapping around numpy 1.x

return xp.abs(a - b) <= atol

return xp.abs(a - b) <= (atol + xp.abs(b) // nrtol)


Expand Down
3 changes: 1 addition & 2 deletions src/array_api_extra/_lib/_utils/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,7 @@ def eager_shape(x: Array, /) -> tuple[int, ...]:


def meta_namespace(
*arrays: Array | int | float | complex | bool | None,
xp: ModuleType | None = None,
*arrays: Array | complex | None, xp: ModuleType | None = None
) -> ModuleType:
"""
Get the namespace of Dask chunks.
Expand Down
10 changes: 10 additions & 0 deletions tests/test_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
lazy_xp_function(sinc, static_argnames="xp")


NUMPY_GE2 = int(np.__version__.split(".")[0]) >= 2


@pytest.mark.skip_xp_backend(
Backend.SPARSE, reason="read-only backend without .at support"
)
Expand Down Expand Up @@ -213,6 +216,13 @@ def test_hypothesis( # type: ignore[explicit-any,decorated-any]
xp: ModuleType,
library: Backend,
):
if (
library in (Backend.NUMPY, Backend.NUMPY_READONLY)
and not NUMPY_GE2
and dtype is np.float32
):
pytest.xfail(reason="NumPy 1.x dtype promotion for scalars")

mbs = npst.mutually_broadcastable_shapes(num_shapes=n_arrays + 1, min_side=0)
input_shapes, _ = data.draw(mbs)
cond_shape, *shapes = input_shapes
Expand Down
6 changes: 3 additions & 3 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
from array_api_extra._lib._utils._typing import Array, Device, DType
from array_api_extra.testing import lazy_xp_function

# mypy: disable-error-code=no-untyped-usage
from .conftest import np_compat

np_compat = array_namespace(np.empty(0)) # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
# mypy: disable-error-code=no-untyped-usage

# FIXME calls xp.unique_values without size
lazy_xp_function(in1d, jax_jit=False, static_argnames=("assume_unique", "invert", "xp"))
Expand Down Expand Up @@ -149,7 +149,7 @@ def test_numpy_generics(self, dtype: DType):
which are subclasses of float and complex.
"""
a = cast(Array, dtype(0)) # type: ignore[operator] # pyright: ignore[reportCallIssue]
xa, xb = asarrays(a, 0, xp=np)
xa, xb = asarrays(a, 0, xp=np_compat)
assert xa.dtype == dtype
assert xb.dtype == dtype

Expand Down
9 changes: 2 additions & 7 deletions tests/test_lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,7 @@ def f(x: Array) -> tuple[Array, Array]:
@pytest.mark.parametrize(
"as_numpy",
[
pytest.param(
False,
marks=pytest.mark.xfail_xp_backend(
Backend.TORCH, reason="illegal dtype promotion"
),
),
False,
pytest.param(
True,
marks=[
Expand All @@ -119,7 +114,7 @@ def f(x: Array, y: Array) -> tuple[Array, Array]:
return x + y, x - y

x = xp.asarray([1, 2], dtype=xp.float32)
y = xp.asarray(3, dtype=xp.float64)
y = xp.asarray([3], dtype=xp.float64)
expect = (
xp.asarray([4, 5], dtype=xp.float64),
xp.asarray([-2, -1], dtype=xp.float64),
Expand Down
Loading