• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IntelPython / dpctl / 16460688165

23 Jul 2025 03:19AM UTC coverage: 85.936% (+0.05%) from 85.882%
16460688165

Pull #2098

github

web-flow
Merge 1fc9a2587 into aa05645a6
Pull Request #2098: Implement `tensor.isin`

3251 of 3906 branches covered (83.23%)

Branch coverage included in aggregate %.

116 of 120 new or added lines in 7 files covered. (96.67%)

3 existing lines in 3 files now uncovered.

12300 of 14190 relevant lines covered (86.68%)

5902.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.53
/dpctl/tensor/_ctors.py
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 operator
1✔
18
from numbers import Number
1✔
19

20
import numpy as np
1✔
21

22
import dpctl
1✔
23
import dpctl.memory as dpm
1✔
24
import dpctl.tensor as dpt
1✔
25
import dpctl.tensor._tensor_impl as ti
1✔
26
import dpctl.utils
1✔
27
from dpctl.tensor._copy_utils import (
1✔
28
    _empty_like_orderK,
29
    _from_numpy_empty_like_orderK,
30
)
31
from dpctl.tensor._data_types import _get_dtype
1✔
32
from dpctl.tensor._device import normalize_queue_device
1✔
33
from dpctl.tensor._usmarray import _is_object_with_buffer_protocol
1✔
34

35
__doc__ = "Implementation of creation functions in :module:`dpctl.tensor`"
1✔
36

37
_empty_tuple = tuple()
1✔
38
_host_set = frozenset([None])
1✔
39

40

41
def _array_info_dispatch(obj):
1✔
42
    if isinstance(obj, dpt.usm_ndarray):
1✔
43
        return obj.shape, obj.dtype, frozenset([obj.sycl_queue])
1✔
44
    if isinstance(obj, np.ndarray):
1✔
45
        return obj.shape, obj.dtype, _host_set
1✔
46
    if isinstance(obj, range):
1✔
47
        return (len(obj),), int, _host_set
1✔
48
    if isinstance(obj, bool):
1✔
49
        return _empty_tuple, bool, _host_set
1✔
50
    if isinstance(obj, float):
1✔
51
        return _empty_tuple, float, _host_set
1✔
52
    if isinstance(obj, int):
1✔
53
        return _empty_tuple, int, _host_set
1✔
54
    if isinstance(obj, complex):
1✔
55
        return _empty_tuple, complex, _host_set
1✔
56
    if isinstance(
1✔
57
        obj,
58
        (
59
            list,
60
            tuple,
61
        ),
62
    ):
63
        return _array_info_sequence(obj)
1✔
64
    if _is_object_with_buffer_protocol(obj):
1✔
65
        np_obj = np.array(obj)
1✔
66
        return np_obj.shape, np_obj.dtype, _host_set
1✔
67
    if hasattr(obj, "__usm_ndarray__"):
1✔
68
        usm_ar = getattr(obj, "__usm_ndarray__")
1✔
69
        if isinstance(usm_ar, dpt.usm_ndarray):
1!
70
            return usm_ar.shape, usm_ar.dtype, frozenset([usm_ar.sycl_queue])
1✔
71
    if hasattr(obj, "__sycl_usm_array_interface__"):
1!
72
        usm_ar = _usm_ndarray_from_suai(obj)
1✔
73
        return usm_ar.shape, usm_ar.dtype, frozenset([usm_ar.sycl_queue])
1✔
74
    raise ValueError(type(obj))
×
75

76

77
def _array_info_sequence(li):
1✔
78
    if not isinstance(li, (list, tuple, range)):
1!
79
        raise TypeError(f"Expected list, tuple, or range, got {type(li)}")
×
80
    n = len(li)
1✔
81
    dim = None
1✔
82
    dt = None
1✔
83
    device = frozenset()
1✔
84
    for el in li:
1✔
85
        el_dim, el_dt, el_dev = _array_info_dispatch(el)
1✔
86
        if dim is None:
1✔
87
            dim = el_dim
1✔
88
            dt = np.promote_types(el_dt, el_dt)
1✔
89
            device = device.union(el_dev)
1✔
90
        elif el_dim == dim:
1✔
91
            dt = np.promote_types(dt, el_dt)
1✔
92
            device = device.union(el_dev)
1✔
93
        else:
94
            raise ValueError(f"Inconsistent dimensions, {dim} and {el_dim}")
1✔
95
    if dim is None:
1✔
96
        dim = tuple()
1✔
97
        dt = float
1✔
98
        device = _host_set
1✔
99
    return (n,) + dim, dt, device
1✔
100

101

102
def _asarray_from_usm_ndarray(
1✔
103
    usm_ndary,
104
    dtype=None,
105
    copy=None,
106
    usm_type=None,
107
    sycl_queue=None,
108
    order="K",
109
):
110
    if not isinstance(usm_ndary, dpt.usm_ndarray):
1!
111
        raise TypeError(
×
112
            f"Expected dpctl.tensor.usm_ndarray, got {type(usm_ndary)}"
113
        )
114
    if usm_type is None:
1✔
115
        usm_type = usm_ndary.usm_type
1✔
116
    if sycl_queue is not None:
1✔
117
        exec_q = dpctl.utils.get_execution_queue(
1✔
118
            [usm_ndary.sycl_queue, sycl_queue]
119
        )
120
        copy_q = normalize_queue_device(sycl_queue=sycl_queue, device=exec_q)
1✔
121
    else:
122
        copy_q = usm_ndary.sycl_queue
1✔
123
    if dtype is None:
1✔
124
        dtype = _map_to_device_dtype(usm_ndary.dtype, copy_q)
1✔
125
    # Conditions for zero copy:
126
    can_zero_copy = copy is not True
1✔
127
    #    dtype is unchanged
128
    can_zero_copy = can_zero_copy and dtype == usm_ndary.dtype
1✔
129
    #    USM allocation type is unchanged
130
    can_zero_copy = can_zero_copy and usm_type == usm_ndary.usm_type
1✔
131
    #    sycl_queue is unchanged
132
    can_zero_copy = can_zero_copy and copy_q is usm_ndary.sycl_queue
1✔
133
    #    order is unchanged
134
    c_contig = usm_ndary.flags.c_contiguous
1✔
135
    f_contig = usm_ndary.flags.f_contiguous
1✔
136
    fc_contig = usm_ndary.flags.forc
1✔
137
    if can_zero_copy:
1✔
138
        if order == "C" and c_contig:
1✔
139
            pass
1✔
140
        elif order == "F" and f_contig:
1✔
141
            pass
1✔
142
        elif order == "A" and fc_contig:
1✔
143
            pass
1✔
144
        elif order == "K":
1✔
145
            pass
1✔
146
        else:
147
            can_zero_copy = False
1✔
148
    if copy is False and can_zero_copy is False:
1✔
149
        raise ValueError("asarray(..., copy=False) is not possible")
1✔
150
    if can_zero_copy:
1✔
151
        return usm_ndary
1✔
152
    if order == "A":
1!
153
        order = "F" if f_contig and not c_contig else "C"
×
154
    if order == "K" and fc_contig:
1✔
155
        order = "C" if c_contig else "F"
1✔
156
    if order == "K":
1✔
157
        _ensure_native_dtype_device_support(dtype, copy_q.sycl_device)
1✔
158
        res = _empty_like_orderK(usm_ndary, dtype, usm_type, copy_q)
1✔
159
    else:
160
        _ensure_native_dtype_device_support(dtype, copy_q.sycl_device)
1✔
161
        res = dpt.usm_ndarray(
1✔
162
            usm_ndary.shape,
163
            dtype=dtype,
164
            buffer=usm_type,
165
            order=order,
166
            buffer_ctor_kwargs={"queue": copy_q},
167
        )
168
    eq = dpctl.utils.get_execution_queue([usm_ndary.sycl_queue, copy_q])
1✔
169
    if eq is not None:
1!
170
        _manager = dpctl.utils.SequentialOrderManager[eq]
1✔
171
        dep_evs = _manager.submitted_events
1✔
172
        hev, cpy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
1✔
173
            src=usm_ndary, dst=res, sycl_queue=eq, depends=dep_evs
174
        )
175
        _manager.add_event_pair(hev, cpy_ev)
1✔
176
    else:
177
        tmp = dpt.asnumpy(usm_ndary)
1✔
178
        res[...] = tmp
1✔
179
    return res
1✔
180

181

182
def _map_to_device_dtype(dt, q):
1✔
183
    dtc = dt.char
1✔
184
    if dtc == "?" or np.issubdtype(dt, np.integer):
1✔
185
        return dt
1✔
186
    d = q.sycl_device
1✔
187
    if np.issubdtype(dt, np.floating):
1✔
188
        if dtc == "f":
1✔
189
            return dt
1✔
190
        if dtc == "d" and d.has_aspect_fp64:
1✔
191
            return dt
1✔
192
        if dtc == "e" and d.has_aspect_fp16:
1!
193
            return dt
1✔
194
        return dpt.dtype("f4")
1✔
195
    if np.issubdtype(dt, np.complexfloating):
1!
196
        if dtc == "F":
1✔
197
            return dt
1✔
198
        if dtc == "D" and d.has_aspect_fp64:
1!
199
            return dt
1✔
200
        return dpt.dtype("c8")
×
201
    raise RuntimeError(f"Unrecognized data type '{dt}' encountered.")
×
202

203

204
def _usm_ndarray_from_suai(obj):
1✔
205
    sua_iface = getattr(obj, "__sycl_usm_array_interface__")
1✔
206
    membuf = dpm.as_usm_memory(obj)
1✔
207
    ary = dpt.usm_ndarray(
1✔
208
        sua_iface["shape"],
209
        dtype=sua_iface["typestr"],
210
        buffer=membuf,
211
        strides=sua_iface.get("strides", None),
212
    )
213
    _data_field = sua_iface["data"]
1✔
214
    if isinstance(_data_field, tuple) and len(_data_field) > 1:
1!
215
        ro_field = _data_field[1]
