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

IntelPython / dpctl / 5980634988

25 Aug 2023 09:34PM UTC coverage: 85.634% (-0.002%) from 85.636%
5980634988

Pull #1368

github

web-flow
Merge a653eb348 into 1595dce05
Pull Request #1368: Address NumPy 1.25 deprecation warnings

2344 of 2770 branches covered (0.0%)

Branch coverage included in aggregate %.

10 of 10 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

8487 of 9878 relevant lines covered (85.92%)

7945.97 hits per line

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

90.03
/dpctl/tensor/_usmarray.pyx
1
#                       Data Parallel Control (dpctl)
1✔
2
#
3
#  Copyright 2020-2022 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
# distutils: language = c++
18
# cython: language_level=3
19
# cython: linetrace=True
20

21
import sys
1✔
22

23
import numpy as np
1✔
24

25
import dpctl
1✔
26
import dpctl.memory as dpmem
1✔
27

28
from ._data_types import bool as dpt_bool
1✔
29
from ._device import Device
1✔
30
from ._print import usm_ndarray_repr, usm_ndarray_str
1✔
31

32
from cpython.mem cimport PyMem_Free
33
from cpython.tuple cimport PyTuple_New, PyTuple_SetItem
34

35
cimport dpctl as c_dpctl
36
cimport dpctl.memory as c_dpmem
37
cimport dpctl.tensor._dlpack as c_dlpack
38

39
import dpctl.tensor._flags as _flags
1✔
40
from dpctl.tensor._tensor_impl import default_device_fp_type
1✔
41

42
include "_stride_utils.pxi"
43
include "_types.pxi"
44
include "_slicing.pxi"
45

46

47
cdef class InternalUSMArrayError(Exception):
48
    """
49
    A InternalError exception is raised when internal
50
    inconsistency has been detected.
51
    """
52
    pass
53

54

55
cdef object _as_zero_dim_ndarray(object usm_ary):
1✔
56
    "Convert size-1 array to NumPy 0d array"
57
    mem_view = dpmem.as_usm_memory(usm_ary)
1✔
58
    host_buf = mem_view.copy_to_host()
1✔
59
    view = host_buf.view(usm_ary.dtype)
1✔
60
    view.shape = tuple()
1✔
61
    return view
1✔
62

63

64
cdef class usm_ndarray:
65
    """ usm_ndarray(shape, dtype=None, strides=None, buffer="device", \
66
           offset=0, order="C", buffer_ctor_kwargs=dict(), \
67
           array_namespace=None)
68

69
    An array object represents a multidimensional tensor of numeric
70
    elements stored in a USM allocation on a SYCL device.
71

72
    Arg:
73
        shape (int, tuple):
74
            Shape of the array to be created.
75
        dtype (str, dtype):
76
            Array data type, i.e. the type of array elements.
77
            If ``dtype`` has the value ``None``, it is determined by default
78
            floating point type supported by target device.
79
            The supported types are
80
               * ``bool``
81
                     boolean type
82
               * ``int8``, ``int16``, ``int32``, ``int64``,
83
                     signed integer types
84
               * ``uint8``, ``uint16``, ``uint32``, ``uint64``,
85
                     unsigned integer types
86
               * ``float16``
87
                     half-precision floating type,
88
                     supported if target device's property
89
                     ``has_aspect_fp16`` is ``True``
90
               * ``float32``, ``complex64``
91
                     single-precision real and complex floating
92
                     types
93
               * ``float64``, ``complex128``
94
                     double-precision real and complex floating
95
                     types, supported if target device's property
96
                     ``has_aspect_fp64`` is ``True``.
97
            Default: ``None``.
98
        strides (tuple, optional):
99
            Strides of the array to be created in elements.
100
            If ``strides`` has the value ``None``, it is determined by the
101
            ``shape`` of the array and the requested ``order``.
102
            Default: ``None``.
103
        buffer (str, object, optional):
104
            A string corresponding to the type of USM allocation to make,
105
            or a Python object representing a USM memory allocation, i.e.
106
            :class:`dpctl.memory.MemoryUSMDevice`,
107
            :class:`dpctl.memory.MemoryUSMShared`, or
108
            :class:`dpctl.memory.MemoryUSMHost`. Recognized strings are
109
            ``"device"``, ``"shared"``, or ``"host"``. Additional arguments to
110
            the USM memory alloctors can be passed in a dictionary specified
111
            via ``buffer_ctor_kwrds`` keyword parameter.
112
            Default: ``"device"``.
113
        offset (int, optional):
114
            Offset of the array element with all zero indexes relative to the
115
            start of the provided `buffer` in elements. The argument is ignored
116
            if the ``buffer`` value is a string and the memory is allocated by
117
            the constructor. Default: ``0``.
118
        order ({"C", "F"}, optional):
119
            The memory layout of the array when constructing using a new
120
            allocation. Value ``"C"`` corresponds to C-contiguous, or row-major
121
            memory layout, while value ``"F"`` corresponds to F-contiguous, or
122
            column-major layout. Default: ``"C"``.
123
        buffer_ctor_kwargs (dict, optional):
124
            Dictionary with keyword parameters to use when creating a new USM
125
            memory allocation. See :class:`dpctl.memory.MemoryUSMShared` for
126
            supported keyword arguments.
127
        array_namespace (module, optional):
128
            Array namespace module associated with this array.
129
            Default: ``None``.
130

131
    ``buffer`` can be ``"shared"``, ``"host"``, ``"device"`` to allocate
132
    new device memory by calling respective constructor with
133
    the specified ``buffer_ctor_kwrds``; ``buffer`` can be an
134
    instance of :class:`dpctl.memory.MemoryUSMShared`,
135
    :class:`dpctl.memory.MemoryUSMDevice`, or
136
    :class:`dpctl.memory.MemoryUSMHost`; ``buffer`` can also be
137
    another :class:`dpctl.tensor.usm_ndarray` instance, in which case its
138
    underlying ``MemoryUSM*`` buffer is used.
139
    """
140

141
    cdef void _reset(usm_ndarray self):
1✔
142
        """
143
        Initializes member fields
144
        """
145
        self.base_ = None
1✔
146
        self.array_namespace_ = None
1✔
147
        self.nd_ = -1
1✔
148
        self.data_ = <char *>0
1✔
149
        self.shape_ = <Py_ssize_t *>0
1✔
150
        self.strides_ = <Py_ssize_t *>0
1✔
151
        self.flags_ = 0
1✔
152

153
    cdef void _cleanup(usm_ndarray self):
1✔
154
        if (self.shape_):
1✔
155
            PyMem_Free(self.shape_)
1✔
156
        if (self.strides_):
1✔
157
            PyMem_Free(self.strides_)
1✔
158
        self._reset()
1✔
159

160
    def __cinit__(self, shape, dtype=None, strides=None, buffer='device',
161
                  Py_ssize_t offset=0, order='C',
162
                  buffer_ctor_kwargs=dict(),
1✔
163
                  array_namespace=None):
164
        """
165
        strides and offset must be given in units of array elements.
166
        buffer can be strings ('device'|'shared'|'host' to allocate new memory)
167
        or dpctl.memory.MemoryUSM* buffers, or usm_ndrray instances.
168
        """
169
        cdef int nd = 0
1✔
170
        cdef int typenum = 0
1✔
171
        cdef int itemsize = 0
1✔
172
        cdef int err = 0
1✔
173
        cdef int contig_flag = 0
1✔
174
        cdef Py_ssize_t *shape_ptr = NULL
1✔
175
        cdef Py_ssize_t ary_nelems = 0
1✔
176
        cdef Py_ssize_t ary_nbytes = 0
1✔
177
        cdef Py_ssize_t *strides_ptr = NULL
1✔
178
        cdef Py_ssize_t _offset = offset
1✔
179
        cdef Py_ssize_t ary_min_displacement = 0
1✔
180
        cdef Py_ssize_t ary_max_displacement = 0
1✔
181
        cdef bint is_fp64 = False
1✔
182
        cdef bint is_fp16 = False
1✔
183

184
        self._reset()
1✔
185
        if (not isinstance(shape, (list, tuple))
1✔
186
                and not hasattr(shape, 'tolist')):
1✔
187
            try:
