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

IntelPython / dpnp / 24687578389

20 Apr 2026 08:03PM UTC coverage: 78.429% (-3.6%) from 82.034%
24687578389

push

github

web-flow
Migrate `dpctl.tensor` into `dpnp.tensor` (#2856)

This PR migrates the tensor implementation from `dpctl.tensor` into
`dpnp.tensor` making dpnp the primary owner of the Array API-compliant
tensor layer

Major changes:

- Move compiled C++/SYCL extensions (`_tensor_impl,
_tensor_elementwise_impl, _tensor_reductions_impl, _tensor_sorting_impl,
_tensor_accumulation_impl, tensor linalg`) into `dpnp.tensor`
- Move `usm_ndarray`, `compute-follows-data utilities` and tensor
`tests` from dpctl
- Replace all `dpctl.tensor` references with `dpnp.tensor` in
docstrings, error messages and comments
- Remove redundant dpctl.tensor C-API  interface
- Add `tensor.rst` documentation page describing the module, its
relationship to `dpnp.ndarray` and `dpctl` and linking to the `dpctl
0.21.1 API` reference

This simplifies maintenance, reduces cross-project dependencies and
enables independent development and release cycles

1573 of 2908 branches covered (54.09%)

Branch coverage included in aggregate %.

6973 of 9803 new or added lines in 203 files covered. (71.13%)

1 existing line in 1 file now uncovered.

26259 of 32579 relevant lines covered (80.6%)

7622.15 hits per line

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

94.64
/dpnp/tensor/_array_api.py
1
# *****************************************************************************
2
# Copyright (c) 2026, Intel Corporation
3
# All rights reserved.
4
#
5
# Redistribution and use in source and binary forms, with or without
6
# modification, are permitted provided that the following conditions are met:
7
# - Redistributions of source code must retain the above copyright notice,
8
#   this list of conditions and the following disclaimer.
9
# - Redistributions in binary form must reproduce the above copyright notice,
10
#   this list of conditions and the following disclaimer in the documentation
11
#   and/or other materials provided with the distribution.
12
# - Neither the name of the copyright holder nor the names of its contributors
13
#   may be used to endorse or promote products derived from this software
14
#   without specific prior written permission.
15
#
16
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26
# THE POSSIBILITY OF SUCH DAMAGE.
27
# *****************************************************************************
28

29
import dpctl
1✔
30

31
import dpnp.tensor as dpt
1✔
32

33
from ._tensor_impl import (
1✔
34
    default_device_complex_type,
35
    default_device_fp_type,
36
    default_device_index_type,
37
    default_device_int_type,
38
)
39

40

41
def _isdtype_impl(dtype, kind):
1✔
42
    if isinstance(kind, str):
1✔
43
        if kind == "bool":
1✔
44
            return dtype.kind == "b"
1✔
45
        elif kind == "signed integer":
1✔
46
            return dtype.kind == "i"
1✔
47
        elif kind == "unsigned integer":
1✔
48
            return dtype.kind == "u"
1✔
49
        elif kind == "integral":
1✔
50
            return dtype.kind in "iu"
1✔
51
        elif kind == "real floating":
1✔
52
            return dtype.kind == "f"
1✔
53
        elif kind == "complex floating":
1✔
54
            return dtype.kind == "c"
1✔
55
        elif kind == "numeric":
1✔
56
            return dtype.kind in "iufc"
1✔
57
        else:
58
            raise ValueError(f"Unrecognized data type kind: {kind}")
1✔
59

60
    elif isinstance(kind, tuple):
1✔
61
        return any(_isdtype_impl(dtype, k) for k in kind)
1✔
62
    else:
NEW
63
        raise TypeError(f"Unsupported type for dtype kind: {type(kind)}")
×
64

65

66
def _get_device_impl(d):
1✔
67
    if d is None:
1✔
68
        return dpctl.select_default_device()
1✔
69
    elif isinstance(d, dpctl.SyclDevice):
1✔
NEW
70
        return d
×
71
    elif isinstance(d, (dpt.Device, dpctl.SyclQueue)):
1✔
NEW
72
        return d.sycl_device
×
73
    else:
74
        try:
1✔
75
            return dpctl.SyclDevice(d)
1✔
76
        except TypeError:
1✔
77
            raise TypeError(f"Unsupported type for device argument: {type(d)}")
1✔
78

79

80
__array_api_version__ = "2024.12"
1✔
81

82

83
class Info:
1✔
84
    """namespace returned by ``__array_namespace_info__()``"""
85

86
    def __init__(self):
1✔
87
        self._capabilities = {
1✔
88
            "boolean indexing": True,
89
            "data-dependent shapes": True,
90
            "max dimensions": None,
91
        }
92
        self._all_dtypes = {
1✔
93
            "bool": dpt.bool,
94
            "float32": dpt.float32,
95
            "float64": dpt.float64,
96
            "complex64": dpt.complex64,
97
            "complex128": dpt.complex128,
98
            "int8": dpt.int8,
99
            "int16": dpt.int16,
100
            "int32": dpt.int32,
101
            "int64": dpt.int64,
102
            "uint8": dpt.uint8,
103
            "uint16": dpt.uint16,
104
            "uint32": dpt.uint32,
105
            "uint64": dpt.uint64,
106
        }
107

108
    def capabilities(self):
1✔
109
        """
110
        capabilities()
111

112
        Returns a dictionary of ``dpctl``'s capabilities.
113

114
        The dictionary contains the following keys:
115
            ``"boolean indexing"``:
116
                boolean indicating ``dpctl``'s support of boolean indexing.
117
                Value: ``True``
118
            ``"data-dependent shapes"``:
119
                boolean indicating ``dpctl``'s support of data-dependent shapes.
120
                Value: ``True``
121
            ``max dimensions``:
122
                integer indication the maximum array dimension supported by ``dpctl``.
123
                Value: ``None``
124

125
        Returns:
126
            dict:
127
                dictionary of ``dpctl``'s capabilities
128
        """
129
        return self._capabilities.copy()
1✔
130

131
    def default_device(self):
1✔
132
        """
133
        default_device()
134

135
        Returns the default SYCL device.
136
        """
137
        return dpctl.select_default_device()
1✔
138

139
    def default_dtypes(self, *, device=None):
1✔
140
        """
141
        default_dtypes(*, device=None)
142

143
        Returns a dictionary of default data types for ``device``.
144

145
        Args:
146
            device (Optional[:class:`dpctl.SyclDevice`, :class:`dpctl.SyclQueue`, :class:`dpctl.tensor.Device`, str]):
147
                array API concept of device used in getting default data types.
148
                ``device`` can be ``None`` (in which case the default device
149
                is used), an instance of :class:`dpctl.SyclDevice`, an instance
150
                of :class:`dpctl.SyclQueue`, a :class:`dpctl.tensor.Device`
151
                object returned by :attr:`dpctl.tensor.usm_ndarray.device`, or
152
                a filter selector string.
153
                Default: ``None``.
154

155
        Returns:
156
            dict:
157
                a dictionary of default data types for ``device``:
158

159
                    - ``"real floating"``: dtype
160
                    - ``"complex floating"``: dtype
161
                    - ``"integral"``: dtype
162
                    - ``"indexing"``: dtype
163
        """
164
        device = _get_device_impl(device)
1✔
165
        return {
1✔
166
            "real floating": dpt.dtype(default_device_fp_type(device)),
167
            "complex floating": dpt.dtype(default_device_complex_type(device)),
168
            "integral": dpt.dtype(default_device_int_type(device)),
169
            "indexing": dpt.dtype(default_device_index_type(device)),
170
        }
171

172
    def dtypes(self, *, device=None, kind=None):
1✔
173
        """
174
        dtypes(*, device=None, kind=None)
175

176
        Returns a dictionary of all Array API data types of a specified
177
        ``kind`` supported by ``device``.
178

179
        This dictionary only includes data types supported by the
180
        `Python Array API <https://data-apis.org/array-api/latest/>`_
181
        specification.
182

183
        Args:
184
            device (Optional[:class:`dpctl.SyclDevice`, :class:`dpctl.SyclQueue`, :class:`dpctl.tensor.Device`, str]):
185
                array API concept of device used in getting default data types.
186
                ``device`` can be ``None`` (in which case the default device is
187
                used), an instance of :class:`dpctl.SyclDevice`, an instance of
188
                :class:`dpctl.SyclQueue`, a :class:`dpctl.tensor.Device`
189
                object returned by :attr:`dpctl.tensor.usm_ndarray.device`, or
190
                a filter selector string.
191
                Default: ``None``.
192

193
            kind (Optional[str, Tuple[str, ...]]):
194
                data type kind.
195

196
                - if ``kind`` is ``None``, returns a dictionary of all data
197
                  types supported by `device`
198
                - if ``kind`` is a string, returns a dictionary containing the
199
                  data types belonging to the data type kind specified.
200

201
                  Supports:
202

203
                  * ``"bool"``
204
                  * ``"signed integer"``
205
                  * ``"unsigned integer"``
206
                  * ``"integral"``
207
                  * ``"real floating"``
208
                  * ``"complex floating"``
209
                  * ``"numeric"``
210

211
                - if ``kind`` is a tuple, the tuple represents a union of
212
                  ``kind`` strings, and returns a dictionary containing data
213
                  types corresponding to the-specified union.
214

215
                Default: ``None``.
216

217
        Returns:
218
            dict:
219
                a dictionary of the supported data types of the specified
220
                ``kind``
221
        """
222
        device = _get_device_impl(device)
1✔
223
        _fp64 = device.has_aspect_fp64
1✔
224
        if kind is None:
1✔
225
            return {
1✔
226
                key: val
227
                for key, val in self._all_dtypes.items()
228
                if _fp64 or (key != "float64" and key != "complex128")
229
            }
230
        else:
231
            return {
1✔
232
                key: val
233
                for key, val in self._all_dtypes.items()
234
                if (_fp64 or (key != "float64" and key != "complex128"))
235
                and _isdtype_impl(val, kind)
236
            }
237

238
    def devices(self):
1✔
239
        """
240
        devices()
241

242
        Returns a list of supported devices.
243
        """
244
        return dpctl.get_devices()
1✔
245

246

247
def __array_namespace_info__():
1✔
248
    """
249
    __array_namespace_info__()
250

251
    Returns a namespace with Array API namespace inspection utilities.
252

253
    """
254
    return Info()
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

© 2026 Coveralls, Inc