1✔
216
    else:
217
        ro_field = False
×
218
    if ro_field:
1✔
219
        ary.flags["W"] = False
1✔
220
    return ary
1✔
221

222

223
def _asarray_from_numpy_ndarray(
1✔
224
    ary, dtype=None, usm_type=None, sycl_queue=None, order="K"
225
):
226
    if not isinstance(ary, np.ndarray):
1!
227
        raise TypeError(f"Expected numpy.ndarray, got {type(ary)}")
×
228
    if usm_type is None:
1✔
229
        usm_type = "device"
1✔
230
    copy_q = normalize_queue_device(sycl_queue=None, device=sycl_queue)
1✔
231
    if ary.dtype.char not in "?bBhHiIlLqQefdFD":
1✔
232
        raise TypeError(
1✔
233
            f"Numpy array of data type {ary.dtype} is not supported. "
234
            "Please convert the input to an array with numeric data type."
235
        )
236
    if dtype is None:
1✔
237
        # deduce device-representable output data type
238
        dtype = _map_to_device_dtype(ary.dtype, copy_q)
1✔
239
    _ensure_native_dtype_device_support(dtype, copy_q.sycl_device)
1✔
240
    f_contig = ary.flags["F"]
1✔
241
    c_contig = ary.flags["C"]
1✔
242
    fc_contig = f_contig or c_contig
1✔
243
    if order == "A":
1!
244
        order = "F" if f_contig and not c_contig else "C"
×
245
    if order == "K" and fc_contig:
1✔
246
        order = "C" if c_contig else "F"
1✔
247
    if order == "K":
1✔
248
        # new USM allocation
249
        res = _from_numpy_empty_like_orderK(ary, dtype, usm_type, copy_q)
1✔
250
    else:
251
        res = dpt.usm_ndarray(
1✔
252
            ary.shape,
253
            dtype=dtype,
254
            buffer=usm_type,
255
            order=order,
256
            buffer_ctor_kwargs={"queue": copy_q},
257
        )
258
    res[...] = ary
1✔
259
    return res
×
260

261

262
def _ensure_native_dtype_device_support(dtype, dev) -> None:
1✔
263
    """Check that dtype is natively supported by device.
264

265
    Arg:
266
        dtype:
267
            Elemental data-type
268
        dev (:class:`dpctl.SyclDevice`):
269
            The device about which the query is being made.
270
    Returns:
271
        None
272
    Raise:
273
        ValueError:
274
            if device does not natively support this `dtype`.
275
    """
276
    if dtype in [dpt.float64, dpt.complex128] and not dev.has_aspect_fp64:
1!
277
        raise ValueError(
×
278
            f"Device {dev.name} does not provide native support "
279
            "for double-precision floating point type."
280
        )
281
    if (
1✔
282
        dtype
283
        in [
284
            dpt.float16,
285
        ]
286
        and not dev.has_aspect_fp16
287
    ):
288
        raise ValueError(
1✔
289
            f"Device {dev.name} does not provide native support "
290
            "for half-precision floating point type."
291
        )
292

293

294
def _usm_types_walker(o, usm_types_list):
1✔
295
    if isinstance(o, dpt.usm_ndarray):
1✔
296
        usm_types_list.append(o.usm_type)
1✔
297
        return
1✔
298
    if hasattr(o, "__usm_ndarray__"):
1✔
299
        usm_arr = getattr(o, "__usm_ndarray__")
1✔
300
        if isinstance(usm_arr, dpt.usm_ndarray):
1!
301
            usm_types_list.append(usm_arr.usm_type)
1✔
302
            return
1✔
303
    if hasattr(o, "__sycl_usm_array_interface__"):
1✔
304
        usm_ar = _usm_ndarray_from_suai(o)
1✔
305
        usm_types_list.append(usm_ar.usm_type)
1✔
306
        return
1✔
307
    if _is_object_with_buffer_protocol(o):
1✔
308
        return
1✔
309
    if isinstance(o, (int, bool, float, complex)):
1✔
310
        return
1✔
311
    if isinstance(o, (list, tuple, range)):
1!
312
        for el in o:
1✔
313
            _usm_types_walker(el, usm_types_list)
1✔
314
        return
1✔
315
    raise TypeError
1✔
316

317

318
def _device_copy_walker(seq_o, res, _manager):
1✔
319
    if isinstance(seq_o, dpt.usm_ndarray):
1✔
320
        exec_q = res.sycl_queue
1✔
321
        deps = _manager.submitted_events
1✔
322
        ht_ev, cpy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
1✔
323
            src=seq_o, dst=res, sycl_queue=exec_q, depends=deps
324
        )
325
        _manager.add_event_pair(ht_ev, cpy_ev)
1✔
326
        return
1✔
327
    if hasattr(seq_o, "__usm_ndarray__"):
1✔
328
        usm_arr = getattr(seq_o, "__usm_ndarray__")
1✔
329
        if isinstance(usm_arr, dpt.usm_ndarray):
1!
330
            _device_copy_walker(usm_arr, res, _manager)
1✔
331
            return
1✔
332
    if hasattr(seq_o, "__sycl_usm_array_interface__"):
1✔
333
        usm_ar = _usm_ndarray_from_suai(seq_o)
1✔
334
        exec_q = res.sycl_queue
1✔
335
        deps = _manager.submitted_events
1✔
336
        ht_ev, cpy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
1✔
337
            src=usm_ar, dst=res, sycl_queue=exec_q, depends=deps
338
        )
339
        _manager.add_event_pair(ht_ev, cpy_ev)
1✔
340
        return
1✔
341
    if isinstance(seq_o, (list, tuple)):
1!
342
        for i, el in enumerate(seq_o):
1✔
343
            _device_copy_walker(el, res[i], _manager)
1✔
344
        return
1✔
345
    raise TypeError
1✔
346

347

348
def _copy_through_host_walker(seq_o, usm_res):
1✔
349
    if isinstance(seq_o, dpt.usm_ndarray):
1✔
350
        if (
1✔
351
            dpctl.utils.get_execution_queue(
352
                (
353
                    usm_res.sycl_queue,
354
                    seq_o.sycl_queue,
355
                )
356
            )
357
            is None
358
        ):
359
            usm_res[...] = dpt.asnumpy(seq_o).copy()
1✔
360
            return
×
361
        else:
362
            usm_res[...] = seq_o
1✔
363
    if hasattr(seq_o, "__usm_ndarray__"):
1✔
364
        usm_arr = getattr(seq_o, "__usm_ndarray__")
1✔
365
        if isinstance(usm_arr, dpt.usm_ndarray):
×
366
            _copy_through_host_walker(usm_arr, usm_res)
×
367
            return
×
368
    if hasattr(seq_o, "__sycl_usm_array_interface__"):
1✔
369
        usm_ar = _usm_ndarray_from_suai(seq_o)
1✔
370
        if (
1!
371
            dpctl.utils.get_execution_queue(
372
                (
373
                    usm_res.sycl_queue,
374
                    usm_ar.sycl_queue,
375
                )
376
            )
377
            is None
378
        ):
379
            usm_res[...] = dpt.asnumpy(usm_ar).copy()
1✔
380
        else:
381
            usm_res[...] = usm_ar
×
382
        return
1✔
383
    if _is_object_with_buffer_protocol(seq_o):
1✔
384
        np_ar = np.asarray(seq_o)
1✔
385
        usm_res[...] = np_ar
1✔
386
        return
1✔
387
    if isinstance(seq_o, (list, tuple)):
1✔
388
        for i, el in enumerate(seq_o):
1✔
389
            _copy_through_host_walker(el, usm_res[i])
1✔
390
        return
1✔
391
    usm_res[...] = np.asarray(seq_o)
1✔
392

393

394
def _asarray_from_seq(
1✔
395
    seq_obj,
396
    seq_shape,
397
    seq_dt,
398
    alloc_q,
399
    exec_q,
400
    dtype=None,
401
    usm_type=None,
402
    order="C",
403
):
404
    "`seq_obj` is a sequence"
405
    if usm_type is None:
1!
406
        usm_types_in_seq = []
1✔
407
        _usm_types_walker(seq_obj, usm_types_in_seq)
1✔
408
        usm_type = dpctl.utils.get_coerced_usm_type(usm_types_in_seq)
1✔
409
    dpctl.utils.validate_usm_type(usm_type)
1✔
410
    if dtype is None:
1!
411
        dtype = _map_to_device_dtype(seq_dt, alloc_q)
1✔
412
    else:
413
        _mapped_dt = _map_to_device_dtype(dtype, alloc_q)
×
414
        if _mapped_dt != dtype:
×
415
            raise ValueError(
×
416
                f"Device {alloc_q.sycl_device} "
417
                f"does not support {dtype} natively."
418
            )
419
        dtype = _mapped_dt
×
420
    if order in "KA":
1!
421
        order = "C"
1✔
422
    if isinstance(exec_q, dpctl.SyclQueue):
1✔
423
        res = dpt.empty(
1✔
424
            seq_shape,
425
            dtype=dtype,
426
            usm_type=usm_type,
427
            sycl_queue=alloc_q,
428
            order=order,
429
        )
430
        _manager = dpctl.utils.SequentialOrderManager[exec_q]
1✔
431
        _device_copy_walker(seq_obj, res, _manager)
1✔
432
        return res
1✔
433
    else:
434
        res = dpt.empty(
1✔
435
            seq_shape,
436
            dtype=dtype,
437
            usm_type=usm_type,
438
            sycl_queue=alloc_q,
439
            order=order,
440
        )
441
        _copy_through_host_walker(seq_obj, res)
1✔
442
        return res
1✔
443

444

445
def _asarray_from_seq_single_device(
1✔
446
    obj,
447
    seq_shape,
448
    seq_dt,
449
    seq_dev,
450
    dtype=None,
451
    usm_type=None,
452
    sycl_queue=None,
453
    order="C",
454
):
455
    if sycl_queue is None:
1✔
456
        exec_q = seq_dev
1✔
457
        alloc_q = seq_dev