1✔
188
                <Py_ssize_t> shape
1✔
189
                shape = [shape, ]
1✔
190
            except Exception:
1✔
191
                raise TypeError("Argument shape must be a list or a tuple.")
1✔
192
        nd = len(shape)
1✔
193
        if dtype is None:
1✔
194
            if isinstance(buffer, (dpmem._memory._Memory, usm_ndarray)):
1✔
195
                q = buffer.sycl_queue
×
196
            else:
197
                q = buffer_ctor_kwargs.get("queue")
1✔
198
            if q is not None:
1✔
199
                dtype = default_device_fp_type(q)
1✔
200
            else:
201
                dev = dpctl.select_default_device()
1✔
202
                dtype = "f8" if dev.has_aspect_fp64 else "f4"
1✔
203
        typenum = dtype_to_typenum(dtype)
1✔
204
        if (typenum < 0):
1✔
205
            if typenum == -2:
1✔
206
                raise ValueError("Data type '" + str(dtype) + "' can only have native byteorder.")
1✔
207
            elif typenum == -1:
208
                raise ValueError("Data type '" + str(dtype) + "' is not understood.")
1✔
209
            raise TypeError(f"Expected string or a dtype object, got {type(dtype)}")
1✔
210
        itemsize = type_bytesize(typenum)
1✔
211
        if (itemsize < 1):
1✔
212
            raise TypeError("dtype=" + np.dtype(dtype).name + " is not supported.")
1✔
213
        # allocate host C-arrays for shape, strides
214
        err = _from_input_shape_strides(
1✔
215
            nd, shape, strides, itemsize, <char> ord(order),
1✔
216
            &shape_ptr, &strides_ptr, &ary_nelems,
217
            &ary_min_displacement, &ary_max_displacement, &contig_flag
218
        )
219
        if (err):
1✔
220
            self._cleanup()
1✔
221
            if err == ERROR_MALLOC:
1✔
222
                raise MemoryError("Memory allocation for shape/strides "
×
223
                                  "array failed.")
224
            elif err == ERROR_INCORRECT_ORDER:
1✔
225
                raise ValueError(
1✔
226
                    "Unsupported order='{}' given. "
227
                    "Supported values are 'C' or 'F'.".format(order))
1✔
228
            elif err == ERROR_UNEXPECTED_STRIDES:
1✔
229
                raise ValueError(
1✔
230
                    "strides={} is not understood".format(strides))
1✔
231
            else:
232
                raise InternalUSMArrayError(
1✔
233
                    " .. while processing shape and strides.")
234
        ary_nbytes = (ary_max_displacement -
235
                      ary_min_displacement + 1) * itemsize
1✔
236
        if isinstance(buffer, dpmem._memory._Memory):
1✔
237
            _buffer = buffer
1✔
238
        elif isinstance(buffer, (str, bytes)):
1✔
239
            if isinstance(buffer, bytes):
1✔
240
                buffer = buffer.decode("UTF-8")
1✔
241
            _offset = -ary_min_displacement
1✔
242
            if (buffer == "shared"):
1✔
243
                _buffer = dpmem.MemoryUSMShared(ary_nbytes,
1✔
244
                                                **buffer_ctor_kwargs)
1✔
245
            elif (buffer == "device"):
1✔
246
                _buffer = dpmem.MemoryUSMDevice(ary_nbytes,
1✔
247
                                                **buffer_ctor_kwargs)
1✔
248
            elif (buffer == "host"):
1✔
249
                _buffer = dpmem.MemoryUSMHost(ary_nbytes,
1✔
250
                                              **buffer_ctor_kwargs)
1✔
251
            else:
252
                self._cleanup()
1✔
253
                raise ValueError(
1✔
254
                    ("buffer='{}' is not understood. "
255
                    "Recognized values are 'device', 'shared',  'host', "
256
                    "an instance of `MemoryUSM*` object, or a usm_ndarray"
257
                     "").format(buffer))
1✔
258
        elif isinstance(buffer, usm_ndarray):
1✔
259
            _buffer = buffer.usm_data
1✔
260
        else:
261
            self._cleanup()
1✔
262
            raise ValueError("buffer='{}' was not understood.".format(buffer))
1✔
263
        if (_offset + ary_min_displacement < 0 or
1✔
264
           (_offset + ary_max_displacement + 1) * itemsize > _buffer.nbytes):
1✔
265
            self._cleanup()
1✔
266
            raise ValueError(("buffer='{}' can not accommodate "
1✔
267
                              "the requested array.").format(buffer))
1✔
268
        is_fp64 = (typenum == UAR_DOUBLE or typenum == UAR_CDOUBLE)
1✔
269
        is_fp16 = (typenum == UAR_HALF)
1✔
270
        if (is_fp64 or is_fp16):
1✔
271
            if ((is_fp64 and not _buffer.sycl_device.has_aspect_fp64) or
1✔
272
                (is_fp16 and not _buffer.sycl_device.has_aspect_fp16)
1✔
273
            ):
274
                raise ValueError(
×
275
                    f"Device {_buffer.sycl_device.name} does"
×
UNCOV
276
                    f" not support {dtype} natively."
×
277
                )
278
        self.base_ = _buffer
1✔
279
        self.data_ = (<char *> (<size_t> _buffer._pointer)) + itemsize * _offset
1✔
280
        self.shape_ = shape_ptr
1✔
281
        self.strides_ = strides_ptr
1✔
282
        self.typenum_ = typenum
1✔
283
        self.flags_ = (contig_flag | USM_ARRAY_WRITABLE)
1✔
284
        self.nd_ = nd
1✔
285
        self.array_namespace_ = array_namespace
1✔
286

287
    def __dealloc__(self):
288
        self._cleanup()
1✔
289

290
    @property
291
    def _pointer(self):
292
        "Returns USM pointer for data allocation encoded as integer"
293
        return <size_t> self.get_data()
1✔
294

295
    cdef Py_ssize_t get_offset(self) except *:
1✔
296
        cdef char *mem_ptr = NULL
1✔
297
        cdef char *ary_ptr = self.get_data()
1✔
298
        mem_ptr = <char *>(<size_t> self.base_._pointer)
1✔
299
        byte_offset = ary_ptr - mem_ptr
1✔
300
        item_size = self.get_itemsize()
1✔
301
        if (byte_offset % item_size):
1✔
302
            raise InternalUSMArrayError(
×
303
                "byte_offset is not a multiple of item_size.")
304
        return byte_offset // item_size
1✔
305

306
    @property
307
    def _element_offset(self):
308
        """Returns the offset of the zero-index element of the array, in elements,
309
        relative to the start of memory allocation"""
310
        return self.get_offset()
1✔
311

312
    @property
313
    def _byte_bounds(self):
314
        """Returns a 2-tuple with pointers to the end-points of the array"""
315
        cdef Py_ssize_t min_disp = 0
1✔
316
        cdef Py_ssize_t max_disp = 0
1✔
317
        cdef Py_ssize_t step_ = 0
1✔
318
        cdef Py_ssize_t dim_ = 0
1✔
319
        cdef int it = 0
1✔
320
        cdef Py_ssize_t _itemsize = self.get_itemsize()
1✔
321

322
        if ((self.flags_ & USM_ARRAY_C_CONTIGUOUS) or (self.flags_ & USM_ARRAY_F_CONTIGUOUS)):
1✔
323
            return (
1✔
324
                self._pointer,
1✔
325
                self._pointer + shape_to_elem_count(self.nd_, self.shape_) * _itemsize
1✔
326
            )
327

328
        for it in range(self.nd_):
1✔
329
           dim_ = self.shape[it]
1✔
330
           if dim_ > 0:
1✔
331
               step_ = self.strides[it]
1✔
332
               if step_ > 0:
1✔
333
                   max_disp += step_ * (dim_ - 1)
1✔
334
               else:
335
                   min_disp += step_ * (dim_ - 1)
1✔
336

337
        return (
1✔
338
            self._pointer + min_disp * _itemsize,
1✔
339
            self._pointer + (max_disp + 1) * _itemsize
1✔
340
        )
341

342

343
    cdef char* get_data(self):
1✔
344
        """Returns the USM pointer for this array."""
345
        return self.data_
1✔
346

347
    cdef int get_ndim(self):
