Skip to content

Commit d48f411

Browse files
committed
ENH: device-dependent default dtypes in creation_functions
1 parent 782689e commit d48f411

2 files changed

Lines changed: 67 additions & 2 deletions

File tree

array_api_strict/_creation_functions.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
import numpy as np
77

88
from ._dtypes import DType, _all_dtypes, _np_dtype
9-
from ._devices import CPU_DEVICE, Device, device_supports_dtype, check_device as _check_device
9+
from ._devices import (
10+
CPU_DEVICE, Device, device_supports_dtype, get_default_dtypes,
11+
check_device as _check_device
12+
)
1013
from ._flags import get_array_api_strict_flags
1114
from ._typing import NestedSequence, SupportsBufferProtocol, SupportsDLPack
1215

@@ -146,6 +149,8 @@ def empty(
146149

147150
_check_device(device)
148151
_check_valid_dtype(dtype, device)
152+
if dtype is None:
153+
dtype = get_default_dtypes(device)["real floating"]
149154

150155
return Array._new(np.empty(shape, dtype=_np_dtype(dtype)), device=device)
151156

@@ -234,6 +239,8 @@ def full(
234239

235240
_check_device(device)
236241
_check_valid_dtype(dtype, device)
242+
if dtype is None:
243+
dtype = get_default_dtypes(device)["real floating"]
237244

238245
if not isinstance(fill_value, bool | int | float | complex):
239246
msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
@@ -350,6 +357,8 @@ def ones(
350357

351358
_check_device(device)
352359
_check_valid_dtype(dtype, device)
360+
if dtype is None:
361+
dtype = get_default_dtypes(device)["real floating"]
353362

354363
return Array._new(np.ones(shape, dtype=_np_dtype(dtype)), device=device)
355364

@@ -415,6 +424,8 @@ def zeros(
415424

416425
_check_device(device)
417426
_check_valid_dtype(dtype, device)
427+
if dtype is None:
428+
dtype = get_default_dtypes(device)["real floating"]
418429

419430
return Array._new(np.zeros(shape, dtype=_np_dtype(dtype)), device=device)
420431

array_api_strict/tests/test_creation_functions.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
zeros_like,
2424
)
2525
from .._dtypes import float32, float64
26-
from .._array_object import Array, CPU_DEVICE, Device
26+
from .._array_object import Array
27+
from .._devices import CPU_DEVICE, ALL_DEVICES, Device
28+
from .._info import __array_namespace_info__
2729
from .._flags import set_array_api_strict_flags
2830

2931
def test_asarray_errors():
@@ -212,6 +214,7 @@ def test_zeros_like_errors():
212214
assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype=int))
213215
assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype="i"))
214216

217+
215218
def test_meshgrid_dtype_errors():
216219
# Doesn't raise
217220
meshgrid()
@@ -221,6 +224,57 @@ def test_meshgrid_dtype_errors():
221224
assert_raises(ValueError, lambda: meshgrid(asarray([1.], dtype=float32), asarray([1.], dtype=float64)))
222225

223226

227+
228+
def _full(a, *args, **kwds):
229+
return full(a, fill_value=42, *args, **kwds)
230+
231+
232+
def _full_like(a, *args, **kwds):
233+
return full_like(a, fill_value=42, *args, **kwds)
234+
235+
236+
class TestDefaultDType:
237+
238+
info = __array_namespace_info__()
239+
240+
@pytest.mark.parametrize("device", ALL_DEVICES)
241+
@pytest.mark.parametrize("func", [empty, zeros, ones, _full])
242+
def test_ones_etc(self, func, device):
243+
a = func(1, device=device)
244+
assert a.dtype == self.info.default_dtypes(device=device)["real floating"]
245+
246+
@pytest.mark.parametrize("func", [empty_like, zeros_like, ones_like, _full_like])
247+
def test_ones_like_etc_correct(self, func):
248+
# float32 is preserved
249+
a = ones(2, dtype=float32)
250+
device = Device('F32_device')
251+
b = func(a, device=device)
252+
assert b.dtype == self.info.default_dtypes(device=device)["real floating"]
253+
254+
@pytest.mark.parametrize("func", [empty_like, zeros_like, ones_like, _full_like])
255+
def test_ones_like_etc_incorrect(self, func):
256+
a = ones(2)
257+
assert a.dtype == float64
258+
assert a.device == Device()
259+
260+
# XXX: a.dtype not supported by the device: ValueError or TypeError?
261+
262+
# >>> a = torch.ones(3, dtype=torch.float64, device='cpu')
263+
# >>> torch.ones_like(a, device='mps')
264+
# TypeError: Cannot convert a MPS Tensor to float64 dtype as the MPS framework
265+
# doesn't support float64.
266+
with pytest.raises(TypeError):
267+
func(a, device=Device('F32_device'))
268+
# TODO:
269+
# def asarray(
270+
# def arange(
271+
# def eye(
272+
# def linspace(
273+
# def meshgrid(*arrays: Array, indexing: Literal["xy", "ij"] = "xy") -> tuple[Array, ...]:
274+
# def tril(x: Array, /, *, k: int = 0) -> Array:
275+
# def triu(x: Array, /, *, k: int = 0) -> Array:
276+
277+
224278
@pytest.mark.parametrize("api_version", ['2021.12', '2022.12', '2023.12'])
225279
def from_dlpack_2023_12(api_version):
226280
if api_version != '2022.12':

0 commit comments

Comments
 (0)