1✔
458
    else:
459
        exec_q = dpctl.utils.get_execution_queue(
1✔
460
            (
461
                sycl_queue,
462
                seq_dev,
463
            )
464
        )
465
        alloc_q = sycl_queue
×
466
    return _asarray_from_seq(
1✔
467
        obj,
468
        seq_shape,
469
        seq_dt,
470
        alloc_q,
471
        exec_q,
472
        dtype=dtype,
473
        usm_type=usm_type,
474
        order=order,
475
    )
476

477

478
def asarray(
1✔
479
    obj,
480
    /,
481
    *,
482
    dtype=None,
483
    device=None,
484
    copy=None,
485
    usm_type=None,
486
    sycl_queue=None,
487
    order="K",
488
):
489
    """
490
    Converts input object to :class:`dpctl.tensor.usm_ndarray`.
491

492
    Args:
493
        obj: Python object to convert. Can be an instance of
494
            :class:`dpctl.tensor.usm_ndarray`,
495
            an object representing SYCL USM allocation and implementing
496
            ``__sycl_usm_array_interface__`` protocol, an instance
497
            of :class:`numpy.ndarray`, an object supporting Python buffer
498
            protocol, a Python scalar, or a (possibly nested) sequence of
499
            Python scalars.
500
        dtype (data type, optional):
501
            output array data type. If ``dtype`` is
502
            ``None``, the output array data type is inferred from data types in
503
            ``obj``. Default: ``None``
504
        copy (`bool`, optional):
505
            boolean indicating whether or not to copy the
506
            input. If ``True``, always creates a copy. If ``False``, the
507
            need to copy raises :exc:`ValueError`. If ``None``, tries to reuse
508
            existing memory allocations if possible, but allows to perform
509
            a copy otherwise. Default: ``None``
510
        order (``"C"``, ``"F"``, ``"A"``, ``"K"``, optional):
511
            memory layout of the output array. Default: ``"K"``
512
        device (optional): array API concept of device where the output array
513
            is created. ``device`` can be ``None``, a oneAPI filter selector
514
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
515
            a non-partitioned SYCL device, an instance of
516
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
517
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
518
            Default: ``None``
519
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
520
            The type of SYCL USM allocation for the output array.
521
            Default: ``"device"``
522
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
523
            The SYCL queue to use
524
            for output array allocation and copying. ``sycl_queue`` and
525
            ``device`` are complementary arguments, i.e. use one or another.
526
            If both are specified, a :exc:`TypeError` is raised unless both
527
            imply the same underlying SYCL queue to be used. If both are
528
            ``None``, a cached queue targeting default-selected device is
529
            used for allocation and population. Default: ``None``
530

531
    Returns:
532
        usm_ndarray:
533
            Array created from input object.
534
    """
535
    # 1. Check that copy is a valid keyword
536
    if copy not in [None, True, False]:
1✔
537
        raise TypeError(
1✔
538
            "Recognized copy keyword values should be True, False, or None"
539
        )
540
    # 2. Check that dtype is None, or a valid dtype
541
    if dtype is not None:
1✔
542
        dtype = dpt.dtype(dtype)
1✔
543
    # 3. Validate order
544
    if not isinstance(order, str):
1✔
545
        raise TypeError(
1✔
546
            f"Expected order keyword to be of type str, got {type(order)}"
547
        )
548
    if len(order) == 0 or order[0] not in "KkAaCcFf":
1✔
549
        raise ValueError(
1✔
550
            "Unrecognized order keyword value, expecting 'K', 'A', 'F', or 'C'."
551
        )
552
    order = order[0].upper()
1✔
553
    # 4. Check that usm_type is None, or a valid value
554
    dpctl.utils.validate_usm_type(usm_type, allow_none=True)
1✔
555
    # 5. Normalize device/sycl_queue [keep it None if was None]
556
    if device is not None or sycl_queue is not None:
1✔
557
        sycl_queue = normalize_queue_device(
1✔
558
            sycl_queue=sycl_queue, device=device
559
        )
560

561
    # handle instance(obj, usm_ndarray)
562
    if isinstance(obj, dpt.usm_ndarray):
1✔
563
        return _asarray_from_usm_ndarray(
1✔
564
            obj,
565
            dtype=dtype,
566
            copy=copy,
567
            usm_type=usm_type,
568
            sycl_queue=sycl_queue,
569
            order=order,
570
        )
571
    if hasattr(obj, "__usm_ndarray__"):
1✔
572
        usm_arr = getattr(obj, "__usm_ndarray__")
1✔
573
        if isinstance(usm_arr, dpt.usm_ndarray):
1!
574
            return _asarray_from_usm_ndarray(
1✔
575
                usm_arr,
576
                dtype=dtype,
577
                copy=copy,
578
                usm_type=usm_type,
579
                sycl_queue=sycl_queue,
580
                order=order,
581
            )
582
    if hasattr(obj, "__sycl_usm_array_interface__"):
1✔
583
        ary = _usm_ndarray_from_suai(obj)
1✔
584
        return _asarray_from_usm_ndarray(
1✔
585
            ary,
586
            dtype=dtype,
587
            copy=copy,
588
            usm_type=usm_type,
589
            sycl_queue=sycl_queue,
590
            order=order,
591
        )
592
    if isinstance(obj, np.ndarray):
1✔
593
        if copy is False:
1✔
594
            raise ValueError(
1✔
595
                "Converting numpy.ndarray to usm_ndarray requires a copy"
596
            )
597
        return _asarray_from_numpy_ndarray(
1✔
598
            obj,
599
            dtype=dtype,
600
            usm_type=usm_type,
601
            sycl_queue=sycl_queue,
602
            order=order,
603
        )
604
    if _is_object_with_buffer_protocol(obj):
1✔
605
        if copy is False:
1✔
606
            raise ValueError(
1✔
607
                f"Converting {type(obj)} to usm_ndarray requires a copy"
608
            )
609
        return _asarray_from_numpy_ndarray(
1✔
610
            np.array(obj),
611
            dtype=dtype,
612
            usm_type=usm_type,
613
            sycl_queue=sycl_queue,
614
            order=order,
615
        )
616
    if isinstance(obj, (list, tuple, range)):
1✔
617
        if copy is False:
1✔
618
            raise ValueError(
1✔
619
                "Converting Python sequence to usm_ndarray requires a copy"
620
            )
621
        seq_shape, seq_dt, devs = _array_info_sequence(obj)
1✔
622
        if devs == _host_set:
1✔
623
            return _asarray_from_numpy_ndarray(
1✔
624
                np.asarray(obj, dtype=dtype, order=order),
625
                dtype=dtype,
626
                usm_type=usm_type,
627
                sycl_queue=sycl_queue,
628
                order=order,
629
            )
630
        elif len(devs) == 1:
1✔
631
            seq_dev = list(devs)[0]
1✔
632
            return _asarray_from_seq_single_device(
1✔
633
                obj,
634
                seq_shape,
635
                seq_dt,
636
                seq_dev,
637
                dtype=dtype,
638
                usm_type=usm_type,
639
                sycl_queue=sycl_queue,
640
                order=order,
641
            )
642
        elif len(devs) > 1:
1!
643
            devs = [dev for dev in devs if dev is not None]
1✔
644
            if sycl_queue is None:
1✔
645
                if len(devs) == 1:
1✔
646
                    alloc_q = devs[0]
1✔
647
                else:
648
                    raise dpctl.utils.ExecutionPlacementError(
1✔
649
                        "Please specify `device` or `sycl_queue` keyword "
650
                        "argument to determine where to allocate the "
651
                        "resulting array."
652
                    )
653
            else:
654
                alloc_q = sycl_queue
1✔
655
            return _asarray_from_seq(
1✔
656
                obj,
657
                seq_shape,
658
                seq_dt,
659
                alloc_q,
660
                #  force copying via host
661
                None,
662
                dtype=dtype,
663
                usm_type=usm_type,
664
                order=order,
665
            )
666
    if copy is False:
1✔
667
        raise ValueError(
1✔
668
            f"Converting {type(obj)} to usm_ndarray requires a copy"
669
        )
670
    # obj is a scalar, create 0d array
671
    return _asarray_from_numpy_ndarray(
1✔
672
        np.asarray(obj, dtype=dtype),
673
        dtype=dtype,
674
        usm_type=usm_type,
675
        sycl_queue=sycl_queue,
676
        order="C",
677
    )
678

679

680
def empty(
1✔
681
    shape,
682
    *,
683
    dtype=None,
684
    order="C",
685
    device=None,
686
    usm_type="device",
687
    sycl_queue=None,
688
):
689
    """
690
    Creates :class:`dpctl.tensor.usm_ndarray` from uninitialized
691
    USM allocation.
692

693
    Args:
694
        shape (Tuple[int], int):
695
            Dimensions of the array to be created.
696
        dtype (optional):
697
            data type of the array. Can be typestring,
698
            a :class:`numpy.dtype` object, :mod:`numpy` char string,
699
            or a NumPy scalar type. The ``None`` value creates an
700
            array of floating point data type. Default: ``None``
701
        order (``"C"``, or ``F"``):
702
            memory layout for the array. Default: ``"C"``
703
        device (optional): array API concept of device where the output array
704
            is created. ``device`` can be ``None``, a oneAPI filter selector
705
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
706
            a non-partitioned SYCL device, an instance of
707
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
708
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
709
            Default: ``None``
710
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
711
            The type of SYCL USM allocation for the output array.
712
            Default: ``"device"``
713
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
714
            The SYCL queue to use
715
            for output array allocation and copying. ``sycl_queue`` and
716
            ``device`` are complementary arguments, i.e. use one or another.
717
            If both are specified, a :exc:`TypeError` is raised unless both
718
            imply the same underlying SYCL queue to be used. If both are
719
            ``None``, a cached queue targeting default-selected device is
720
            used for allocation and population. Default: ``None``
721

722
    Returns:
723
        usm_ndarray:
724
            Created empty array.
725
    """