1✔
348
        """
349
        Returns the number of indices needed to address
350
        an element of this array.
351
        """
352
        return self.nd_
1✔
353

354
    cdef Py_ssize_t* get_shape(self):
1✔
355
        """
356
        Returns pointer to shape C-array for this array.
357

358
        C-array has at least ``ndim`` non-negative elements,
359
        which determine the range of permissible indices
360
        addressing individual elements of this array.
361
        """
362
        return self.shape_
1✔
363

364
    cdef Py_ssize_t* get_strides(self):
1✔
365
        """
366
        Returns pointer to strides C-array for this array.
367

368
        The pointer can be NULL (contiguous array), or the
369
        array size is at least ``ndim`` elements
370
        """
371
        return self.strides_
1✔
372

373
    cdef int get_typenum(self):
1✔
374
        """Returns typenum corresponding to values of this array"""
375
        return self.typenum_
1✔
376

377
    cdef int get_itemsize(self):
1✔
378
        """
379
        Returns itemsize of this arrays in bytes
380
        """
381
        return type_bytesize(self.typenum_)
1✔
382

383
    cdef int get_flags(self):
1✔
384
        """Returns flags of this array"""
385
        return self.flags_
1✔
386

387
    cdef object get_base(self):
1✔
388
        """Returns the object owning the USM data addressed by this array"""
389
        return self.base_
1✔
390

391
    cdef c_dpctl.SyclQueue get_sycl_queue(self):
1✔
392
        cdef c_dpmem._Memory mem
393
        if not isinstance(self.base_, dpctl.memory._Memory):
1✔
394
            raise InternalUSMArrayError(
×
395
                "This array has unexpected memory owner"
396
            )
397
        mem = <c_dpmem._Memory> self.base_
1✔
398
        return mem.queue
1✔
399

400
    cdef c_dpctl.DPCTLSyclQueueRef get_queue_ref(self) except *:
1✔
401
        """
402
        Returns a copy of DPCTLSyclQueueRef associated with array
403
        """
404
        cdef c_dpctl.SyclQueue q = self.get_sycl_queue()
1✔
405
        cdef c_dpctl.DPCTLSyclQueueRef QRef = q.get_queue_ref()
1✔
406
        cdef c_dpctl.DPCTLSyclQueueRef QRefCopy = NULL
1✔
407
        if QRef is not NULL:
1✔
408
            QRefCopy = c_dpctl.DPCTLQueue_Copy(QRef)
1✔
409
            return QRefCopy
1✔
410
        else:
411
            raise InternalUSMArrayError(
×
412
                "Memory owner of this array is corrupted"
413
            )
414

415
    @property
416
    def __sycl_usm_array_interface__(self):
417
        """
418
        Gives ``__sycl_usm_array_interface__`` dictionary describing
419
        the array.
420
        """
421
        cdef Py_ssize_t byte_offset = -1
1✔
422
        cdef int item_size = -1
1✔
423
        cdef Py_ssize_t elem_offset = -1
1✔
424
        cdef char *mem_ptr = NULL
1✔
425
        cdef char *ary_ptr = NULL
1✔
426
        if (not isinstance(self.base_, dpmem._memory._Memory)):
1✔
427
            raise InternalUSMArrayError(
×
428
                "Invalid instance of usm_ndarray ecountered. "
429
                "Private field base_ has an unexpected type {}.".format(
×
430
                    type(self.base_)
×
431
                )
432
            )
433
        ary_iface = self.base_.__sycl_usm_array_interface__
1✔
434
        mem_ptr = <char *>(<size_t> ary_iface['data'][0])
1✔
435
        ary_ptr = <char *>(<size_t> self.data_)
1✔
436
        ro_flag = False if (self.flags_ & USM_ARRAY_WRITABLE) else True
1✔
437
        ary_iface['data'] = (<size_t> mem_ptr, ro_flag)
1✔
438
        ary_iface['shape'] = self.shape
1✔
439
        if (self.strides_):
1✔
440
            ary_iface['strides'] = _make_int_tuple(self.nd_, self.strides_)
1✔
441
        else:
442
            if (self.flags_ & USM_ARRAY_C_CONTIGUOUS):
1✔
443
                ary_iface['strides'] = None
1✔
444
            elif (self.flags_ & USM_ARRAY_F_CONTIGUOUS):
1✔
445
                ary_iface['strides'] = _f_contig_strides(self.nd_, self.shape_)
1✔
446
            else:
447
                raise InternalUSMArrayError(
×
448
                    "USM Array is not contiguous and has empty strides"
449
                )
450
        ary_iface['typestr'] = _make_typestr(self.typenum_)
1✔
451
        byte_offset = ary_ptr - mem_ptr
1✔
452
        item_size = self.get_itemsize()
1✔
453
        if (byte_offset % item_size):
1✔
454
            raise InternalUSMArrayError(
×
455
                "byte_offset is not a multiple of item_size.")
456
        elem_offset = byte_offset // item_size
1✔
457
        ary_iface['offset'] = elem_offset
1✔
458
        return ary_iface
1✔
459

460
    @property
461
    def ndim(self):
462
        """
463
        Gives the number of indices needed to address elements of this array.
464
        """
465
        return self.nd_
1✔
466

467
    @property
468
    def usm_data(self):
469
        """
470
        Gives USM memory object underlying usm_array instance.
471
        """
472
        return self.get_base()
1✔
473

474
    @property
475
    def shape(self):
476
        """
477
        Elements of the shape tuple give the lengths of the
478
        respective array dimensions.
479
        """
480
        if self.nd_ > 0:
1✔
481
            return _make_int_tuple(self.nd_, self.shape_)
1✔
482
        else:
483
            return tuple()
1✔
484

485
    @shape.setter
486
    def shape(self, new_shape):
487
        """
488
        Setting shape is only allowed when reshaping to the requested
489
        dimensions can be returned as view. Use :func:`dpctl.tensor.reshape`
490
        to reshape the array in all other cases.
491
        """
492
        cdef int new_nd = -1
1✔
493
        cdef Py_ssize_t nelems = -1
1✔
494
        cdef int err = 0
1✔
495
        cdef Py_ssize_t min_disp = 0
1✔
496
        cdef Py_ssize_t max_disp = 0
1✔
497
        cdef int contig_flag = 0
1✔
498
        cdef Py_ssize_t *shape_ptr = NULL
1✔
499
        cdef Py_ssize_t *strides_ptr = NULL
1✔
500
        cdef Py_ssize_t size = -1
1✔
501
        import operator
1✔
502

503
        from ._reshape import reshaped_strides
1✔
504

505
        new_nd = len(new_shape)
1✔
506
        try:
1✔
507
            new_shape = tuple(operator.index(dim) for dim in new_shape)
1✔
508
        except TypeError:
1✔
509
            raise TypeError(
1✔
510
                "Target shape must be a finite iterable of integers"
511
            )
512
        size = shape_to_elem_count(self.nd_, self.shape_)
1✔
513
        if not np.prod(new_shape) == size:
1✔
514
            raise TypeError(
×
515
                f"Can not reshape array of size {self.size} into {new_shape}"
×
516
            )
517
        if size > 0:
1✔
518
            new_strides = reshaped_strides(
519
               self.shape,
1✔
520
               self.strides,
1✔
521
               new_shape
1✔
522
            )
523
        else:
524
            new_strides = (1,) * len(new_shape)
1✔
525
        if new_strides is None:
1✔
526
            raise AttributeError(
1✔
527
                "Incompatible shape for in-place modification. "
528
                "Use `reshape()` to make a copy with the desired shape."
529
            )
530
        err = _from_input_shape_strides(
1✔
531
            new_nd, new_shape, new_strides,
532
            self.get_itemsize(),
1✔
533
            b"C",
534
            &shape_ptr, &strides_ptr,
535
            &nelems, &min_disp, &max_disp, &contig_flag
536
        )
537
        if (err == 0):
1✔
538
            if (self.shape_):
1✔
539
                PyMem_Free(self.shape_)
1✔
540
            if (self.strides_):
1✔
541
                PyMem_Free(self.strides_)
1✔
542
            self.flags_ = contig_flag
1✔
543
            self.nd_ = new_nd
1✔
544
            self.shape_ = shape_ptr
