Commit 446e146
committed
BUG: do not change the dtype in asarray(array_from_another_library)
Consider
>>> x = np.asarray(3, dtype=np.float32)
>>> y = xp.asarray(x, device=xp.Device("device1"))
>>> y.dtype == xp.float32
Since `x` is an array, the dtype of `y` must match the dtype of `x`,
not be the default dtype of the device of `y`!
In fact, this is the behavior in 2.5, so restore it.
The fix follows from the difference between 2.5 and 2.6:
- in 2.5, we called `res = np.array(...)` and wrapped `res` into an xp-array
- in 2.6, we additionally select adjust the dtype to match the default for the device.
The last part should be gated:
- if `obj` is an array_like python object, it does not have a .dtype attribute,
thus we adjust res.dtype (this is new in 2.6)
- if `obj` is a array from numpy or pytorch CPU (i.e. numpy conversion succeeds),
`res.dtype` is a numpy analog of `obj.dtype`, so we honor that (this is
what 2.6 broke, and we fix here)
- if `obj` has a dtype attribute but numpy fails to convert it (so `obj`
is a GPU array or a pydata sparse array etc), calling `np.array(obj)` fails with
an exception, and we never reach the dtype adjustment stage anyway
(and this is unchanged from 2.5).
$ git diff 2.5..2.6 -- array_api_strict/_creation_functions.py
... snip ...
@@ -108,6 +106,27 @@ def asarray(
raise OverflowError("Integer out of bounds for array dtypes")
res = np.array(obj, dtype=_np_dtype, copy=copy)
+
+ # numpy default dtype may differ; if so, adjust the dtype
+ if dtype is None and device is not None:
+ res_dtype = DType(res.dtype)
+ # The dtype selected by Numpy might not be the default dtype
+ # on this device. We thus find the default dtype for the dtype "kind", and
+ # cast to the device-appropriate default.
+ from ._data_type_functions import isdtype
+ if isdtype(res_dtype, "bool"):
+ target_dtype = DType("bool")
+ elif isdtype(res_dtype, "integral"):
+ target_dtype = get_default_dtypes(device)["integral"]
+ elif isdtype(res_dtype, "real floating"):
+ target_dtype = get_default_dtypes(device)["real floating"]
+ elif isdtype(res_dtype, "complex floating"):
+ target_dtype = get_default_dtypes(device)["complex floating"]
+ else:
+ raise ValueError(f"{res_dtype = } not understood.")
+
+ res = res.astype(target_dtype._np_dtype)
+
return Array._new(res, device=device)1 parent 95ded08 commit 446e146
2 files changed
Lines changed: 13 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
110 | | - | |
111 | | - | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
112 | 116 | | |
113 | 117 | | |
114 | 118 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
368 | 368 | | |
369 | 369 | | |
370 | 370 | | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
371 | 378 | | |
372 | 379 | | |
373 | 380 | | |
| |||
0 commit comments