726
    if not isinstance(order, str) or len(order) == 0 or order[0] not in "CcFf":
1✔
727
        raise ValueError(
1✔
728
            "Unrecognized order keyword value, expecting 'F' or 'C'."
729
        )
730
    order = order[0].upper()
1✔
731
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
732
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
733
    dtype = _get_dtype(dtype, sycl_queue)
1✔
734
    _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
735
    res = dpt.usm_ndarray(
1✔
736
        shape,
737
        dtype=dtype,
738
        buffer=usm_type,
739
        order=order,
740
        buffer_ctor_kwargs={"queue": sycl_queue},
741
    )
742
    return res
1✔
743

744

745
def _coerce_and_infer_dt(*args, dt, sycl_queue, err_msg, allow_bool=False):
1✔
746
    "Deduce arange type from sequence spec"
747
    nd, seq_dt, d = _array_info_sequence(args)
1✔
748
    if d != _host_set or nd != (len(args),):
1✔
749
        raise ValueError(err_msg)
1✔
750
    dt = _get_dtype(dt, sycl_queue, ref_type=seq_dt)
1✔
751
    if np.issubdtype(dt, np.integer):
1✔
752
        return tuple(int(v) for v in args), dt
1✔
753
    if np.issubdtype(dt, np.floating):
1✔
754
        return tuple(float(v) for v in args), dt
1✔
755
    if np.issubdtype(dt, np.complexfloating):
1✔
756
        return tuple(complex(v) for v in args), dt
1✔
757
    if allow_bool and dt.char == "?":
1!
758
        return tuple(bool(v) for v in args), dt
1✔
759
    raise ValueError(f"Data type {dt} is not supported")
1✔
760

761

762
def _round_for_arange(tmp):
1✔
763
    k = int(tmp)
1✔
764
    if k >= 0 and float(k) < tmp:
1✔
765
        tmp = tmp + 1
1✔
766
    return tmp
1✔
767

768

769
def _get_arange_length(start, stop, step):
1✔
770
    "Compute length of arange sequence"
771
    span = stop - start
1✔
772
    if hasattr(step, "__float__") and hasattr(span, "__float__"):
1!
773
        return _round_for_arange(span / step)
1✔
774
    tmp = span / step
1✔
775
    if hasattr(tmp, "__complex__"):
1!
776
        tmp = complex(tmp)
1✔
777
        tmp = tmp.real
1✔
778
    else:
779
        tmp = float(tmp)
1✔
780
    return _round_for_arange(tmp)
1✔
781

782

783
def _to_scalar(obj, sc_ty):
1✔
784
    """A way to convert object to NumPy scalar type.
785
    Raises OverflowError if obj can not be represented
786
    using the requested scalar type.
787
    """
788
    zd_arr = np.asarray(obj, dtype=sc_ty)
1✔
789
    return zd_arr[tuple()]
1✔
790

791

792
def arange(
1✔
793
    start,
794
    /,
795
    stop=None,
796
    step=1,
797
    *,
798
    dtype=None,
799
    device=None,
800
    usm_type="device",
801
    sycl_queue=None,
802
):
803
    """
804
    Returns evenly spaced values within the half-open interval [start, stop)
805
    as a one-dimensional array.
806

807
    Args:
808
        start:
809
            Starting point of the interval
810
        stop:
811
            Ending point of the interval. Default: ``None``
812
        step: Increment of the returned sequence. Default: ``1``
813
        dtype: Output array data type. Default: ``None``
814
        device (optional): array API concept of device where the output array
815
            is created. ``device`` can be ``None``, a oneAPI filter selector
816
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
817
            a non-partitioned SYCL device, an instance of
818
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
819
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
820
            Default: ``None``
821
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
822
            The type of SYCL USM allocation for the output array.
823
            Default: ``"device"``
824
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
825
            The SYCL queue to use
826
            for output array allocation and copying. ``sycl_queue`` and
827
            ``device`` are complementary arguments, i.e. use one or another.
828
            If both are specified, a :exc:`TypeError` is raised unless both
829
            imply the same underlying SYCL queue to be used. If both are
830
            ``None``, a cached queue targeting default-selected device is
831
            used for allocation and population. Default: ``None``
832

833
    Returns:
834
        usm_ndarray:
835
            Array populated with evenly spaced values.
836
    """
837
    if stop is None:
1✔
838
        stop = start
1✔
839
        start = 0
1✔
840
    if step is None:
1✔
841
        step = 1
1✔
842
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
843
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
844
    is_bool = False
1✔
845
    if dtype:
1✔
846
        is_bool = (dtype is bool) or (dpt.dtype(dtype) == dpt.bool)
1✔
847
    _, dt = _coerce_and_infer_dt(
1✔
848
        start,
849
        stop,
850
        step,
851
        dt=dpt.int8 if is_bool else dtype,
852
        sycl_queue=sycl_queue,
853
        err_msg="start, stop, and step must be Python scalars",
854
        allow_bool=False,
855
    )
856
    try:
1✔
857
        tmp = _get_arange_length(start, stop, step)
1✔
858
        sh = max(int(tmp), 0)
1✔
859
    except TypeError:
×
860
        sh = 0
×
861
    if is_bool and sh > 2:
1!
UNCOV
862
        raise ValueError("no fill-function for boolean data type")
×
863
    res = dpt.usm_ndarray(
1✔
864
        (sh,),
865
        dtype=dt,
866
        buffer=usm_type,
867
        order="C",
868
        buffer_ctor_kwargs={"queue": sycl_queue},
869
    )
870
    sc_ty = dt.type
1✔
871
    _first = _to_scalar(start, sc_ty)
1✔
872
    if sh > 1:
1✔
873
        _second = _to_scalar(start + step, sc_ty)
1✔
874
        if dt in [dpt.uint8, dpt.uint16, dpt.uint32, dpt.uint64]:
1✔
875
            int64_ty = dpt.int64.type
1✔
876
            _step = int64_ty(_second) - int64_ty(_first)
1✔
877
        else:
878
            _step = _second - _first
1✔
879
        _step = sc_ty(_step)
1✔
880
    else:
881
        _step = sc_ty(1)
1✔
882
    _start = _first
1✔
883
    _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
884
    # populating newly allocated array, no task dependencies
885
    hev, lin_ev = ti._linspace_step(_start, _step, res, sycl_queue)
1✔
886
    _manager.add_event_pair(hev, lin_ev)
1✔
887
    if is_bool:
1✔
888
        res_out = dpt.usm_ndarray(
1✔
889
            (sh,),
890
            dtype=dpt.bool,
891
            buffer=usm_type,
892
            order="C",
893
            buffer_ctor_kwargs={"queue": sycl_queue},
894
        )
895
        hev_cpy, cpy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
1✔
896
            src=res, dst=res_out, sycl_queue=sycl_queue, depends=[lin_ev]
897
        )
898
        _manager.add_event_pair(hev_cpy, cpy_ev)
1✔
899
        return res_out
1✔
900
    return res
1✔
901

902

903
def zeros(
1✔
904
    shape,
905
    *,
906
    dtype=None,
907
    order="C",
908
    device=None,
909
    usm_type="device",
910
    sycl_queue=None,
911
):
912
    """
913
    Returns a new :class:`dpctl.tensor.usm_ndarray` having a specified
914
    shape and filled with zeros.
915

916
    Args:
917
        shape (Tuple[int], int):
918
            Dimensions of the array to be created.
919
        dtype (optional):
920
            data type of the array. Can be typestring,
921
            a :class:`numpy.dtype` object, :mod:`numpy` char string,
922
            or a NumPy scalar type. Default: ``None``
923
        order ("C", or "F"):
924
            memory layout for the array. Default: ``"C"``
925
        device (optional): array API concept of device where the output array
926
            is created. ``device`` can be ``None``, a oneAPI filter selector
927
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
928
            a non-partitioned SYCL device, an instance of
929
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
930
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
931
            Default: ``None``
932
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
933
            The type of SYCL USM allocation for the output array.
934
            Default: ``"device"``
935
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
936
            The SYCL queue to use
937
            for output array allocation and copying. ``sycl_queue`` and
938
            ``device`` are complementary arguments, i.e. use one or another.
939
            If both are specified, a :exc:`TypeError` is raised unless both
940
            imply the same underlying SYCL queue to be used. If both are
941
            ``None``, a cached queue targeting default-selected device is
942
            used for allocation and population. Default: ``None``
943

944
    Returns:
945
        usm_ndarray:
946
            Constructed array initialized with zeros.
947
    """
948
    if not isinstance(order, str) or len(order) == 0 or order[0] not in "CcFf":
1✔
949
        raise ValueError(
1✔
950
            "Unrecognized order keyword value, expecting 'F' or 'C'."
951
        )
952
    order = order[0].upper()
1✔
953
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
954
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
955
    dtype = _get_dtype(dtype, sycl_queue)
1✔
956
    _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
957
    res = dpt.usm_ndarray(
1✔
958
        shape,
959
        dtype=dtype,
960
        buffer=usm_type,
961
        order=order,
962
        buffer_ctor_kwargs={"queue": sycl_queue},
963
    )
964
    _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
965
    # populating new allocation, no dependent events
966
    hev, zeros_ev = ti._zeros_usm_ndarray(res, sycl_queue)
1✔
967
    _manager.add_event_pair(hev, zeros_ev)
1✔
968

969
    return res
1✔
970

971