1✔
545
            self.strides_ = strides_ptr
1✔
546
        else:
547
            raise InternalUSMArrayError(
×
548
                "Encountered in shape setter, error code {err}".format(err)
×
549
            )
550

551
    @property
552
    def strides(self):
553
        """
554
        Returns memory displacement in array elements, upon unit
555
        change of respective index.
556

557
        E.g. for strides (s1, s2, s3) and multi-index (i1, i2, i3)
558

559
           a[i1, i2, i3] == (&a[0,0,0])[ s1*s1 + s2*i2 + s3*i3]
560
        """
561
        if (self.strides_):
1✔
562
            return _make_int_tuple(self.nd_, self.strides_)
1✔
563
        else:
564
            if (self.flags_ & USM_ARRAY_C_CONTIGUOUS):
1✔
565
                return _c_contig_strides(self.nd_, self.shape_)
1✔
566
            elif (self.flags_ & USM_ARRAY_F_CONTIGUOUS):
1✔
567
                return _f_contig_strides(self.nd_, self.shape_)
1✔
568
            else:
569
                raise ValueError("Inconsitent usm_ndarray data")
×
570

571
    @property
572
    def flags(self):
573
        """
574
        Returns :class:`dpctl.tensor._flags` object.
575
        """
576
        return _flags.Flags(self, self.flags_)
1✔
577

578
    cdef _set_writable_flag(self, int flag):
1✔
579
        cdef int arr_fl = self.flags_
1✔
580
        arr_fl ^= (arr_fl & USM_ARRAY_WRITABLE)  # unset WRITABLE flag
1✔
581
        arr_fl |= (USM_ARRAY_WRITABLE if flag else 0)
1✔
582
        self.flags_ = arr_fl
1✔
583

584
    @property
585
    def usm_type(self):
586
        """
587
        USM type of underlying memory. Can be ``"device"``, ``"shared"``,
588
        or ``"host"``.
589

590
        See: https://docs.oneapi.com/versions/latest/dpcpp/iface/usm.html
591
        """
592
        return self.base_.get_usm_type()
1✔
593

594
    @property
595
    def itemsize(self):
596
        """
597
        Size of array element in bytes.
598
        """
599
        return self.get_itemsize()
1✔
600

601
    @property
602
    def nbytes(self):
603
        """
604
        Total bytes consumed by the elements of the array.
605
        """
606
        return (
1✔
607
            shape_to_elem_count(self.nd_, self.shape_) *
1✔
608
            self.get_itemsize())
1✔
609

610
    @property
611
    def size(self):
612
        """
613
        Number of elements in the array.
614
        """
615
        return shape_to_elem_count(self.nd_, self.shape_)
1✔
616

617
    @property
618
    def dtype(self):
619
        """
620
        Returns NumPy's dtype corresponding to the type of the array elements.
621
        """
622
        return np.dtype(_make_typestr(self.typenum_))
1✔
623

624
    @property
625
    def sycl_queue(self):
626
        """
627
        Returns :class:`dpctl.SyclQueue` object associated with USM data.
628
        """
629
        return self.get_sycl_queue()
1✔
630

631
    @property
632
    def sycl_device(self):
633
        """
634
        Returns :class:`dpctl.SyclDevice` object on which USM data was allocated.
635
        """
636
        q = self.sycl_queue
1✔
637
        return q.sycl_device
1✔
638

639
    @property
640
    def device(self):
641
        """
642
        Returns data-API object representing residence of the array data.
643
        """
644
        return Device.create_device(self.sycl_queue)
1✔
645

646
    @property
647
    def sycl_context(self):
648
        """
649
        Returns :class:`dpctl.SyclContext` object to which USM data is bound.
650
        """
651
        q = self.sycl_queue
1✔
652
        return q.sycl_context
1✔
653

654
    @property
655
    def T(self):
656
        """ Returns tranposed array for 2D array, raises `ValueError`
657
        otherwise.
658
        """
659
        if self.nd_ == 2:
1✔
660
            return _transpose(self)
1✔
661
        else:
662
            raise ValueError(
1✔
663
                "array.T requires array to have 2 dimensions. "
664
                "Use array.mT to transpose stacks of matrices and "
665
                "dpctl.tensor.permute_dims() to permute dimensions."
666
            )
667

668
    @property
669
    def mT(self):
670
        """ Returns array where the last two dimensions are transposed.
671
        """
672
        if self.nd_ < 2:
1✔
673
            raise ValueError(
1✔
674
                "array.mT requires array to have at least 2 dimensions."
675
            )
676
        return _m_transpose(self)
1✔
677

678
    @property
679
    def real(self):
680
        """ Returns real component for arrays with complex data-types
681
        and returns itself for all other data-types.
682
        """
683
        if (self.typenum_ < UAR_CFLOAT):
1✔
684
            # elements are real
685
            return self
1✔
686
        if (self.typenum_ < UAR_TYPE_SENTINEL):
1✔
687
            return _real_view(self)
1✔
688

689
    @property
690
    def imag(self):
691
        """ Returns imaginary component for arrays with complex data-types
692
        and returns zero array for all other data-types.
693
        """
694
        if (self.typenum_ < UAR_CFLOAT):
1✔
695
            # elements are real
696
            return _zero_like(self)
1✔
697
        if (self.typenum_ < UAR_TYPE_SENTINEL):
1✔
698
            return _imag_view(self)
1✔
699

700
    def __getitem__(self, ind):
701
        cdef tuple _meta = _basic_slice_meta(
1✔
702
            ind, (<object>self).shape, (<object> self).strides,
1✔
703
            self.get_offset())
1✔
704
        cdef usm_ndarray res
705
        cdef int i = 0
1✔
706
        cdef bint matching = 1
1✔
707

708
        if len(_meta) < 5:
1✔
709
            raise RuntimeError
×
710

711
        res = usm_ndarray.__new__(
1✔
712
            usm_ndarray,
713
            _meta[0],
1✔
714
            dtype=_make_typestr(self.typenum_),
1✔
715
            strides=_meta[1],
1✔
716
            buffer=self.base_,
1✔
717
            offset=_meta[2]
1✔
718
        )
719
        res.flags_ |= (self.flags_ & USM_ARRAY_WRITABLE)
1✔
720
        res.array_namespace_ = self.array_namespace_
1✔
721

722
        adv_ind = _meta[3]
1✔
723
        adv_ind_start_p = _meta[4]
1✔
724

725
        if adv_ind_start_p < 0:
1✔
726
            return res
1✔
727

728
        from ._copy_utils import _extract_impl, _nonzero_impl, _take_multi_index
1✔
729
        if len(adv_ind) == 1 and adv_ind[0].dtype == dpt_bool:
1✔
730
            key_ = adv_ind[0]
1✔
731
            adv_ind_end_p = key_.ndim + adv_ind_start_p
1✔
732
            if adv_ind_end_p > res.ndim:
1✔
733
                raise IndexError("too many indices for the array")
×
734
            key_shape = key_.shape
1✔
735
            arr_shape = res.shape[adv_ind_start_p:adv_ind_end_p]
1✔
736
            for i in range(key_.ndim):
1✔
737
                if matching:
1✔
738
                    if not key_shape[i] == arr_shape[i] and key_shape[i] > 0:
1✔
739
                        matching = 0
×
740
            if not matching:
1✔
741
                raise IndexError("boolean index did not match indexed array in dimensions")
×
742
            res = _extract_impl(res, key_, axis=adv_ind_start_p)
1✔
743
            return res
1✔
744

745
        if any(ind.dtype == dpt_bool for ind in adv_ind):
1✔
746
            adv_ind_int = list()
×
747
            for ind in adv_ind:
×
748
                if ind.dtype == dpt_bool:
×
749
                    adv_ind_int.extend(_nonzero_impl(ind))
×
750
                else:
751
                    adv_ind_int.append(ind)
×
752
            return _take_multi_index(res, tuple(adv_ind_int), adv_ind_start_p)
×
753

754
        return _take_multi_index(res, adv_ind, adv_ind_start_p)
1✔
755

756

757
    def to_device(self, target, stream=None):
