55
66import numpy as np
77
8- from ._dtypes import DType , _all_dtypes , _np_dtype
8+ from ._dtypes import DType , _all_dtypes , _np_dtype , bool as xp_bool
9+ from ._devices import (
10+ Device , device_supports_dtype , get_default_dtypes ,
11+ check_device as _check_device
12+ )
913from ._flags import get_array_api_strict_flags
1014from ._typing import NestedSequence , SupportsBufferProtocol , SupportsDLPack
1115
1418 from typing_extensions import TypeIs
1519
1620 # Circular import
17- from ._array_object import Array , Device
21+ from ._array_object import Array
1822
1923
2024class Undef (Enum ):
@@ -24,10 +28,15 @@ class Undef(Enum):
2428_undef = Undef .UNDEF
2529
2630
27- def _check_valid_dtype (dtype : DType | None ) -> None :
31+ def _check_valid_dtype (dtype : DType | None , device : Device | None = None ) -> None :
2832 # Note: Only spelling dtypes as the dtype objects is supported.
29- if dtype not in (None ,) + _all_dtypes :
30- raise ValueError (f"dtype must be one of the supported dtypes, got { dtype !r} " )
33+ if dtype is not None :
34+ if dtype not in _all_dtypes :
35+ raise ValueError (f"dtype must be one of the supported dtypes, got { dtype !r} " )
36+
37+ if device is not None :
38+ if not device_supports_dtype (device , dtype ):
39+ raise ValueError (f"Device { device !r} does not support dtype={ dtype !r} ." )
3140
3241
3342def _supports_buffer_protocol (obj : object ) -> TypeIs [SupportsBufferProtocol ]:
@@ -38,18 +47,6 @@ def _supports_buffer_protocol(obj: object) -> TypeIs[SupportsBufferProtocol]:
3847 return True
3948
4049
41- def _check_device (device : Device | None ) -> None :
42- # _array_object imports in this file are inside the functions to avoid
43- # circular imports
44- from ._array_object import ALL_DEVICES , Device
45-
46- if device is not None and not isinstance (device , Device ):
47- raise ValueError (f"Unsupported device { device !r} " )
48-
49- if device is not None and device not in ALL_DEVICES :
50- raise ValueError (f"Unsupported device { device !r} " )
51-
52-
5350def asarray (
5451 obj : Array | complex | NestedSequence [complex ] | SupportsBufferProtocol ,
5552 / ,
@@ -65,11 +62,12 @@ def asarray(
6562 """
6663 from ._array_object import Array
6764
68- _check_valid_dtype (dtype )
65+ _check_device (device )
66+ _check_valid_dtype (dtype , device )
6967 _np_dtype = None
7068 if dtype is not None :
7169 _np_dtype = dtype ._np_dtype
72- _check_device ( device )
70+
7371 if isinstance (obj , Array ) and device is None :
7472 device = obj .device
7573
@@ -108,6 +106,27 @@ def asarray(
108106 raise OverflowError ("Integer out of bounds for array dtypes" )
109107
110108 res = np .array (obj , dtype = _np_dtype , copy = copy )
109+
110+ # numpy default dtype may differ; if so, adjust the dtype
111+ if dtype is None and device is not None :
112+ res_dtype = DType (res .dtype )
113+ # The dtype selected by Numpy might not be the default dtype
114+ # on this device. We thus find the default dtype for the dtype "kind", and
115+ # cast to the device-appropriate default.
116+ from ._data_type_functions import isdtype
117+ if isdtype (res_dtype , "bool" ):
118+ target_dtype = DType ("bool" )
119+ elif isdtype (res_dtype , "integral" ):
120+ target_dtype = get_default_dtypes (device )["integral" ]
121+ elif isdtype (res_dtype , "real floating" ):
122+ target_dtype = get_default_dtypes (device )["real floating" ]
123+ elif isdtype (res_dtype , "complex floating" ):
124+ target_dtype = get_default_dtypes (device )["complex floating" ]
125+ else :
126+ raise ValueError (f"{ res_dtype = } not understood." )
127+
128+ res = res .astype (target_dtype ._np_dtype )
129+
111130 return Array ._new (res , device = device )
112131
113132
@@ -127,8 +146,13 @@ def arange(
127146 """
128147 from ._array_object import Array
129148
130- _check_valid_dtype (dtype )
131149 _check_device (device )
150+ _check_valid_dtype (dtype , device )
151+ if dtype is None :
152+ if any (isinstance (x , float ) for x in (start , stop , step )):
153+ dtype = get_default_dtypes (device )["real floating" ]
154+ else :
155+ dtype = get_default_dtypes (device )["integral" ]
132156
133157 return Array ._new (
134158 np .arange (start , stop , step , dtype = _np_dtype (dtype )),
@@ -149,8 +173,10 @@ def empty(
149173 """
150174 from ._array_object import Array
151175
152- _check_valid_dtype (dtype )
153176 _check_device (device )
177+ _check_valid_dtype (dtype , device )
178+ if dtype is None :
179+ dtype = get_default_dtypes (device )["real floating" ]
154180
155181 return Array ._new (np .empty (shape , dtype = _np_dtype (dtype )), device = device )
156182
@@ -165,10 +191,12 @@ def empty_like(
165191 """
166192 from ._array_object import Array
167193
168- _check_valid_dtype (dtype )
169194 _check_device (device )
170195 if device is None :
171196 device = x .device
197+ if dtype is None :
198+ dtype = x .dtype
199+ _check_valid_dtype (dtype , device )
172200
173201 return Array ._new (np .empty_like (x ._array , dtype = _np_dtype (dtype )), device = device )
174202
@@ -189,8 +217,10 @@ def eye(
189217 """
190218 from ._array_object import Array
191219
192- _check_valid_dtype (dtype )
193220 _check_device (device )
221+ _check_valid_dtype (dtype , device )
222+ if dtype is None :
223+ dtype = get_default_dtypes (device )["real floating" ]
194224
195225 return Array ._new (
196226 np .eye (n_rows , M = n_cols , k = k , dtype = _np_dtype (dtype )), device = device
@@ -217,7 +247,7 @@ def from_dlpack(
217247 else :
218248 device = None
219249 if hasattr (x , "__dlpack_device__" ):
220- from ._array_object import _device_from_dlpack_device
250+ from ._devices import _device_from_dlpack_device
221251
222252 dl_type , dl_id = x .__dlpack_device__ ()
223253 device = _device_from_dlpack_device (dl_type , dl_id )
@@ -242,12 +272,22 @@ def full(
242272 """
243273 from ._array_object import Array
244274
245- _check_valid_dtype (dtype )
246275 _check_device (device )
276+ _check_valid_dtype (dtype , device )
247277
248278 if not isinstance (fill_value , bool | int | float | complex ):
249279 msg = f"Expected Python scalar fill_value, got type { type (fill_value )} "
250280 raise TypeError (msg )
281+
282+ if dtype is None :
283+ if type (fill_value ) == bool :
284+ dtype = xp_bool
285+ else :
286+ kind = {
287+ int : "integral" , float : "real floating" , complex : "complex floating"
288+ }[type (fill_value )]
289+ dtype = get_default_dtypes (device )[kind ]
290+
251291 res = np .full (shape , fill_value , dtype = _np_dtype (dtype ))
252292 if DType (res .dtype ) not in _all_dtypes :
253293 # This will happen if the fill value is not something that NumPy
@@ -271,10 +311,12 @@ def full_like(
271311 """
272312 from ._array_object import Array
273313
274- _check_valid_dtype (dtype )
275314 _check_device (device )
276315 if device is None :
277316 device = x .device
317+ if dtype is None :
318+ dtype = x .dtype
319+ _check_valid_dtype (dtype , device )
278320
279321 if not isinstance (fill_value , bool | int | float | complex ):
280322 msg = f"Expected Python scalar fill_value, got type { type (fill_value )} "
@@ -305,8 +347,13 @@ def linspace(
305347 """
306348 from ._array_object import Array
307349
308- _check_valid_dtype (dtype )
309350 _check_device (device )
351+ _check_valid_dtype (dtype , device )
352+ if dtype is None :
353+ if isinstance (start , complex ) or isinstance (stop , complex ):
354+ dtype = get_default_dtypes (device )["complex floating" ]
355+ else :
356+ dtype = get_default_dtypes (device )["real floating" ]
310357
311358 return Array ._new (
312359 np .linspace (start , stop , num , dtype = _np_dtype (dtype ), endpoint = endpoint ),
@@ -358,8 +405,10 @@ def ones(
358405 """
359406 from ._array_object import Array
360407
361- _check_valid_dtype (dtype )
362408 _check_device (device )
409+ _check_valid_dtype (dtype , device )
410+ if dtype is None :
411+ dtype = get_default_dtypes (device )["real floating" ]
363412
364413 return Array ._new (np .ones (shape , dtype = _np_dtype (dtype )), device = device )
365414
@@ -374,10 +423,12 @@ def ones_like(
374423 """
375424 from ._array_object import Array
376425
377- _check_valid_dtype (dtype )
378426 _check_device (device )
379427 if device is None :
380428 device = x .device
429+ if dtype is None :
430+ dtype = x .dtype
431+ _check_valid_dtype (dtype , device )
381432
382433 return Array ._new (np .ones_like (x ._array , dtype = _np_dtype (dtype )), device = device )
383434
@@ -423,8 +474,10 @@ def zeros(
423474 """
424475 from ._array_object import Array
425476
426- _check_valid_dtype (dtype )
427477 _check_device (device )
478+ _check_valid_dtype (dtype , device )
479+ if dtype is None :
480+ dtype = get_default_dtypes (device )["real floating" ]
428481
429482 return Array ._new (np .zeros (shape , dtype = _np_dtype (dtype )), device = device )
430483
@@ -439,9 +492,11 @@ def zeros_like(
439492 """
440493 from ._array_object import Array
441494
442- _check_valid_dtype (dtype )
443495 _check_device (device )
444496 if device is None :
445497 device = x .device
498+ if dtype is None :
499+ dtype = x .dtype
500+ _check_valid_dtype (dtype , device )
446501
447502 return Array ._new (np .zeros_like (x ._array , dtype = _np_dtype (dtype )), device = device )
0 commit comments