972
def ones(
1✔
973
    shape,
974
    *,
975
    dtype=None,
976
    order="C",
977
    device=None,
978
    usm_type="device",
979
    sycl_queue=None,
980
):
981
    """ ones(shape, dtype=None, order="C", \
982
             device=None, usm_type="device", sycl_queue=None)
983

984
    Returns a new :class:`dpctl.tensor.usm_ndarray` having a specified
985
    shape and filled with ones.
986

987
    Args:
988
        shape (Tuple[int], int):
989
            Dimensions of the array to be created.
990
        dtype (optional):
991
            data type of the array. Can be typestring,
992
            a :class:`numpy.dtype` object, :mod:`numpy` char string,
993
            or a NumPy scalar type. Default: ``None``
994
        order ("C", or "F"): memory layout for the array. Default: ``"C"``
995
        device (optional): array API concept of device where the output array
996
            is created. ``device`` can be ``None``, a oneAPI filter selector
997
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
998
            a non-partitioned SYCL device, an instance of
999
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1000
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1001
            Default: ``None``
1002
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1003
            The type of SYCL USM allocation for the output array.
1004
            Default: ``"device"``
1005
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1006
            The SYCL queue to use
1007
            for output array allocation and copying. ``sycl_queue`` and
1008
            ``device`` are complementary arguments, i.e. use one or another.
1009
            If both are specified, a :exc:`TypeError` is raised unless both
1010
            imply the same underlying SYCL queue to be used. If both are
1011
            ``None``, a cached queue targeting default-selected device is
1012
            used for allocation and population. Default: ``None``
1013

1014
    Returns:
1015
        usm_ndarray:
1016
            Created array initialized with ones.
1017
    """
1018
    if not isinstance(order, str) or len(order) == 0 or order[0] not in "CcFf":
1✔
1019
        raise ValueError(
1✔
1020
            "Unrecognized order keyword value, expecting 'F' or 'C'."
1021
        )
1022
    order = order[0].upper()
1✔
1023
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1024
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1025
    dtype = _get_dtype(dtype, sycl_queue)
1✔
1026
    res = dpt.usm_ndarray(
1✔
1027
        shape,
1028
        dtype=dtype,
1029
        buffer=usm_type,
1030
        order=order,
1031
        buffer_ctor_kwargs={"queue": sycl_queue},
1032
    )
1033
    _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1034
    # populating new allocation, no dependent events
1035
    hev, full_ev = ti._full_usm_ndarray(1, res, sycl_queue)
1✔
1036
    _manager.add_event_pair(hev, full_ev)
1✔
1037
    return res
1✔
1038

1039

1040
def _cast_fill_val(fill_val, dt):
1✔
1041
    """
1042
    Casts the Python scalar `fill_val` to another Python type coercible to the
1043
    requested data type `dt`, if necessary.
1044
    """
1045
    val_type = type(fill_val)
1✔
1046
    if val_type in [float, complex] and np.issubdtype(dt, np.integer):
1✔
1047
        return int(fill_val.real)
1✔
1048
    elif val_type is complex and np.issubdtype(dt, np.floating):
1✔
1049
        return fill_val.real
1✔
1050
    elif val_type is int and np.issubdtype(dt, np.integer):
1✔
1051
        return _to_scalar(fill_val, dt)
1✔
1052
    else:
1053
        return fill_val
1✔
1054

1055

1056
def _validate_fill_value(fill_val):
1✔
1057
    """
1058
    Validates that `fill_val` is a numeric or boolean scalar.
1059
    """
1060
    # TODO: verify if `np.True_` and `np.False_` should be instances of
1061
    # Number in NumPy, like other NumPy scalars and like Python bools
1062
    # check for `np.bool_` separately as NumPy<2 has no `np.bool`
1063
    if not isinstance(fill_val, Number) and not isinstance(fill_val, np.bool_):
1✔
1064
        raise TypeError(
1✔
1065
            f"array cannot be filled with scalar of type {type(fill_val)}"
1066
        )
1067

1068

1069
def full(
1✔
1070
    shape,
1071
    fill_value,
1072
    *,
1073
    dtype=None,
1074
    order="C",
1075
    device=None,
1076
    usm_type=None,
1077
    sycl_queue=None,
1078
):
1079
    """
1080
    Returns a new :class:`dpctl.tensor.usm_ndarray` having a specified
1081
    shape and filled with `fill_value`.
1082

1083
    Args:
1084
        shape (tuple):
1085
            Dimensions of the array to be created.
1086
        fill_value (int,float,complex,usm_ndarray):
1087
            fill value
1088
        dtype (optional): data type of the array. Can be typestring,
1089
            a :class:`numpy.dtype` object, :mod:`numpy` char string,
1090
            or a NumPy scalar type. Default: ``None``
1091
        order ("C", or "F"):
1092
            memory layout for the array. Default: ``"C"``
1093
        device (optional): array API concept of device where the output array
1094
            is created. ``device`` can be ``None``, a oneAPI filter selector
1095
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1096
            a non-partitioned SYCL device, an instance of
1097
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1098
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1099
            Default: ``None``
1100
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1101
            The type of SYCL USM allocation for the output array.
1102
            Default: ``"device"``
1103
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1104
            The SYCL queue to use
1105
            for output array allocation and copying. ``sycl_queue`` and
1106
            ``device`` are complementary arguments, i.e. use one or another.
1107
            If both are specified, a :exc:`TypeError` is raised unless both
1108
            imply the same underlying SYCL queue to be used. If both are
1109
            ``None``, a cached queue targeting default-selected device is
1110
            used for allocation and population. Default: ``None``
1111

1112
    Returns:
1113
        usm_ndarray:
1114
            New array initialized with given value.
1115
    """
1116
    if not isinstance(order, str) or len(order) == 0 or order[0] not in "CcFf":
1✔
1117
        raise ValueError(
1✔
1118
            "Unrecognized order keyword value, expecting 'F' or 'C'."
1119
        )
1120
    order = order[0].upper()
1✔
1121
    dpctl.utils.validate_usm_type(usm_type, allow_none=True)
1✔
1122

1123
    if isinstance(fill_value, (dpt.usm_ndarray, np.ndarray, tuple, list)):
1✔
1124
        if (
1✔
1125
            isinstance(fill_value, dpt.usm_ndarray)
1126
            and sycl_queue is None
1127
            and device is None
1128
        ):
1129
            sycl_queue = fill_value.sycl_queue
1✔
1130
        else:
1131
            sycl_queue = normalize_queue_device(
1✔
1132
                sycl_queue=sycl_queue, device=device
1133
            )
1134
        X = dpt.asarray(
1✔
1135
            fill_value,
1136
            dtype=dtype,
1137
            order=order,
1138
            usm_type=usm_type,
1139
            sycl_queue=sycl_queue,
1140
        )
1141
        return dpt.copy(dpt.broadcast_to(X, shape), order=order)
1✔
1142
    else:
1143
        _validate_fill_value(fill_value)
1✔
1144

1145
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1146
    usm_type = usm_type if usm_type is not None else "device"
1✔
1147
    dtype = _get_dtype(dtype, sycl_queue, ref_type=type(fill_value))
1✔
1148
    res = dpt.usm_ndarray(
1✔
1149
        shape,
1150
        dtype=dtype,
1151
        buffer=usm_type,
1152
        order=order,
1153
        buffer_ctor_kwargs={"queue": sycl_queue},
1154
    )
1155
    fill_value = _cast_fill_val(fill_value, dtype)
1✔
1156

1157
    _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1158
    # populating new allocation, no dependent events
1159
    hev, full_ev = ti._full_usm_ndarray(fill_value, res, sycl_queue)
1✔
1160
    _manager.add_event_pair(hev, full_ev)
1✔
1161
    return res
1✔
1162

1163

1164
def _normalize_order(order, arr):
1✔
1165
    """
1166
    Utility function for processing the `order` keyword of array-like
1167
    constructors, which support `"K"` and `"A"` orders.
1168
    """
1169
    arr_flags = arr.flags
1✔
1170
    f_contig = arr_flags["F"]
1✔
1171
    c_contig = arr_flags["C"]
1✔
1172
    if order == "A":
1✔
1173
        order = "F" if f_contig and not c_contig else "C"
1✔
1174
    if order == "K" and (f_contig or c_contig):
1✔
1175
        order = "C" if c_contig else "F"
1✔
1176
    return order
1✔
1177

1178

1179
def empty_like(
1✔
1180
    x, /, *, dtype=None, order="K", device=None, usm_type=None, sycl_queue=None
1181
):
1182
    """
1183
    Returns an uninitialized :class:`dpctl.tensor.usm_ndarray` with the
1184
    same `shape` as the input array `x`.
1185

1186
    Args:
1187
        x (usm_ndarray):
1188
            Input array from which to derive the output array shape.
1189
        dtype (optional):
1190
            data type of the array. Can be a typestring,
1191
            a :class:`numpy.dtype` object, NumPy char string,
1192
            or a NumPy scalar type. Default: ``None``
1193
        order ("C", "F", "A", or "K"):
1194
            memory layout for the array. Default: ``"K"``
1195
        device (optional): array API concept of device where the output array
1196
            is created. ``device`` can be ``None``, a oneAPI filter selector
1197
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1198
            a non-partitioned SYCL device, an instance of
1199
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1200
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1201
            Default: ``None``
1202
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1203
            The type of SYCL USM allocation for the output array.
1204
            Default: ``"device"``
1205
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1206
            The SYCL queue to use
1207
            for output array allocation and copying. ``sycl_queue`` and
1208
            ``device`` are complementary arguments, i.e. use one or another.
1209
            If both are specified, a :exc:`TypeError` is raised unless both
1210
            imply the same underlying SYCL queue to be used. If both are
1211
            ``None``, a cached queue targeting default-selected device is
1212
            used for allocation. Default: ``None``
1213

1214
    Returns:
1215
        usm_ndarray:
1216
            Created empty array with uninitialized memory.
1217
    """
1218
    if not isinstance(x, dpt.usm_ndarray):
1✔
1219
        raise TypeError(f"Expected instance of dpt.usm_ndarray, got {type(x)}.")
1✔
1220
    if (
1✔
1221
        not isinstance(order, str)
1222
        or len(order) == 0
1223
        or order[0] not in "CcFfAaKk"
1224
    ):
1225
        raise ValueError(
1✔
1226
            "Unrecognized order keyword value, expecting 'C', 'F', 'A', or 'K'."
1227
        )
1228
    order = order[0].upper()
1✔
1229
    if dtype is None:
1✔
1230
        dtype = x.dtype
1✔
1231
    if usm_type is None:
1✔
1232
        usm_type = x.usm_type
1✔
1233
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1234
    if device is None and sycl_queue is None:
1✔
1235
        device = x.device
1✔
1236
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1237
    dtype = dpt.dtype(dtype)
1✔
1238
    order = _normalize_order(order, x)
1✔
1239
    if order == "K":
1✔
1240
        _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1241
        return _empty_like_orderK(x, dtype, usm_type, sycl_queue)
1✔
1242
    else:
1243
        shape = x.shape
1✔
1244
        _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1245
        res = dpt.usm_ndarray(
1✔
1246
            shape,
1247
            dtype=dtype,
1248
            buffer=usm_type,
1249
            order=order,
1250
            buffer_ctor_kwargs={"queue": sycl_queue},
1251
        )
1252
        return res
1✔
1253

1254

1255
def zeros_like(
1✔
1256
    x, /, *, dtype=None, order="K", device=None, usm_type=None, sycl_queue=None
1257
):
1258
    """
1259
    Creates :class:`dpctl.tensor.usm_ndarray` from USM allocation
1260
    initialized with zeros.
1261

1262
    Args:
1263
        x (usm_ndarray):
1264
            Input array from which to derive the shape of the
1265
            output array.
1266
        dtype (optional):
1267
            data type of the array. Can be typestring,
1268
            a :class:`numpy.dtype` object, :mod:`numpy` char string, or a
1269
            NumPy scalar type. If `None`, output array has the same data
1270
            type as the input array. Default: ``None``
1271
        order ("C", or "F"):
1272
            memory layout for the array. Default: ``"C"``
1273
        device (optional):
1274
            array API concept of device where the output array
1275
            is created. ``device`` can be ``None``, a oneAPI filter selector
1276
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1277
            a non-partitioned SYCL device, an instance of
1278
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1279
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1280
            Default: ``None``
1281
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1282
            The type of SYCL USM allocation for the output array.
1283
            Default: ``"device"``
1284
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1285
            The SYCL queue to use
1286
            for output array allocation and copying. ``sycl_queue`` and
1287
            ``device`` are complementary arguments, i.e. use one or another.
1288
            If both are specified, a :exc:`TypeError` is raised unless both
1289
            imply the same underlying SYCL queue to be used. If both are
1290
            ``None``, a cached queue targeting default-selected device is
1291
            used for allocation and population. Default: ``None``
1292

1293
    Returns:
1294
        usm_ndarray:
1295
            New array initialized with zeros.
1296
    """
1297
    if not isinstance(x, dpt.usm_ndarray):
1✔
1298
        raise TypeError(f"Expected instance of dpt.usm_ndarray, got {type(x)}.")
1✔
1299
    if (
1✔
1300
        not isinstance(order, str)
1301
        or len(order) == 0
1302
        or order[0] not in "CcFfAaKk"
1303
    ):
1304
        raise ValueError(
1✔
1305
            "Unrecognized order keyword value, expecting 'C', 'F', 'A', or 'K'."
1306
        )
1307
    order = order[0].upper()
1✔
1308
    if dtype is None:
1✔
1309
        dtype = x.dtype
1✔
1310
    if usm_type is None:
1!
1311
        usm_type = x.usm_type
1✔
1312
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1313
    if device is None and sycl_queue is None:
1✔
1314
        device = x.device
1✔
1315
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1316
    dtype = dpt.dtype(dtype)
1✔
1317
    order = _normalize_order(order, x)
1✔
1318
    if order == "K":
1✔
1319
        _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1320
        res = _empty_like_orderK(x, dtype, usm_type, sycl_queue)
1✔
1321
        _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1322
        # populating new allocation, no dependent events
1323
        hev, full_ev = ti._full_usm_ndarray(0, res, sycl_queue)
1✔
1324
        _manager.add_event_pair(hev, full_ev)
1✔
1325
        return res
1✔
1326
    else:
1327
        _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1328
        sh = x.shape
1✔
1329
        return zeros(
1✔
1330
            sh,
1331
            dtype=dtype,
1332
            order=order,
1333
            device=device,
1334
            usm_type=usm_type,
1335
            sycl_queue=sycl_queue,
1336
        )
1337

1338

1339
def ones_like(
1✔
1340
    x, /, *, dtype=None, order="K", device=None, usm_type=None, sycl_queue=None
1341
):
1342
    """
1343
    Returns a new :class:`dpctl.tensor.usm_ndarray` filled with ones and
1344
    having the same `shape` as the input array `x`.
1345

1346
    Args:
1347
        x (usm_ndarray):
1348
            Input array from which to derive the output array shape
1349
        dtype (optional):
1350
            data type of the array. Can be typestring,
1351
            a :class:`numpy.dtype` object, :mod:`numpy` char string,
1352
            or a NumPy scalar type. Default: `None`
1353
        order ("C", "F", "A", or "K"):
1354
            memory layout for the array. Default: ``"C"``
1355
        device (optional):
1356
            array API concept of device where the output array
1357
            is created. ``device`` can be ``None``, a oneAPI filter selector
1358
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1359
            a non-partitioned SYCL device, an instance of
1360
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1361
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1362
            Default: ``None``
1363
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1364
            The type of SYCL USM allocation for the output array.
1365
            Default: ``"device"``
1366
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1367
            The SYCL queue to use
1368
            for output array allocation and copying. ``sycl_queue`` and
1369
            ``device`` are complementary arguments, i.e. use one or another.
1370
            If both are specified, a :exc:`TypeError` is raised unless both
1371
            imply the same underlying SYCL queue to be used. If both are
1372
            ``None``, a cached queue targeting default-selected device is
1373
            used for allocation and population. Default: ``None``
1374

1375
    Returns:
1376
        usm_ndarray:
1377
            New array initialized with ones.
1378
    """
1379
    if not isinstance(x, dpt.usm_ndarray):
1✔
1380
        raise TypeError(f"Expected instance of dpt.usm_ndarray, got {type(x)}.")
1✔
1381
    if (
1✔
1382
        not isinstance(order, str)
1383
        or len(order) == 0
1384
        or order[0] not in "CcFfAaKk"
1385
    ):
1386
        raise ValueError(
1✔
1387
            "Unrecognized order keyword value, expecting 'C', 'F', 'A', or 'K'."
1388
        )
1389
    order = order[0].upper()
1✔
1390
    if dtype is None:
1✔
1391
        dtype = x.dtype
1✔
1392
    if usm_type is None:
1✔
1393
        usm_type = x.usm_type
1✔
1394
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1395
    if device is None and sycl_queue is None:
1✔
1396
        device = x.device
1✔
1397
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1398
    dtype = dpt.dtype(dtype)
1✔
1399
    order = _normalize_order(order, x)
1✔
1400
    if order == "K":
1✔
1401
        _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1402
        res = _empty_like_orderK(x, dtype, usm_type, sycl_queue)
1✔
1403
        _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1404
        # populating new allocation, no dependent events
1405
        hev, full_ev = ti._full_usm_ndarray(1, res, sycl_queue)
1✔
1406
        _manager.add_event_pair(hev, full_ev)
1✔
1407
        return res
1✔
1408
    else:
1409
        sh = x.shape
1✔
1410
        return ones(
1✔
1411
            sh,
1412
            dtype=dtype,
1413
            order=order,
1414
            device=device,
1415
            usm_type=usm_type,
1416
            sycl_queue=sycl_queue,
1417
        )
1418

1419

1420
def full_like(
1✔
1421
    x,
1422
    /,
1423
    fill_value,
1424
    *,
1425
    dtype=None,
1426
    order="K",
1427
    device=None,
1428
    usm_type=None,
1429
    sycl_queue=None,
1430
):
1431
    """ full_like(x, fill_value, dtype=None, order="K", \
1432
                  device=None, usm_type=None, sycl_queue=None)
1433

1434
    Returns a new :class:`dpctl.tensor.usm_ndarray` filled with `fill_value`
1435
    and having the same `shape` as the input array `x`.
1436

1437
    Args:
1438
        x (usm_ndarray): Input array from which to derive the output array
1439
            shape.
1440
        fill_value: the value to fill output array with
1441
        dtype (optional):
1442
            data type of the array. Can be typestring,
1443
            a :class:`numpy.dtype` object, :mod:`numpy` char string, or a
1444
            NumPy scalar type. If ``dtype`` is ``None``, the output array data
1445
            type is inferred from ``x``. Default: ``None``
1446
        order ("C", "F", "A", or "K"):
1447
            memory layout for the array. Default: ``"K"``
1448
        device (optional):
1449
            array API concept of device where the output array
1450
            is created. ``device`` can be ``None``, a oneAPI filter selector
1451
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1452
            a non-partitioned SYCL device, an instance of
1453
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1454
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1455
            Default: ``None``
1456
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1457
            The type of SYCL USM allocation for the output array.
1458
            Default: ``"device"``
1459
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1460
            The SYCL queue to use
1461
            for output array allocation and copying. ``sycl_queue`` and
1462
            ``device`` are complementary arguments, i.e. use one or another.
1463
            If both are specified, a :exc:`TypeError` is raised unless both
1464
            imply the same underlying SYCL queue to be used. If both are
1465
            ``None``, a cached queue targeting default-selected device is
1466
            used for allocation and population. Default: ``None``
1467

1468
    Returns:
1469
        usm_ndarray:
1470
            New array initialized with given value.
1471
    """
1472
    if not isinstance(x, dpt.usm_ndarray):
1✔
1473
        raise TypeError(f"Expected instance of dpt.usm_ndarray, got {type(x)}.")
1✔
1474
    if (
1✔
1475
        not isinstance(order, str)
1476
        or len(order) == 0
1477
        or order[0] not in "CcFfAaKk"
1478
    ):
1479
        raise ValueError(
1✔
1480
            "Unrecognized order keyword value, expecting 'C', 'F', 'A', or 'K'."
1481
        )
1482
    order = order[0].upper()
1✔
1483
    if dtype is None:
1✔
1484
        dtype = x.dtype
1✔
1485
    if usm_type is None:
1!
1486
        usm_type = x.usm_type
1✔
1487
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1488
    if device is None and sycl_queue is None:
1!
1489
        device = x.device
1✔
1490
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1491
    sh = x.shape
1✔
1492
    dtype = dpt.dtype(dtype)
1✔
1493
    order = _normalize_order(order, x)
1✔
1494
    if order == "K":
1✔
1495
        _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1496
        if isinstance(fill_value, (dpt.usm_ndarray, np.ndarray, tuple, list)):
1!
1497
            X = dpt.asarray(
×
1498
                fill_value,
1499
                dtype=dtype,
1500
                order=order,
1501
                usm_type=usm_type,
1502
                sycl_queue=sycl_queue,
1503
            )
1504
            X = dpt.broadcast_to(X, sh)
×
1505
            res = _empty_like_orderK(x, dtype, usm_type, sycl_queue)
×
1506
            _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
×
1507
            # order copy after tasks populating X
1508
            dep_evs = _manager.submitted_events
×
1509
            hev, copy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
×
1510
                src=X, dst=res, sycl_queue=sycl_queue, depends=dep_evs
1511
            )
1512
            _manager.add_event_pair(hev, copy_ev)
×
1513
            return res
×
1514
        else:
1515
            _validate_fill_value(fill_value)
1✔
1516

1517
        dtype = _get_dtype(dtype, sycl_queue, ref_type=type(fill_value))
1✔
1518
        res = _empty_like_orderK(x, dtype, usm_type, sycl_queue)
1✔
1519
        fill_value = _cast_fill_val(fill_value, dtype)
1✔
1520
        _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1521
        # populating new allocation, no dependent events
1522
        hev, full_ev = ti._full_usm_ndarray(fill_value, res, sycl_queue)
1✔
1523
        _manager.add_event_pair(hev, full_ev)
1✔
1524
        return res
1✔
1525
    else:
1526
        return full(
1✔
1527
            sh,
1528
            fill_value,
1529
            dtype=dtype,
1530
            order=order,
1531
            device=device,
1532
            usm_type=usm_type,
1533
            sycl_queue=sycl_queue,
1534
        )
1535

1536

1537
def linspace(
1✔
1538
    start,
1539
    stop,
1540
    /,
1541
    num,
1542
    *,
1543
    dtype=None,
1544
    device=None,
1545
    endpoint=True,
1546
    sycl_queue=None,
1547
    usm_type="device",
1548
):
1549
    """
1550
    linspace(start, stop, num, dtype=None, device=None, endpoint=True, \
1551
        sycl_queue=None, usm_type="device")
1552

1553
    Returns :class:`dpctl.tensor.usm_ndarray` array populated with
1554
    evenly spaced numbers of specified interval.
1555

1556
    Args:
1557
        start:
1558
            the start of the interval.
1559
        stop:
1560
            the end of the interval. If the ``endpoint`` is ``False``, the
1561
            function generates ``num+1`` evenly spaced points starting
1562
            with ``start`` and ending with ``stop`` and exclude the
1563
            ``stop`` from the returned array such that the returned array
1564
            consists of evenly spaced numbers over the half-open interval
1565
            ``[start, stop)``. If ``endpoint`` is ``True``, the output
1566
            array consists of evenly spaced numbers over the closed
1567
            interval ``[start, stop]``. Default: ``True``
1568
        num (int):
1569
            number of samples. Must be a non-negative integer; otherwise,
1570
            the function raises ``ValueError`` exception.
1571
        dtype:
1572
            output array data type. Should be a floating data type.
1573
            If ``dtype`` is ``None``, the output array must be the default
1574
            floating point data type for target device.
1575
            Default: ``None``
1576
        device (optional):
1577
            array API concept of device where the output array
1578
            is created. ``device`` can be ``None``, a oneAPI filter selector
1579
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1580
            a non-partitioned SYCL device, an instance of
1581
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1582
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1583
            Default: ``None``
1584
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1585
            The type of SYCL USM allocation for the output array.
1586
            Default: ``"device"``
1587
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1588
            The SYCL queue to use
1589
            for output array allocation and copying. ``sycl_queue`` and
1590
            ``device`` are complementary arguments, i.e. use one or another.
1591
            If both are specified, a :exc:`TypeError` is raised unless both
1592
            imply the same underlying SYCL queue to be used. If both are
1593
            ``None``, a cached queue targeting default-selected device is
1594
            used for allocation and population. Default: ``None``
1595
        endpoint: boolean indicating whether to include ``stop`` in the
1596
            interval. Default: ``True``
1597

1598
    Returns:
1599
        usm_ndarray:
1600
            Array populated with evenly spaced numbers in the requested
1601
            interval.
1602
    """
1603
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1604
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1605
    if endpoint not in [True, False]:
1!
1606
        raise TypeError("endpoint keyword argument must be of boolean type")
×
1607
    num = operator.index(num)
1✔
1608
    if num < 0:
1!
1609
        raise ValueError("Number of points must be non-negative")
×
1610
    _, dt = _coerce_and_infer_dt(
1✔
1611
        start,
1612
        stop,
1613
        dt=dtype,
1614
        sycl_queue=sycl_queue,
1615
        err_msg="start and stop must be Python scalars.",
1616
        allow_bool=True,
1617
    )
1618
    int_dt = None
1✔
1619
    if np.issubdtype(dt, np.integer):
1✔
1620
        if dtype is not None:
1✔
1621
            int_dt = dt
1✔
1622
        dt = ti.default_device_fp_type(sycl_queue)
1✔
1623
        dt = dpt.dtype(dt)
1✔
1624
        start = float(start)
1✔
1625
        stop = float(stop)
1✔
1626
    res = dpt.empty(num, dtype=dt, usm_type=usm_type, sycl_queue=sycl_queue)
1✔
1627
    _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1628
    hev, la_ev = ti._linspace_affine(
1✔
1629
        start, stop, dst=res, include_endpoint=endpoint, sycl_queue=sycl_queue
1630
    )
1631
    _manager.add_event_pair(hev, la_ev)
1✔
1632
    return res if int_dt is None else dpt.astype(res, int_dt)
1✔
1633

1634

1635
def eye(
1✔
1636
    n_rows,
1637
    n_cols=None,
1638
    /,
1639
    *,
1640
    k=0,
1641
    dtype=None,
1642
    order="C",
1643
    device=None,
1644
    usm_type="device",
1645
    sycl_queue=None,
1646
):
1647
    """
1648
    eye(n_rows, n_cols=None, /, *, k=0, dtype=None, \
1649
        device=None, usm_type="device", sycl_queue=None)
1650

1651
    Creates :class:`dpctl.tensor.usm_ndarray` with ones on the `k`-th
1652
    diagonal.
1653

1654
    Args:
1655
        n_rows (int):
1656
            number of rows in the output array.
1657
        n_cols (int, optional):
1658
            number of columns in the output array. If ``None``,
1659
            ``n_cols = n_rows``. Default: ``None``
1660
        k (int):
1661
            index of the diagonal, with ``0`` as the main diagonal.
1662
            A positive value of ``k`` is a superdiagonal, a negative value
1663
            is a subdiagonal.
1664
            Raises :exc:`TypeError` if ``k`` is not an integer.
1665
            Default: ``0``
1666
        dtype (optional):
1667
            data type of the array. Can be typestring,
1668
            a :class:`numpy.dtype` object, :mod:`numpy` char string, or
1669
            a NumPy scalar type. Default: ``None``
1670
        order ("C" or "F"):
1671
            memory layout for the array. Default: ``"C"``
1672
        device (optional):
1673
            array API concept of device where the output array
1674
            is created. ``device`` can be ``None``, a oneAPI filter selector
1675
            string, an instance of :class:`dpctl.SyclDevice` corresponding to
1676
            a non-partitioned SYCL device, an instance of
1677
            :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device` object
1678
            returned by :attr:`dpctl.tensor.usm_ndarray.device`.
1679
            Default: ``None``
1680
        usm_type (``"device"``, ``"shared"``, ``"host"``, optional):
1681
            The type of SYCL USM allocation for the output array.
1682
            Default: ``"device"``
1683
        sycl_queue (:class:`dpctl.SyclQueue`, optional):
1684
            The SYCL queue to use
1685
            for output array allocation and copying. ``sycl_queue`` and
1686
            ``device`` are complementary arguments, i.e. use one or another.
1687
            If both are specified, a :exc:`TypeError` is raised unless both
1688
            imply the same underlying SYCL queue to be used. If both are
1689
            ``None``, a cached queue targeting default-selected device is
1690
            used for allocation and population. Default: ``None``
1691

1692
    Returns:
1693
        usm_ndarray:
1694
            A diagonal matrix.
1695
    """
1696
    if not isinstance(order, str) or len(order) == 0 or order[0] not in "CcFf":
1✔
1697
        raise ValueError(
1✔
1698
            "Unrecognized order keyword value, expecting 'F' or 'C'."
1699
        )
1700
    order = order[0].upper()
1✔
1701
    n_rows = operator.index(n_rows)
1✔
1702
    n_cols = n_rows if n_cols is None else operator.index(n_cols)
1✔
1703
    k = operator.index(k)
1✔
1704
    if k >= n_cols or -k >= n_rows:
1!
1705
        return dpt.zeros(
×
1706
            (n_rows, n_cols),
1707
            dtype=dtype,
1708
            order=order,
1709
            device=device,
1710
            usm_type=usm_type,
1711
            sycl_queue=sycl_queue,
1712
        )
1713
    dpctl.utils.validate_usm_type(usm_type, allow_none=False)
1✔
1714
    sycl_queue = normalize_queue_device(sycl_queue=sycl_queue, device=device)
1✔
1715
    dtype = _get_dtype(dtype, sycl_queue)
1✔
1716
    _ensure_native_dtype_device_support(dtype, sycl_queue.sycl_device)