1✔
758
        """ to_device(target_device)
759

760
        Transfers this array to specified target device.
761

762
        :Example:
763
            .. code-block:: python
764

765
                import dpctl
766
                import dpctl.tensor as dpt
767

768
                x = dpt.full(10**6, 2, dtype="int64")
769
                q_prof = dpctl.SyclQueue(
770
                    x.sycl_device, property="enable_profiling")
771
                # return a view with profile-enabled queue
772
                y = x.to_device(q_prof)
773
                timer = dpctl.SyclTimer()
774
                with timer(q_prof):
775
                    z = y * y
776
                print(timer.dt)
777

778
        Args:
779
            target_device (object):
780
                Array API concept of target device.
781
                It can be a oneAPI filter selector string,
782
                an instance of :class:`dpctl.SyclDevice` corresponding to a
783
                non-partitioned SYCL device, an instance of
784
                :class:`dpctl.SyclQueue`, or a :class:`dpctl.tensor.Device`
785
                object returned by :attr:`dpctl.tensor.usm_array.device`.
786

787
        Returns:
788
            usm_ndarray:
789
                A view if data copy is not required, and a copy otherwise.
790
                If copying is required, it is done by copying from the original
791
                allocation device to the host, followed by copying from host
792
                to the target device.
793
        """
794
        cdef c_dpctl.DPCTLSyclQueueRef QRef = NULL
1✔
795
        cdef c_dpmem._Memory arr_buf
796
        d = Device.create_device(target)
1✔
797

798
        if (stream is None or type(stream) is not dpctl.SyclQueue or
1✔
799
            stream == self.sycl_queue):
×
800
            pass
801
        else:
802
            ev = self.sycl_queue.submit_barrier()
×
803
            stream.submit_barrier(dependent_events=[ev])
×
804

805
        if (d.sycl_context == self.sycl_context):
1✔
806
            arr_buf = <c_dpmem._Memory> self.usm_data
1✔
807
            QRef = (<c_dpctl.SyclQueue> d.sycl_queue).get_queue_ref()
1✔
808
            view_buffer = c_dpmem._Memory.create_from_usm_pointer_size_qref(
1✔
809
                arr_buf.memory_ptr,
810
                arr_buf.nbytes,
811
                QRef,
812
                memory_owner = arr_buf
813
            )
814
            res = usm_ndarray(
1✔
815
                self.shape,
1✔
816
                self.dtype,
1✔
817
                buffer=view_buffer,
1✔
818
                strides=self.strides,
1✔
819
                offset=self.get_offset()
1✔
820
            )
821
            res.flags_ = self.flags_
1✔
822
            return res
1✔
823
        else:
824
            nbytes = self.usm_data.nbytes
1✔
825
            copy_buffer = type(self.usm_data)(
1✔
826
                nbytes, queue=d.sycl_queue
1✔
827
            )
828
            copy_buffer.copy_from_device(self.usm_data)
1✔
829
            res = usm_ndarray(
1✔
830
                self.shape,
1✔
831
                self.dtype,
1✔
832
                buffer=copy_buffer,
1✔
833
                strides=self.strides,
1✔
834
                offset=self.get_offset()
1✔
835
            )
836
            res.flags_ = self.flags_
1✔
837
            return res
1✔
838

839
    def _set_namespace(self, mod):
1✔
840
        """ Sets array namespace to given module `mod`. """
841
        self.array_namespace_ = mod
1✔
842

843
    def __array_namespace__(self, api_version=None):
1✔
844
        """
845
        Returns array namespace, member functions of which
846
        implement data API.
847
        """
848
        return self.array_namespace_ if self.array_namespace_ is not None else dpctl.tensor
1✔
849

850
    def __bool__(self):
851
        if self.size == 1:
1✔
852
            view = _as_zero_dim_ndarray(self)
1✔
853
            return view.__bool__()
1✔
854

855
        if self.size == 0:
1✔
856
            raise ValueError(
1✔
857
                "The truth value of an empty array is ambiguous"
858
            )
859

860
        raise ValueError(
1✔
861
            "The truth value of an array with more than one element is "
862
            "ambiguous. Use dpctl.tensor.any() or dpctl.tensor.all()"
863
        )
864

865
    def __float__(self):
866
        if self.size == 1:
1✔
867
            view = _as_zero_dim_ndarray(self)
1✔
868
            return view.__float__()
1✔
869

870
        raise ValueError(
1✔
871
            "only size-1 arrays can be converted to Python scalars"
872
        )
873

874
    def __complex__(self):
1✔
875
        if self.size == 1:
1✔
876
            view = _as_zero_dim_ndarray(self)
1✔
877
            return view.__complex__()
1✔
878

879
        raise ValueError(
1✔
880
            "only size-1 arrays can be converted to Python scalars"
881
        )
882

883
    def __int__(self):
884
        if self.size == 1:
1✔
885
            view = _as_zero_dim_ndarray(self)
1✔
886
            return view.__int__()
1✔
887

888
        raise ValueError(
1✔
889
            "only size-1 arrays can be converted to Python scalars"
890
        )
891

892
    def __index__(self):
893
        if np.issubdtype(self.dtype, np.integer):
1✔
894
            return int(self)
1✔
895

896
        raise IndexError("only integer arrays are valid indices")
1✔
897

898
    def __abs__(self):
899
        return dpctl.tensor.abs(self)
1✔
900

901
    def __add__(first, other):
902
        """
903
        Implementation for operator.add
904
        """
905
        return dpctl.tensor.add(first, other)
1✔
906

907
    def __and__(first, other):
908
        "Implementation for operator.and"
909
        return dpctl.tensor.bitwise_and(first, other)
1✔
910

911
    def __dlpack__(self, stream=None):
1✔
912
        """
913
        Produces DLPack capsule.
914

915
        Raises:
916
            MemoryError: when host memory can not be allocated.
917
            DLPackCreationError: when array is allocated on a partitioned
918
                SYCL device, or with a non-default context.
919
            NotImplementedError: when non-default value of `stream` keyword
920
                is used.
921
        """
922
        _caps = c_dlpack.to_dlpack_capsule(self)
1✔
923
        if (stream is None or type(stream) is not dpctl.SyclQueue or
1✔
924
            stream == self.sycl_queue):
1✔
925
            pass
926
        else:
927
            ev = self.sycl_queue.submit_barrier()
1✔
928
            stream.submit_barrier(dependent_events=[ev])
1✔
929
        return _caps
1✔
930

931
    def __dlpack_device__(self):
1✔
932
        """
933
        Gives a tuple (`device_type`, `device_id`) corresponding to ``DLDevice``
934
        entry in ``DLTensor`` in DLPack protocol.
935

936
        The tuple describes the non-partitioned device where the array
937
        has been allocated.
938

939
        Raises:
940
            DLPackCreationError: when array is allocation on a partitioned
941
                SYCL device
942
        """
943
        cdef int dev_id = (<c_dpctl.SyclDevice>self.sycl_device).get_overall_ordinal()
1✔
944
        if dev_id < 0:
1✔
945
            raise c_dlpack.DLPackCreationError(
×
946
                "DLPack protocol is only supported for non-partitioned devices"
947
            )
948
        else:
949
            return (
1✔
950
                c_dlpack.device_oneAPI,
1✔
951
                dev_id,
1✔
952
            )
953

954
    def __eq__(self, other):
955
        return dpctl.tensor.equal(self, other)
1✔
956

957
    def __floordiv__(first, other):
958
        return dpctl.tensor.floor_divide(first, other)
1✔
959

960
    def __ge__(self, other):
961
        return dpctl.tensor.greater_equal(self, other)
1✔
962

963
    def __gt__(self, other):
964
        return dpctl.tensor.greater(self, other)
1✔
965

966
    def __invert__(self):
967
        return dpctl.tensor.bitwise_invert(self)
1✔
968

969
    def __le__(self, other):
970
        return dpctl.tensor.less_equal(self, other)
1✔
971

972
    def __len__(self):
973
        if (self.nd_):
1✔
974
            return self.shape[0]
1✔
975
        else:
976
            raise TypeError("len() of unsized object")
1✔
977

978
    def __lshift__(first, other):
979
        "See comment in __add__"
980
        return dpctl.tensor.bitwise_left_shift(first, other)
1✔
981

982
    def __lt__(self, other):
983
        return dpctl.tensor.less(self, other)
1✔
984

985
    def __matmul__(first, other):
986
        return NotImplemented
1✔
987

988
    def __mod__(first, other):
989
        return dpctl.tensor.remainder(first, other)
1✔
990

991
    def __mul__(first, other):
992
        return dpctl.tensor.multiply(first, other)
1✔
993

994
    def __ne__(self, other):
995
        return dpctl.tensor.not_equal(self, other)
1✔
996

997
    def __neg__(self):
998
        return dpctl.tensor.negative(self)
1✔
999

1000
    def __or__(first, other):
1001
        return dpctl.tensor.bitwise_or(first, other)
1✔
1002

1003
    def __pos__(self):
1004
        return dpctl.tensor.positive(self)
1✔
1005

1006
    def __pow__(first, other, mod):
1007
        if mod is None:
1✔
1008
            return dpctl.tensor.pow(first, other)
1✔
1009
        else:
1010
            return NotImplemented
×
1011

1012
    def __rshift__(first, other):
1013
        return dpctl.tensor.bitwise_right_shift(first, other)
1✔
1014

1015
    def __setitem__(self, key, rhs):
1016
        cdef tuple _meta
1017
        cdef usm_ndarray Xv
1018

1019
        if (self.flags_ & USM_ARRAY_WRITABLE) == 0:
1✔
1020
            raise ValueError("Can not modify read-only array.")
1✔
1021

1022
        _meta = _basic_slice_meta(
1✔
1023
            key, (<object>self).shape, (<object> self).strides,
1✔
1024
            self.get_offset()
1✔
1025
        )
1026

1027
        if len(_meta) < 5:
1✔
1028
            raise RuntimeError
×
1029

1030
        Xv = usm_ndarray.__new__(
1✔
1031
            usm_ndarray,
1032
            _meta[0],
1✔
1033
            dtype=_make_typestr(self.typenum_),
1✔
1034
            strides=_meta[1],
1✔
1035
            buffer=self.base_,
1✔
1036
            offset=_meta[2],
1✔
1037
        )
1038
        # set flags and namespace
1039
        Xv.flags_ |= (self.flags_ & USM_ARRAY_WRITABLE)
1✔
1040
        Xv.array_namespace_ = self.array_namespace_
1✔
1041

1042
        from ._copy_utils import (
1✔
1043
            _copy_from_numpy_into,
1✔
1044
            _copy_from_usm_ndarray_to_usm_ndarray,
1045
            _nonzero_impl,
1046
            _place_impl,
1047
            _put_multi_index,
1048
        )
1049

1050
        adv_ind = _meta[3]
1✔
1051
        adv_ind_start_p = _meta[4]
1✔
1052

1053
        if adv_ind_start_p < 0:
1✔
1054
            # basic slicing
1055
            if isinstance(rhs, usm_ndarray):
1✔
1056
                _copy_from_usm_ndarray_to_usm_ndarray(Xv, rhs)
1✔
1057
            else:
1058
                if hasattr(rhs, "__sycl_usm_array_interface__"):
1✔
1059
                    from dpctl.tensor import asarray
×
1060
                    try:
×
1061
                        rhs_ar = asarray(rhs)
×
1062
                        _copy_from_usm_ndarray_to_usm_ndarray(Xv, rhs_ar)
×
1063
                    except Exception:
×
1064
                        raise ValueError(
×
1065
                            f"Input of type {type(rhs)} could not be "
×
1066
                            "converted to usm_ndarray"
1067
                        )
1068
                else:
1069
                    rhs_np = np.asarray(rhs)
1✔
1070
                    if type_bytesize(rhs_np.dtype.num) < 0:
1✔
1071
                        raise ValueError(
×
1072
                            f"Input of type {type(rhs)} can not be "
×
1073
                            "assigned to usm_ndarray because of "
1074
                            f"unsupported data type '{rhs_np.dtype}'"
×
1075
                        )
1076
                    try:
1✔
1077
                        _copy_from_numpy_into(Xv, rhs_np)
1✔
1078
                    except Exception:
×
1079
                        raise ValueError(
×
1080
                            f"Input of type {type(rhs)} could not be "
×
1081
                            "copied into dpctl.tensor.usm_ndarray"
1082
                        )
1083
            return
1✔
1084

1085
        if len(adv_ind) == 1 and adv_ind[0].dtype == dpt_bool:
1✔
1086
            _place_impl(Xv, adv_ind[0], rhs, axis=adv_ind_start_p)
1✔
1087
            return
1✔
1088

1089
        if any(ind.dtype == dpt_bool for ind in adv_ind):
1✔
1090
            adv_ind_int = list()
×
1091
            for ind in adv_ind:
×
1092
                if ind.dtype == dpt_bool:
×
1093
                    adv_ind_int.extend(_nonzero_impl(ind))
×
1094
                else:
1095
                    adv_ind_int.append(ind)
×
1096
            _put_multi_index(Xv, tuple(adv_ind_int), adv_ind_start_p, rhs)
×
1097
            return
×
1098

1099
        _put_multi_index(Xv, adv_ind, adv_ind_start_p, rhs)
1✔
1100
        return
1✔
1101

1102

1103
    def __sub__(first, other):
1104
        return dpctl.tensor.subtract(first, other)
1✔
1105

1106
    def __truediv__(first, other):
1107
        return dpctl.tensor.divide(first, other)
1✔
1108

1109
    def __xor__(first, other):
1110
        return dpctl.tensor.bitwise_xor(first, other)
1✔
1111

1112
    def __radd__(self, other):
1113
        return dpctl.tensor.add(other, self)
1✔
1114

1115
    def __rand__(self, other):
1116
        return dpctl.tensor.bitwise_and(other, self)
1✔
1117

1118
    def __rfloordiv__(self, other):
1119
        return dpctl.tensor.floor_divide(other, self)
1✔
1120

1121
    def __rlshift__(self, other):
1122
        return dpctl.tensor.bitwise_left_shift(other, self)
1✔
1123

1124
    def __rmatmul__(self, other):
1125
        return NotImplemented
1✔
1126

1127
    def __rmod__(self, other):
1128
        return dpctl.tensor.remainder(other, self)
1✔
1129

1130
    def __rmul__(self, other):
1131
        return dpctl.tensor.multiply(other, self)
1✔
1132

1133
    def __ror__(self, other):
1134
        return dpctl.tensor.bitwise_or(other, self)
1✔
1135

1136
    def __rpow__(self, other):
1137
        return dpctl.tensor.pow(other, self)
1✔
1138

1139
    def __rrshift__(self, other):
1140
        return dpctl.tensor.bitwise_right_shift(other, self)
1✔
1141

1142
    def __rsub__(self, other):
1143
        return dpctl.tensor.subtract(other, self)
1✔
1144

1145
    def __rtruediv__(self, other):
1146
        return dpctl.tensor.divide(other, self)
1✔
1147

1148
    def __rxor__(self, other):
1149
        return dpctl.tensor.bitwise_xor(other, self)
1✔
1150

1151
    def __iadd__(self, other):
1152
        return dpctl.tensor.add(self, other, out=self)
1✔
1153

1154
    def __iand__(self, other):
1155
        return dpctl.tensor.bitwise_and(self, other, out=self)
1✔
1156

1157
    def __ifloordiv__(self, other):
1158
        return dpctl.tensor.floor_divide(self, other, out=self)
1✔
1159

1160
    def __ilshift__(self, other):
1161
        return dpctl.tensor.bitwise_left_shift(self, other, out=self)
1✔
1162

1163
    def __imatmul__(self, other):
1164
        res = self.__matmul__(other)
1✔
1165
        if res is NotImplemented:
1✔
1166
            return res
1✔
1167
        self.__setitem__(Ellipsis, res)
×
1168
        return self
×
1169

1170
    def __imod__(self, other):
1171
        return dpctl.tensor.remainder(self, other, out=self)
1✔
1172

1173
    def __imul__(self, other):
1174
        return dpctl.tensor.multiply(self, other, out=self)
1✔
1175

1176
    def __ior__(self, other):
1177
        return dpctl.tensor.bitwise_or(self, other, out=self)
1✔
1178

1179
    def __ipow__(self, other):
1180
        return dpctl.tensor.pow(self, other, out=self)
1✔
1181

1182
    def __irshift__(self, other):
1183
        return dpctl.tensor.bitwise_right_shift(self, other, out=self)
1✔
1184

1185
    def __isub__(self, other):
1186
        return dpctl.tensor.subtract(self, other, out=self)
1✔
1187

1188
    def __itruediv__(self, other):
1189
        return dpctl.tensor.divide(self, other, out=self)
1✔
1190

1191
    def __ixor__(self, other):
1192
        return dpctl.tensor.bitwise_xor(self, other, out=self)
1✔
1193

1194
    def __str__(self):
1195
        return usm_ndarray_str(self)
1✔
1196

1197
    def __repr__(self):
1198
        return usm_ndarray_repr(self)
1✔
1199

1200

1201
cdef usm_ndarray _real_view(usm_ndarray ary):
1✔
1202
    """
1203
    View into real parts of a complex type array
1204
    """
1205
    cdef int r_typenum_ = -1
1✔
1206
    cdef usm_ndarray r = None
1✔
1207
    cdef Py_ssize_t offset_elems = 0
1✔
1208

1209
    if (ary.typenum_ == UAR_CFLOAT):
1✔
1210
        r_typenum_ = UAR_FLOAT
1✔
1211
    elif (ary.typenum_ == UAR_CDOUBLE):
×
1212
        r_typenum_ = UAR_DOUBLE
×
1213
    else:
1214
        raise InternalUSMArrayError(
×
1215
            "_real_view call on array of non-complex type.")
1216

1217
    offset_elems = ary.get_offset() * 2
1✔
1218
    r = usm_ndarray.__new__(
1✔
1219
        usm_ndarray,
1220
        _make_int_tuple(ary.nd_, ary.shape_) if ary.nd_ > 0 else tuple(),
1✔
1221
        dtype=_make_typestr(r_typenum_),
1✔
1222
        strides=tuple(2 * si for si in ary.strides),
1✔
1223
        buffer=ary.base_,
1✔
1224
        offset=offset_elems,
1✔
1225
        order=('C' if (ary.flags_ & USM_ARRAY_C_CONTIGUOUS) else 'F')
1✔
1226
    )
1227
    r.flags_ |= (ary.flags_ & USM_ARRAY_WRITABLE)
1✔
1228
    r.array_namespace_ = ary.array_namespace_
1✔
1229
    return r
1✔
1230

1231

1232
cdef usm_ndarray _imag_view(usm_ndarray ary):
1✔
1233
    """
1234
    View into imaginary parts of a complex type array
1235
    """
1236
    cdef int r_typenum_ = -1
1✔
1237
    cdef usm_ndarray r = None
1✔
1238
    cdef Py_ssize_t offset_elems = 0
1✔
1239

1240
    if (ary.typenum_ == UAR_CFLOAT):
1✔
1241
        r_typenum_ = UAR_FLOAT
1✔
1242
    elif (ary.typenum_ == UAR_CDOUBLE):
×
1243
        r_typenum_ = UAR_DOUBLE
×
1244
    else:
1245
        raise InternalUSMArrayError(
×
1246
            "_imag_view call on array of non-complex type.")
1247

1248
    # displace pointer to imaginary part
1249
    offset_elems = 2 * ary.get_offset() + 1
1✔
1250
    r = usm_ndarray.__new__(
1✔
1251
        usm_ndarray,
1252
        _make_int_tuple(ary.nd_, ary.shape_) if ary.nd_ > 0 else tuple(),
1✔
1253
        dtype=_make_typestr(r_typenum_),
1✔
1254
        strides=tuple(2 * si for si in ary.strides),
1✔
1255
        buffer=ary.base_,
1✔
1256
        offset=offset_elems,
1✔
1257
        order=('C' if (ary.flags_ & USM_ARRAY_C_CONTIGUOUS) else 'F')
1✔
1258
    )
1259
    r.flags_ |= (ary.flags_ & USM_ARRAY_WRITABLE)
1✔
1260
    r.array_namespace_ = ary.array_namespace_
1✔
1261
    return r
1✔
1262

1263

1264
cdef usm_ndarray _transpose(usm_ndarray ary):
1✔
1265
    """
1266
    Construct transposed array without copying the data
1267
    """
1268
    cdef usm_ndarray r = usm_ndarray.__new__(
1✔
1269
        usm_ndarray,
1270
        _make_reversed_int_tuple(ary.nd_, ary.shape_),
1✔
1271
        dtype=_make_typestr(ary.typenum_),
1✔
1272
        strides=(
1273
            _make_reversed_int_tuple(ary.nd_, ary.strides_)
1✔
1274
            if (ary.strides_) else None),
1✔
1275
        buffer=ary.base_,
1✔
1276
        order=('F' if (ary.flags_ & USM_ARRAY_C_CONTIGUOUS) else 'C'),
1✔
1277
        offset=ary.get_offset()
1✔
1278
    )
1279
    r.flags_ |= (ary.flags_ & USM_ARRAY_WRITABLE)
1✔
1280
    return r
1✔
1281

1282

1283
cdef usm_ndarray _m_transpose(usm_ndarray ary):
1✔
1284
    """
1285
    Construct matrix transposed array
1286
    """
1287
    cdef usm_ndarray r = usm_ndarray.__new__(
1✔
1288
        usm_ndarray,
1289
        _swap_last_two(_make_int_tuple(ary.nd_, ary.shape_)),
1✔
1290
        dtype=_make_typestr(ary.typenum_),
1✔
1291
        strides=_swap_last_two(ary.strides),
1✔
1292
        buffer=ary.base_,
1✔
1293
        order=('F' if (ary.flags_ & USM_ARRAY_C_CONTIGUOUS) else 'C'),
1✔
1294
        offset=ary.get_offset()
1✔
1295
    )
1296
    r.flags_ |= (ary.flags_ & USM_ARRAY_WRITABLE)
1✔
1297
    return r
1✔
1298

1299

1300
cdef usm_ndarray _zero_like(usm_ndarray ary):
1✔
1301
    """
1302
    Make C-contiguous array of zero elements with same shape
1303
    and type as ary.
1304
    """
1305
    cdef dt = _make_typestr(ary.typenum_)
1✔
1306
    cdef usm_ndarray r = usm_ndarray(
1✔
1307
        _make_int_tuple(ary.nd_, ary.shape_),
1✔
1308
        dtype=dt,
1✔
1309
        buffer=ary.base_.get_usm_type()
1✔
1310
    )
1311
    r.base_.memset()
1✔
1312
    return r
1✔
1313

1314

1315
cdef api char* UsmNDArray_GetData(usm_ndarray arr):
1✔
1316
    """Get allocation pointer of zero index element of array """
1317
    return arr.get_data()
1✔
1318

1319

1320
cdef api int UsmNDArray_GetNDim(usm_ndarray arr):
1✔
1321
    """Get array rank: length of its shape"""
1322
    return arr.get_ndim()
1✔
1323

1324

1325
cdef api Py_ssize_t* UsmNDArray_GetShape(usm_ndarray arr):
1✔
1326
    """Get host pointer to shape vector"""
1327
    return arr.get_shape()
1✔
1328

1329

1330
cdef api Py_ssize_t* UsmNDArray_GetStrides(usm_ndarray arr):
1✔
1331
    """Get host pointer to strides vector"""
1332
    return arr.get_strides()
1✔
1333

1334

1335
cdef api int UsmNDArray_GetTypenum(usm_ndarray arr):
1✔
1336
    """Get type number for data type of array elements"""
1337
    return arr.get_typenum()
1✔
1338

1339

1340
cdef api int UsmNDArray_GetElementSize(usm_ndarray arr):
1✔
1341
    """Get array element size in bytes"""
1342
    return arr.get_itemsize()
1✔
1343

1344

1345
cdef api int UsmNDArray_GetFlags(usm_ndarray arr):
1✔
1346
    """Get flags of array"""
1347
    return arr.get_flags()
1✔
1348

1349

1350
cdef api c_dpctl.DPCTLSyclQueueRef UsmNDArray_GetQueueRef(usm_ndarray arr):
1✔
1351
    """Get DPCTLSyclQueueRef for queue associated with the array"""
1352
    return arr.get_queue_ref()
1✔
1353

1354

1355
cdef api Py_ssize_t UsmNDArray_GetOffset(usm_ndarray arr):
1✔
1356
    """Get offset of zero-index array element from the beginning of the USM
1357
    allocation"""
1358
    return arr.get_offset()
1✔
1359

1360

1361
cdef api void UsmNDArray_SetWritableFlag(usm_ndarray arr, int flag):
1✔
1362
    """Set/unset USM_ARRAY_WRITABLE in the given array `arr`."""
1363
    arr._set_writable_flag(flag)
1✔
1364

1365
cdef api object UsmNDArray_MakeSimpleFromMemory(
1✔
1366
    int nd, const Py_ssize_t *shape, int typenum,
1367
    c_dpmem._Memory mobj, Py_ssize_t offset, char order
1368
):
1369
    """Create contiguous usm_ndarray.
1370

1371
    Args:
1372
        nd: number of dimensions (non-negative)
1373
        shape: array of nd non-negative array's sizes along each dimension
1374
        typenum: array elemental type number
1375
        ptr: pointer to the start of allocation
1376
        QRef: DPCTLSyclQueueRef associated with the allocation
1377
        offset: distance between element with zero multi-index and the
1378
                start of allocation
1379
        oder: Memory layout of the array. Use 'C' for C-contiguous or
1380
              row-major layout; 'F' for F-contiguous or column-major layout
1381
    Returns:
1382
        Created usm_ndarray instance
1383
    """
1384
    cdef object shape_tuple = _make_int_tuple(nd, <Py_ssize_t *>shape)
1✔
1385
    cdef usm_ndarray arr = usm_ndarray(
1✔
1386
        shape_tuple,
1387
        dtype=_make_typestr(typenum),
1✔
1388
        buffer=mobj,
1✔
1389
        offset=offset,
1✔
1390
        order=<bytes>(order)
1✔
1391
    )
1392
    return arr
1✔
1393

1394

1395
cdef api object UsmNDArray_MakeSimpleFromPtr(
1✔
1396
    size_t nelems,
1397
    int typenum,
1398
    c_dpctl.DPCTLSyclUSMRef ptr,
1399
    c_dpctl.DPCTLSyclQueueRef QRef,
1400
    object owner
1401
):
1402
    """Create 1D contiguous usm_ndarray from pointer.
1403

1404
    Args:
1405
        nelems: number of elements in array
1406
        typenum: array elemental type number
1407
        ptr: pointer to the start of allocation
1408
        QRef: DPCTLSyclQueueRef associated with the allocation
1409
        owner: Python object managing lifetime of USM allocation.
1410
               Value None implies transfer of USM allocation ownership
1411
               to the created array object.
1412
    Returns:
1413
        Created usm_ndarray instance
1414
    """
1415
    cdef size_t itemsize = type_bytesize(typenum)
1✔
1416
    cdef size_t nbytes = itemsize * nelems
1✔
1417
    cdef c_dpmem._Memory mobj = c_dpmem._Memory.create_from_usm_pointer_size_qref(
1✔
1418
        ptr, nbytes, QRef, memory_owner=owner
1419
    )
1420
    cdef usm_ndarray arr = usm_ndarray(
1✔
1421
        (nelems,),
1✔
1422
        dtype=_make_typestr(typenum),
1✔
1423
        buffer=mobj
1✔
1424
    )
1425
    return arr
1✔
1426

1427
cdef api object UsmNDArray_MakeFromPtr(
1✔
1428
    int nd,
1429
    const Py_ssize_t *shape,
1430
    int typenum,
1431
    const Py_ssize_t *strides,
1432
    c_dpctl.DPCTLSyclUSMRef ptr,
1433
    c_dpctl.DPCTLSyclQueueRef QRef,
1434
    Py_ssize_t offset,
1435
    object owner
1436
):
1437
    """
1438
    General usm_ndarray constructor from externally made USM-allocation.
1439

1440
    Args:
1441
        nd: number of dimensions (non-negative)
1442
        shape: array of nd non-negative array's sizes along each dimension
1443
        typenum: array elemental type number
1444
        strides: array of nd strides along each dimension in elements
1445
        ptr: pointer to the start of allocation
1446
        QRef: DPCTLSyclQueueRef associated with the allocation
1447
        offset: distance between element with zero multi-index and the
1448
                start of allocation
1449
        owner: Python object managing lifetime of USM allocation.
1450
               Value None implies transfer of USM allocation ownership
1451
               to the created array object.
1452
    Returns:
1453
        Created usm_ndarray instance
1454
    """
1455
    cdef size_t itemsize = type_bytesize(typenum)
1✔
1456
    cdef int err = 0
1✔
1457
    cdef size_t nelems = 1
1✔
1458
    cdef Py_ssize_t min_disp = 0
1✔
1459
    cdef Py_ssize_t max_disp = 0
1✔
1460
    cdef Py_ssize_t step_ = 0
1✔
1461
    cdef Py_ssize_t dim_ = 0
1✔
1462
    cdef it = 0
1✔
1463
    cdef c_dpmem._Memory mobj
1464
    cdef usm_ndarray arr
1465
    cdef object obj_shape
1466
    cdef object obj_strides
1467

1468
    if (nd < 0):
1✔
1469
        raise ValueError("Dimensionality must be non-negative")
×
1470
    if (ptr is NULL or QRef is NULL):
1✔
1471
        raise ValueError(
×
1472
            "Non-null USM allocation pointer and QRef are expected"
1473
        )
1474
    if (nd == 0):
1✔
1475
        # case of 0d scalars
1476
        mobj = c_dpmem._Memory.create_from_usm_pointer_size_qref(
1✔
1477
            ptr, itemsize, QRef, memory_owner=owner
1478
        )
1479
        arr = usm_ndarray(
1✔
1480
            tuple(),
1✔
1481
            dtype=_make_typestr(typenum),
1✔
1482
            buffer=mobj
1✔
1483
        )
1484
        return arr
1✔
1485
    if (shape is NULL or strides is NULL):
1✔
1486
        raise ValueError("Both shape and stride vectors are required")
×
1487
    for it in range(nd):
1✔
1488
        dim_ = shape[it]
1✔
1489
        if dim_ < 0:
1✔
1490
            raise ValueError(
×
1491
                f"Dimension along axis {it} must be non-negative"
×
1492
            )
1493
        nelems *= dim_
1✔
1494
        if dim_ > 0:
1✔
1495
            step_ = strides[it]
1✔
1496
            if step_ > 0:
1✔
1497
                max_disp += step_ * (dim_ - 1)
1✔
1498
            else:
1499
                min_disp += step_ * (dim_ - 1)
×
1500

1501
    obj_shape = _make_int_tuple(nd, shape)
1✔
1502
    obj_strides = _make_int_tuple(nd, strides)
1✔
1503
    if nelems == 0:
1✔
1504
        mobj = c_dpmem._Memory.create_from_usm_pointer_size_qref(
1✔
1505
            ptr, itemsize, QRef, memory_owner=owner
1506
        )
1507
        arr = usm_ndarray(
1✔
1508
            obj_shape,
1509
            dtype=_make_typestr(typenum),
1✔
1510
            strides=obj_strides,
1✔
1511
            buffer=mobj,
1✔
1512
            offset=0
1513
        )
1514
        return arr
1✔
1515
    if offset + min_disp < 0:
1✔
1516
        raise ValueError(
×
1517
            "Given shape, strides and offset reference out-of-bound memory"
1518
        )
1519
    nbytes = itemsize * (offset + max_disp + 1)
1✔
1520
    mobj = c_dpmem._Memory.create_from_usm_pointer_size_qref(
1✔
1521
        ptr, nbytes, QRef, memory_owner=owner
1522
    )
1523
    arr = usm_ndarray(
1✔
1524
        obj_shape,
1525
        dtype=_make_typestr(typenum),
1✔
1526
        strides=obj_strides,
1✔
1527
        buffer=mobj,
1✔
1528
        offset=offset
1✔
1529
    )
1530
    return arr
1✔
1531

1532

1533
def _is_object_with_buffer_protocol(o):
1✔
1534
   "Returns True if object support Python buffer protocol"
1535
   return _is_buffer(o)
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