Skip to content

Commit 8dcc44f

Browse files
authored
Merge pull request #2058 from IntelPython/resolve-gh-2055
Resolve gh-2055
2 parents 6ac3a8f + 152a3ed commit 8dcc44f

File tree

4 files changed

+165
-94
lines changed

4 files changed

+165
-94
lines changed

dpctl/tensor/_copy_utils.py

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -349,36 +349,19 @@ def _copy_from_usm_ndarray_to_usm_ndarray(dst, src):
349349
_copy_same_shape(dst, src_same_shape)
350350

351351

352-
def _empty_like_orderK(X, dt, usm_type=None, dev=None):
353-
"""Returns empty array like `x`, using order='K'
354-
355-
For an array `x` that was obtained by permutation of a contiguous
356-
array the returned array will have the same shape and the same
357-
strides as `x`.
352+
def _make_empty_like_orderK(x, dt, usm_type, dev):
358353
"""
359-
if not isinstance(X, dpt.usm_ndarray):
360-
raise TypeError(f"Expected usm_ndarray, got {type(X)}")
361-
if usm_type is None:
362-
usm_type = X.usm_type
363-
if dev is None:
364-
dev = X.device
365-
fl = X.flags
366-
if fl["C"] or X.size <= 1:
367-
return dpt.empty_like(
368-
X, dtype=dt, usm_type=usm_type, device=dev, order="C"
369-
)
370-
elif fl["F"]:
371-
return dpt.empty_like(
372-
X, dtype=dt, usm_type=usm_type, device=dev, order="F"
373-
)
374-
st = list(X.strides)
354+
Returns empty array with shape and strides like `x`, with dtype `dt`,
355+
USM type `usm_type`, on device `dev`.
356+
"""
357+
st = list(x.strides)
375358
perm = sorted(
376-
range(X.ndim),
377-
key=lambda d: builtins.abs(st[d]) if X.shape[d] > 1 else 0,
359+
range(x.ndim),
360+
key=lambda d: builtins.abs(st[d]) if x.shape[d] > 1 else 0,
378361
reverse=True,
379362
)
380-
inv_perm = sorted(range(X.ndim), key=lambda i: perm[i])
381-
sh = X.shape
363+
inv_perm = sorted(range(x.ndim), key=lambda i: perm[i])
364+
sh = x.shape
382365
sh_sorted = tuple(sh[i] for i in perm)
383366
R = dpt.empty(sh_sorted, dtype=dt, usm_type=usm_type, device=dev, order="C")
384367
if min(st) < 0:
@@ -389,12 +372,60 @@ def _empty_like_orderK(X, dt, usm_type=None, dev=None):
389372
if st_sorted[i] < 0
390373
else slice(None, None, None)
391374
)
392-
for i in range(X.ndim)
375+
for i in range(x.ndim)
393376
)
394377
R = R[sl]
395378
return dpt.permute_dims(R, inv_perm)
396379

397380

381+
def _empty_like_orderK(x, dt, usm_type=None, dev=None):
382+
"""
383+
Returns empty array like `x`, using order='K'
384+
385+
For an array `x` that was obtained by permutation of a contiguous
386+
array the returned array will have the same shape and the same
387+
strides as `x`.
388+
"""
389+
if not isinstance(x, dpt.usm_ndarray):
390+
raise TypeError(f"Expected usm_ndarray, got {type(x)}")
391+
if usm_type is None:
392+
usm_type = x.usm_type
393+
if dev is None:
394+
dev = x.device
395+
fl = x.flags
396+
if fl["C"] or x.size <= 1:
397+
return dpt.empty_like(
398+
x, dtype=dt, usm_type=usm_type, device=dev, order="C"
399+
)
400+
elif fl["F"]:
401+
return dpt.empty_like(
402+
x, dtype=dt, usm_type=usm_type, device=dev, order="F"
403+
)
404+
return _make_empty_like_orderK(x, dt, usm_type, dev)
405+
406+
407+
def _from_numpy_empty_like_orderK(x, dt, usm_type, dev):
408+
"""
409+
Returns empty usm_ndarray like NumPy array `x`, using order='K'
410+
411+
For an array `x` that was obtained by permutation of a contiguous
412+
array the returned array will have the same shape and the same
413+
strides as `x`.
414+
"""
415+
if not isinstance(x, np.ndarray):
416+
raise TypeError(f"Expected numpy.ndarray, got {type(x)}")
417+
fl = x.flags
418+
if fl["C"] or x.size <= 1:
419+
return dpt.empty(
420+
x.shape, dtype=dt, usm_type=usm_type, device=dev, order="C"
421+
)
422+
elif fl["F"]:
423+
return dpt.empty(
424+
x.shape, dtype=dt, usm_type=usm_type, device=dev, order="F"
425+
)
426+
return _make_empty_like_orderK(x, dt, usm_type, dev)
427+
428+
398429
def _empty_like_pair_orderK(X1, X2, dt, res_shape, usm_type, dev):
399430
if not isinstance(X1, dpt.usm_ndarray):
400431
raise TypeError(f"Expected usm_ndarray, got {type(X1)}")
@@ -732,7 +763,7 @@ def _extract_impl(ary, ary_mask, axis=0):
732763
if exec_q is None:
733764
raise dpctl.utils.ExecutionPlacementError(
734765
"arrays have different associated queues. "
735-
"Use `Y.to_device(X.device)` to migrate."
766+
"Use `y.to_device(x.device)` to migrate."
736767
)
737768
ary_nd = ary.ndim
738769
pp = normalize_axis_index(operator.index(axis), ary_nd)

dpctl/tensor/_ctors.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
import dpctl.tensor as dpt
2525
import dpctl.tensor._tensor_impl as ti
2626
import dpctl.utils
27-
from dpctl.tensor._copy_utils import _empty_like_orderK
27+
from dpctl.tensor._copy_utils import (
28+
_empty_like_orderK,
29+
_from_numpy_empty_like_orderK,
30+
)
2831
from dpctl.tensor._data_types import _get_dtype
2932
from dpctl.tensor._device import normalize_queue_device
3033
from dpctl.tensor._usmarray import _is_object_with_buffer_protocol
@@ -233,6 +236,7 @@ def _asarray_from_numpy_ndarray(
233236
if dtype is None:
234237
# deduce device-representable output data type
235238
dtype = _map_to_device_dtype(ary.dtype, copy_q)
239+
_ensure_native_dtype_device_support(dtype, copy_q.sycl_device)
236240
f_contig = ary.flags["F"]
237241
c_contig = ary.flags["C"]
238242
fc_contig = f_contig or c_contig
@@ -242,27 +246,8 @@ def _asarray_from_numpy_ndarray(
242246
order = "C" if c_contig else "F"
243247
if order == "K":
244248
# new USM allocation
245-
_ensure_native_dtype_device_support(dtype, copy_q.sycl_device)
246-
res = dpt.usm_ndarray(
247-
ary.shape,
248-
dtype=dtype,
249-
buffer=usm_type,
250-
order="C",
251-
buffer_ctor_kwargs={"queue": copy_q},
252-
)
253-
original_strides = ary.strides
254-
ind = sorted(
255-
range(ary.ndim),
256-
key=lambda i: abs(original_strides[i]),
257-
reverse=True,
258-
)
259-
new_strides = tuple(res.strides[ind[i]] for i in ind)
260-
# reuse previously made USM allocation
261-
res = dpt.usm_ndarray(
262-
res.shape, dtype=res.dtype, buffer=res.usm_data, strides=new_strides
263-
)
249+
res = _from_numpy_empty_like_orderK(ary, dtype, usm_type, copy_q)
264250
else:
265-
_ensure_native_dtype_device_support(dtype, copy_q.sycl_device)
266251
res = dpt.usm_ndarray(
267252
ary.shape,
268253
dtype=dtype,

dpctl/tests/elementwise/test_type_utils.py

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import dpctl
2121
import dpctl.tensor as dpt
22-
import dpctl.tensor._copy_utils as cu
2322
import dpctl.tensor._type_utils as tu
2423

2524
from .utils import _all_dtypes, _map_to_device_dtype
@@ -70,50 +69,6 @@ def test_type_util_can_cast():
7069
assert isinstance(r, bool)
7170

7271

73-
def test_type_utils_empty_like_orderK():
74-
try:
75-
a = dpt.empty((10, 10), dtype=dpt.int32, order="F")
76-
except dpctl.SyclDeviceCreationError:
77-
pytest.skip("No SYCL devices available")
78-
X = cu._empty_like_orderK(a, dpt.int32, a.usm_type, a.device)
79-
assert X.flags["F"]
80-
81-
82-
def test_type_utils_empty_like_orderK_invalid_args():
83-
with pytest.raises(TypeError):
84-
cu._empty_like_orderK([1, 2, 3], dpt.int32, "device", None)
85-
with pytest.raises(TypeError):
86-
cu._empty_like_pair_orderK(
87-
[1, 2, 3],
88-
(
89-
1,
90-
2,
91-
3,
92-
),
93-
dpt.int32,
94-
(3,),
95-
"device",
96-
None,
97-
)
98-
try:
99-
a = dpt.empty(10, dtype=dpt.int32)
100-
except dpctl.SyclDeviceCreationError:
101-
pytest.skip("No SYCL devices available")
102-
with pytest.raises(TypeError):
103-
cu._empty_like_pair_orderK(
104-
a,
105-
(
106-
1,
107-
2,
108-
3,
109-
),
110-
dpt.int32,
111-
(10,),
112-
"device",
113-
None,
114-
)
115-
116-
11772
def test_type_utils_find_buf_dtype():
11873
def _denier_fn(dt):
11974
return False

dpctl/tests/test_tensor_copy_utils.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Data Parallel Control (dpctl)
2+
#
3+
# Copyright 2020-2025 Intel Corporation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import numpy as np
18+
import pytest
19+
20+
import dpctl.tensor as dpt
21+
import dpctl.tensor._copy_utils as cu
22+
from dpctl.tests.helper import get_queue_or_skip
23+
24+
25+
def test_copy_utils_empty_like_orderK():
26+
get_queue_or_skip()
27+
a = dpt.empty((10, 10), dtype=dpt.int32, order="F")
28+
X = cu._empty_like_orderK(a, dpt.int32, a.usm_type, a.device)
29+
assert X.flags["F"]
30+
31+
32+
def test_copy_utils_empty_like_orderK_invalid_args():
33+
get_queue_or_skip()
34+
with pytest.raises(TypeError):
35+
cu._empty_like_orderK([1, 2, 3], dpt.int32, "device", None)
36+
with pytest.raises(TypeError):
37+
cu._empty_like_pair_orderK(
38+
[1, 2, 3],
39+
(
40+
1,
41+
2,
42+
3,
43+
),
44+
dpt.int32,
45+
(3,),
46+
"device",
47+
None,
48+
)
49+
50+
a = dpt.empty(10, dtype=dpt.int32)
51+
with pytest.raises(TypeError):
52+
cu._empty_like_pair_orderK(
53+
a,
54+
(
55+
1,
56+
2,
57+
3,
58+
),
59+
dpt.int32,
60+
(10,),
61+
"device",
62+
None,
63+
)
64+
65+
66+
def test_copy_utils_from_numpy_empty_like_orderK():
67+
q = get_queue_or_skip()
68+
69+
a = np.empty((10, 10), dtype=np.int32, order="C")
70+
r0 = cu._from_numpy_empty_like_orderK(a, dpt.int32, "device", q)
71+
assert r0.flags["C"]
72+
73+
b = np.empty((10, 10), dtype=np.int32, order="F")
74+
r1 = cu._from_numpy_empty_like_orderK(b, dpt.int32, "device", q)
75+
assert r1.flags["F"]
76+
77+
c = np.empty((2, 3, 4), dtype=np.int32, order="C")
78+
c = np.transpose(c, (1, 0, 2))
79+
r2 = cu._from_numpy_empty_like_orderK(c, dpt.int32, "device", q)
80+
assert not r2.flags["C"] and not r2.flags["F"]
81+
82+
83+
def test_copy_utils_from_numpy_empty_like_orderK_invalid_args():
84+
with pytest.raises(TypeError):
85+
cu._from_numpy_empty_like_orderK([1, 2, 3], dpt.int32, "device", None)
86+
87+
88+
def test_gh_2055():
89+
"""
90+
Test that `dpt.asarray` works on contiguous NumPy arrays with `order="K"`
91+
when dimensions are permuted.
92+
93+
See: https://github.com/IntelPython/dpctl/issues/2055
94+
"""
95+
get_queue_or_skip()
96+
97+
a = np.ones((2, 3, 4), dtype=dpt.int32)
98+
a_t = np.transpose(a, (2, 0, 1))
99+
r = dpt.asarray(a_t)
100+
assert not r.flags["C"] and not r.flags["F"]

0 commit comments

Comments
 (0)