1✔
1717
    res = dpt.usm_ndarray(
1✔
1718
        (n_rows, n_cols),
1719
        dtype=dtype,
1720
        buffer=usm_type,
1721
        order=order,
1722
        buffer_ctor_kwargs={"queue": sycl_queue},
1723
    )
1724
    if n_rows != 0 and n_cols != 0:
1!
1725
        _manager = dpctl.utils.SequentialOrderManager[sycl_queue]
1✔
1726
        hev, eye_ev = ti._eye(k, dst=res, sycl_queue=sycl_queue)
1✔
1727
        _manager.add_event_pair(hev, eye_ev)
1✔
1728
    return res
1✔
1729

1730

1731
def tril(x, /, *, k=0):
1✔
1732
    """
1733
    Returns the lower triangular part of a matrix (or a stack of matrices)
1734
    ``x``.
1735

1736
    The lower triangular part of the matrix is defined as the elements on and
1737
    below the specified diagonal ``k``.
1738

1739
    Args:
1740
        x (usm_ndarray):
1741
            Input array
1742
        k (int, optional):
1743
            Specifies the diagonal above which to set
1744
            elements to zero. If ``k = 0``, the diagonal is the main diagonal.
1745
            If ``k < 0``, the diagonal is below the main diagonal.
1746
            If ``k > 0``, the diagonal is above the main diagonal.
1747
            Default: ``0``
1748

1749
    Returns:
1750
        usm_ndarray:
1751
            A lower-triangular array or a stack of lower-triangular arrays.
1752
    """
1753
    if not isinstance(x, dpt.usm_ndarray):
1✔
1754
        raise TypeError(
1✔
1755
            "Expected argument of type dpctl.tensor.usm_ndarray, "
1756
            f"got {type(x)}."
1757
        )
1758

1759
    k = operator.index(k)
1✔
1760

1761
    order = "F" if (x.flags.f_contiguous) else "C"
1✔
1762

1763
    shape = x.shape
1✔
1764
    nd = x.ndim
1✔
1765
    if nd < 2:
1!
1766
        raise ValueError("Array dimensions less than 2.")
×
1767

1768
    q = x.sycl_queue
1✔
1769
    if k >= shape[nd - 1] - 1:
1✔
1770
        res = dpt.empty(
1✔
1771
            x.shape,
1772
            dtype=x.dtype,
1773
            order=order,
1774
            usm_type=x.usm_type,
1775
            sycl_queue=q,
1776
        )
1777
        _manager = dpctl.utils.SequentialOrderManager[q]
1✔
1778
        dep_evs = _manager.submitted_events
1✔
1779
        hev, cpy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
1✔
1780
            src=x, dst=res, sycl_queue=q, depends=dep_evs
1781
        )
1782
        _manager.add_event_pair(hev, cpy_ev)
1✔
1783
    elif k < -shape[nd - 2]:
1✔
1784
        res = dpt.zeros(
1✔
1785
            x.shape,
1786
            dtype=x.dtype,
1787
            order=order,
1788
            usm_type=x.usm_type,
1789
            sycl_queue=q,
1790
        )
1791
    else:
1792
        res = dpt.empty(
1✔
1793
            x.shape,
1794
            dtype=x.dtype,
1795
            order=order,
1796
            usm_type=x.usm_type,
1797
            sycl_queue=q,
1798
        )
1799
        _manager = dpctl.utils.SequentialOrderManager[q]
1✔
1800
        dep_evs = _manager.submitted_events
1✔
1801
        hev, tril_ev = ti._tril(
1✔
1802
            src=x, dst=res, k=k, sycl_queue=q, depends=dep_evs
1803
        )
1804
        _manager.add_event_pair(hev, tril_ev)
1✔
1805

1806
    return res
1✔
1807

1808

1809
def triu(x, /, *, k=0):
1✔
1810
    """
1811
    Returns the upper triangular part of a matrix (or a stack of matrices)
1812
    ``x``.
1813

1814
    The upper triangular part of the matrix is defined as the elements on and
1815
    above the specified diagonal ``k``.
1816

1817
    Args:
1818
        x (usm_ndarray):
1819
            Input array
1820
        k (int, optional):
1821
            Specifies the diagonal below which to set
1822
            elements to zero. If ``k = 0``, the diagonal is the main diagonal.
1823
            If ``k < 0``, the diagonal is below the main diagonal.
1824
            If ``k > 0``, the diagonal is above the main diagonal.
1825
            Default: ``0``
1826

1827
    Returns:
1828
        usm_ndarray:
1829
            An upper-triangular array or a stack of upper-triangular arrays.
1830
    """
1831
    if not isinstance(x, dpt.usm_ndarray):
1✔
1832
        raise TypeError(
1✔
1833
            "Expected argument of type dpctl.tensor.usm_ndarray, "
1834
            f"got {type(x)}."
1835
        )
1836

1837
    k = operator.index(k)
1✔
1838

1839
    order = "F" if (x.flags.f_contiguous) else "C"
1✔
1840

1841
    shape = x.shape
1✔
1842
    nd = x.ndim
1✔
1843
    if nd < 2:
1!
1844
        raise ValueError("Array dimensions less than 2.")
×
1845

1846
    q = x.sycl_queue
1✔
1847
    if k > shape[nd - 1]:
1✔
1848
        res = dpt.zeros(
1✔
1849
            x.shape,
1850
            dtype=x.dtype,
1851
            order=order,
1852
            usm_type=x.usm_type,
1853
            sycl_queue=q,
1854
        )
1855
    elif k <= -shape[nd - 2] + 1:
1✔
1856
        res = dpt.empty(
1✔
1857
            x.shape,
1858
            dtype=x.dtype,
1859
            order=order,
1860
            usm_type=x.usm_type,
1861
            sycl_queue=q,
1862
        )
1863
        _manager = dpctl.utils.SequentialOrderManager[q]
1✔
1864
        dep_evs = _manager.submitted_events
1✔
1865
        hev, cpy_ev = ti._copy_usm_ndarray_into_usm_ndarray(
1✔
1866
            src=x, dst=res, sycl_queue=q, depends=dep_evs
1867
        )
1868
        _manager.add_event_pair(hev, cpy_ev)
1✔
1869
    else:
1870
        res = dpt.empty(
1✔
1871
            x.shape,
1872
            dtype=x.dtype,
1873
            order=order,
1874
            usm_type=x.usm_type,
1875
            sycl_queue=q,
1876
        )
1877
        _manager = dpctl.utils.SequentialOrderManager[q]
1✔
1878
        dep_evs = _manager.submitted_events
1✔
1879
        hev, triu_ev = ti._triu(
1✔
1880
            src=x, dst=res, k=k, sycl_queue=q, depends=dep_evs
1881
        )
1882
        _manager.add_event_pair(hev, triu_ev)
1✔
1883

1884
    return res
1✔
1885

1886

1887
def meshgrid(*arrays, indexing="xy"):
1✔
1888
    """
1889
    Creates list of :class:`dpctl.tensor.usm_ndarray` coordinate matrices
1890
    from vectors.
1891

1892
    Args:
1893
        arrays (usm_ndarray):
1894
            an arbitrary number of one-dimensional arrays
1895
            representing grid coordinates. Each array should have the same
1896
            numeric data type.
1897
        indexing (``"xy"``, or ``"ij"``):
1898
            Cartesian (``"xy"``) or matrix (``"ij"``) indexing of output.
1899
            If provided zero or one one-dimensional vector(s) (i.e., the
1900
            zero- and one-dimensional cases, respectively), the ``indexing``
1901
            keyword has no effect and should be ignored. Default: ``"xy"``
1902

1903
    Returns:
1904
        List[array]:
1905
            list of ``N`` arrays, where ``N`` is the number of
1906
            provided one-dimensional input arrays. Each returned array must
1907
            have rank ``N``.
1908
            For a set of ``n`` vectors with lengths ``N0``, ``N1``, ``N2``, ...
1909
            The cartesian indexing results in arrays of shape
1910
            ``(N1, N0, N2, ...)``, while the
1911
            matrix indexing results in arrays of shape
1912
            ``(N0, N1, N2, ...)``.
1913
            Default: ``"xy"``.
1914

1915
    Raises:
1916
        ValueError: If vectors are not of the same data type, or are not
1917
            one-dimensional.
1918

1919
    """
1920
    ref_dt = None
1✔
1921
    ref_unset = True
1✔
1922
    for array in arrays:
1✔
1923
        if not isinstance(array, dpt.usm_ndarray):
1✔
1924
            raise TypeError(
1✔
1925
                f"Expected instance of dpt.usm_ndarray, got {type(array)}."
1926
            )
1927
        if array.ndim != 1:
1✔
1928
            raise ValueError("All arrays must be one-dimensional.")
1✔
1929
        if ref_unset:
1✔
1930
            ref_unset = False
1✔
1931
            ref_dt = array.dtype
1✔
1932
        else:
1933
            if not ref_dt == array.dtype:
1✔
1934
                raise ValueError(
1✔
1935
                    "All arrays must be of the same numeric data type."
1936
                )
1937
    if indexing not in ["xy", "ij"]:
1✔
1938
        raise ValueError(
1✔
1939
            "Unrecognized indexing keyword value, expecting 'xy' or 'ij.'"
1940
        )
1941
    n = len(arrays)
1✔
1942
    if n == 0:
1✔
1943
        return []
1✔
1944

1945
    sh = (-1,) + (1,) * (n - 1)
1✔
1946

1947
    res = []
1✔
1948
    if n > 1 and indexing == "xy":
1✔
1949
        res.append(dpt.reshape(arrays[0], (1, -1) + sh[2:], copy=True))
1✔
1950
        res.append(dpt.reshape(arrays[1], sh, copy=True))
1✔
1951
        arrays, sh = arrays[2:], sh[-2:] + sh[:-2]
1✔
1952

1953
    for array in arrays:
1✔
1954
        res.append(dpt.reshape(array, sh, copy=True))
1✔
1955
        sh = sh[-1:] + sh[:-1]
1✔
1956

1957
    output = dpt.broadcast_arrays(*res)
1✔
1958

1959
    return output
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc