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

IntelPython / dpctl / 16059786942

03 Jul 2025 08:18PM UTC coverage: 85.898%. Remained the same
16059786942

Pull #2118

github

web-flow
Merge f64686826 into 6f6fe50f2
Pull Request #2118: Permit Cython 3.1.0 for Python 3.13

3225 of 3876 branches covered (83.2%)

Branch coverage included in aggregate %.

12234 of 14121 relevant lines covered (86.64%)

6887.13 hits per line

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

87.69
/dpctl/tensor/_slicing.pxi
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 numbers
×
18
from operator import index
×
19
from cpython.buffer cimport PyObject_CheckBuffer
20

21

22
cdef bint _is_buffer(object o):
1✔
23
    return PyObject_CheckBuffer(o)
1✔
24

25

26
cdef Py_ssize_t _slice_len(
×
27
    Py_ssize_t sl_start,
28
    Py_ssize_t sl_stop,
29
    Py_ssize_t sl_step
30
):
31
    """
32
    Compute len(range(sl_start, sl_stop, sl_step))
33
    """
34
    if sl_start == sl_stop:
1✔
35
        return 0
1✔
36
    if sl_step > 0:
1✔
37
        if sl_start > sl_stop:
1✔
38
            return 0
×
39
        # 1 + argmax k such htat sl_start + sl_step*k < sl_stop
40
        return 1 + ((sl_stop - sl_start - 1) // sl_step)
1✔
41
    else:
42
        if sl_start < sl_stop:
1✔
43
            return 0
×
44
        return 1 + ((sl_stop - sl_start + 1) // sl_step)
1✔
45

46

47
cdef bint _is_integral(object x) except *:
×
48
    """Gives True if x is an integral slice spec"""
49
    if isinstance(x, usm_ndarray):
1✔
50
        if x.ndim > 0:
1✔
51
            return False
1✔
52
        if x.dtype.kind not in "ui":
1✔
53
            return False
×
54
        return True
1✔
55
    if isinstance(x, bool):
1✔
56
        return False
×
57
    if isinstance(x, int):
1✔
58
        return True
1✔
59
    if _is_buffer(x):
1✔
60
        mbuf = memoryview(x)
1✔
61
        if mbuf.ndim == 0:
1✔
62
            f = mbuf.format
1✔
63
            return f in "bBhHiIlLqQ"
1✔
64
        else:
65
            return False
×
66
    if callable(getattr(x, "__index__", None)):
1✔
67
        try:
×
68
            index(x)
×
69
        except (TypeError, ValueError):
×
70
            return False
×
71
        return True
×
72
    return False
1✔
73

74

75
cdef bint _is_boolean(object x) except *:
×
76
    """Gives True if x is an integral slice spec"""
77
    if isinstance(x, usm_ndarray):
1✔
78
        if x.ndim > 0:
1✔
79
            return False
1✔
80
        if x.dtype.kind not in "b":
1✔
81
            return False
1✔
82
        return True
1✔
83
    if isinstance(x, bool):
1✔
84
        return True
1✔
85
    if isinstance(x, (int, float, complex)):
1✔
86
        return False
1✔
87
    if _is_buffer(x):
1✔
88
        mbuf = memoryview(x)
1✔
89
        if mbuf.ndim == 0:
1✔
90
            f = mbuf.format
1✔
91
            return f in "?"
1✔
92
        else:
93
            return False
×
94
    if callable(getattr(x, "__bool__", None)):
1✔
95
        try:
×
96
            x.__bool__()
×
97
        except (TypeError, ValueError):
×
98
            return False
×
99
        return True
×
100
    return False
1✔
101

102

103
def _basic_slice_meta(ind, shape : tuple, strides : tuple, offset : int):
×
104
    """
105
    Give basic slicing index `ind` and array layout information produce
106
    a 5-tuple (resulting_shape, resulting_strides, resulting_offset,
107
       advanced_ind, resulting_advanced_ind_pos)
108
    used to construct a view into underlying array over which advanced
109
    indexing, if any, is to be performed.
110

111
    Raises IndexError for invalid index `ind`.
112
    """
113
    _no_advanced_ind = tuple()
1✔
114
    _no_advanced_pos = -1
1✔
115
    if ind is Ellipsis:
1✔
116
        return (shape, strides, offset, _no_advanced_ind, _no_advanced_pos)
1✔
117
    elif ind is None:
1✔
118
        return (
1✔
119
            (1,) + shape,
1✔
120
            (0,) + strides,
1✔
121
            offset,
122
            _no_advanced_ind,
123
            _no_advanced_pos,
1✔
124
        )
125
    elif isinstance(ind, slice):
1✔
126
        sl_start, sl_stop, sl_step = ind.indices(shape[0])
1✔
127
        sh0 = _slice_len(sl_start, sl_stop, sl_step)
1✔
128
        str0 = sl_step * strides[0]
1✔
129
        new_strides = (
130
            strides if (sl_step == 1 or sh0 == 0) else (str0,) + strides[1:]
1✔
131
        )
132
        new_shape = (sh0, ) + shape[1:]
1✔
133
        is_empty = any(sh_i == 0 for sh_i in new_shape)
1✔
134
        new_offset = offset if is_empty else offset + sl_start * strides[0]
1✔
135
        return (
1✔
136
            new_shape,
1✔
137
            new_strides,
138
            new_offset,
139
            _no_advanced_ind,
140
            _no_advanced_pos,
1✔
141
        )
142
    elif _is_boolean(ind):
1✔
143
        if ind:
1✔
144
            return (
1✔
145
                (1,) + shape,
1✔
146
                (0,) + strides,
1✔
147
                offset,
148
                _no_advanced_ind,
149
                _no_advanced_pos,
1✔
150
            )
151
        else:
152
            return (
1✔
153
                (0,) + shape,
1✔
154
                (0,) + strides,
1✔
155
                offset,
156
                _no_advanced_ind,
157
                _no_advanced_pos,
1✔
158
            )
159
    elif _is_integral(ind):
1✔
160
        ind = index(ind)
1✔
161
        new_shape = shape[1:]
1✔
162
        new_strides = strides[1:]
1✔
163
        is_empty = any(sh_i == 0 for sh_i in new_shape)
1✔
164
        if 0 <= ind < shape[0]:
1✔
165
            new_offset = offset if is_empty else offset + ind * strides[0]
1✔
166
            return (
1✔
167
                new_shape,
1✔
168
                new_strides,
169
                new_offset,
170
                _no_advanced_ind,
171
                _no_advanced_pos,
1✔
172
            )
173
        elif -shape[0] <= ind < 0:
1✔
174
            new_offset = (
175
                offset if is_empty else offset + (shape[0] + ind) * strides[0]
1✔
176
            )
177
            return (
1✔
178
                new_shape,
1✔
179
                new_strides,
180
                new_offset,
181
                _no_advanced_ind,
182
                _no_advanced_pos,
1✔
183
            )
184
        else:
185
            raise IndexError(
×
186
                "Index {0} is out of range for axes 0 with "
187
                "size {1}".format(ind, shape[0]))
×
188
    elif isinstance(ind, usm_ndarray):
1✔
189
        return (shape, strides, offset, (ind,), 0)
1✔
190
    elif isinstance(ind, tuple):
1✔
191
        axes_referenced = 0
1✔
192
        ellipses_count = 0
1✔
193
        newaxis_count = 0
1✔
194
        explicit_index = 0
1✔
195
        seen_arrays_yet = False
1✔
196
        array_streak_started = False
1✔
197
        array_streak_interrupted = False
1✔
198
        for i in ind:
1✔
199
            if i is None:
1✔
200
                newaxis_count += 1
1✔
201
                if array_streak_started:
1✔
202
                    array_streak_interrupted = True
1✔
203
            elif i is Ellipsis:
1✔
204
                ellipses_count += 1
1✔
205
                if array_streak_started:
1✔
206
                    array_streak_interrupted = True
1✔
207
            elif isinstance(i, slice):
1✔
208
                axes_referenced += 1
1✔
209
                if array_streak_started:
1✔
210
                    array_streak_interrupted = True
1✔
211
            elif _is_boolean(i):
1✔
212
                newaxis_count += 1
1✔
213
                if array_streak_started:
1✔
214
                    array_streak_interrupted = True
×
215
            elif _is_integral(i):
1✔
216
                axes_referenced += 1
1✔
217
                if not array_streak_started and array_streak_interrupted:
1✔
218
                    explicit_index += 1
×
219
            elif isinstance(i, usm_ndarray):
1✔
220
                if not seen_arrays_yet:
1✔
221
                    seen_arrays_yet = True
1✔
222
                    array_streak_started = True
1✔
223
                    array_streak_interrupted = False
1✔
224
                if array_streak_interrupted:
1✔
225
                    raise IndexError(
1✔
226
                        "Advanced indexing array specs may not be "
227
                        "separated by basic slicing specs."
228
                    )
229
                dt_k = i.dtype.kind
1✔
230
                if dt_k == "b" and i.ndim > 0:
1✔
231
                    axes_referenced += i.ndim
1✔
232
                elif dt_k in "ui" and i.ndim > 0:
1✔
233
                    axes_referenced += 1
1✔
234
                else:
235
                    raise IndexError(
×
236
                        "arrays used as indices must be of integer "
237
                        "(or boolean) type"
238
                    )
239
            else:
240
                raise IndexError(
1✔
241
                    "Only integers, slices (`:`), ellipsis (`...`), "
242
                    "dpctl.tensor.newaxis (`None`) and integer and "
243
                    "boolean arrays are valid indices."
244
                )
245
        if ellipses_count > 1:
1✔
246
            raise IndexError(
1✔
247
                "an index can only have a single ellipsis ('...')")
248
        if axes_referenced > len(shape):
1✔
249
            raise IndexError(
1✔
250
                "too many indices for an array, array is "
251
                "{0}-dimensional, but {1} were indexed".format(
1✔
252
                    len(shape), axes_referenced))
1✔
253
        if ellipses_count:
1✔
254
            ellipses_count = len(shape) - axes_referenced
1✔
255
        new_shape_len = (newaxis_count + ellipses_count
1✔
256
                         + axes_referenced - explicit_index)
1✔
257
        new_shape = list()
1✔
258
        new_strides = list()
1✔
259
        new_advanced_ind = list()
1✔
260
        k = 0
1✔
261
        new_advanced_start_pos = -1
1✔
262
        advanced_start_pos_set = False
1✔
263
        new_offset = offset
1✔
264
        is_empty = False
1✔
265
        array_streak = False
1✔
266
        for i in range(len(ind)):
1✔
267
            ind_i = ind[i]
1✔
268
            if (ind_i is Ellipsis):
1✔
269
                k_new = k + ellipses_count
1✔
270
                new_shape.extend(shape[k:k_new])
1✔
271
                new_strides.extend(strides[k:k_new])
1✔
272
                if any(dim == 0 for dim in shape[k:k_new]):
1✔
273
                    is_empty = True
×
274
                    new_offset = offset
×
275
                k = k_new
1✔
276
                if array_streak:
1✔
277
                    array_streak = False
1✔
278
            elif ind_i is None:
1✔
279
                new_shape.append(1)
1✔
280
                new_strides.append(0)
1✔
281
                if array_streak:
1✔
282
                    array_streak = False
1✔
283
            elif isinstance(ind_i, slice):
1✔
284
                k_new = k + 1
1✔
285
                sl_start, sl_stop, sl_step = ind_i.indices(shape[k])
1✔
286
                sh_i = _slice_len(sl_start, sl_stop, sl_step)
1✔
287
                str_i = (1 if sh_i == 0 else sl_step) * strides[k]
1✔
288
                new_shape.append(sh_i)
1✔
289
                new_strides.append(str_i)
1✔
290
                if sh_i > 0 and not is_empty:
1✔
291
                    new_offset = new_offset + sl_start * strides[k]
1✔
292
                if sh_i == 0:
1✔
293
                    is_empty = True
1✔
294
                    new_offset = offset
1✔
295
                k = k_new
1✔
296
                if array_streak:
1✔
297
                    array_streak = False
1✔
298
            elif _is_boolean(ind_i):
1✔
299
                new_shape.append(1 if ind_i else 0)
1✔
300
                new_strides.append(0)
1✔
301
                if array_streak:
1✔
302
                    array_streak = False
×
303
            elif _is_integral(ind_i):
1✔
304
                if array_streak:
1✔
305
                    if not isinstance(ind_i, usm_ndarray):
1✔
306
                        ind_i = index(ind_i)
1✔
307
                        # integer will be converted to an array,
308
                        # still raise if OOB
309
                        if not (
1✔
310
                            0 <= ind_i < shape[k] or -shape[k] <= ind_i < 0
1✔
311
                        ):
312
                            raise IndexError(
×
313
                                "Index {0} is out of range for axes "
314
                                "{1} with size {2}".format(ind_i, k, shape[k])
×
315
                            )
316
                    new_advanced_ind.append(ind_i)
1✔
317
                    k_new = k + 1
1✔
318
                    new_shape.extend(shape[k:k_new])
1✔
319
                    new_strides.extend(strides[k:k_new])
1✔
320
                    k = k_new
1✔
321
                else:
322
                    ind_i = index(ind_i)
1✔
323
                    if 0 <= ind_i < shape[k]:
1✔
324
                        k_new = k + 1
1✔
325
                        if not is_empty:
1✔
326
                            new_offset = new_offset + ind_i * strides[k]
1✔
327
                        k = k_new
1✔
328
                    elif -shape[k] <= ind_i < 0:
1✔
329
                        k_new = k + 1
1✔
330
                        if not is_empty:
1✔
331
                            new_offset = (
332
                                new_offset + (shape[k] + ind_i) * strides[k]
1✔
333
                            )
334
                        k = k_new
1✔
335
                    else:
336
                        raise IndexError(
1✔
337
                            "Index {0} is out of range for axes "
338
                            "{1} with size {2}".format(ind_i, k, shape[k])
1✔
339
                        )
340
            elif isinstance(ind_i, usm_ndarray):
1✔
341
                if not array_streak:
1✔
342
                    array_streak = True
1✔
343
                if not advanced_start_pos_set:
1✔
344
                    new_advanced_start_pos = len(new_shape)
1✔
345
                    advanced_start_pos_set = True
1✔
346
                new_advanced_ind.append(ind_i)
1✔
347
                dt_k = ind_i.dtype.kind
1✔
348
                if dt_k == "b":
1✔
349
                    k_new = k + ind_i.ndim
1✔
350
                else:
351
                    k_new = k + 1
1✔
352
                new_shape.extend(shape[k:k_new])
1✔
353
                new_strides.extend(strides[k:k_new])
1✔
354
                k = k_new
1✔
355
        new_shape.extend(shape[k:])
1✔
356
        new_strides.extend(strides[k:])
1✔
357
        new_shape_len += len(shape) - k
1✔
358
        return (
1✔
359
            tuple(new_shape),
1✔
360
            tuple(new_strides),
1✔
361
            new_offset,
362
            tuple(new_advanced_ind),
1✔
363
            new_advanced_start_pos
1✔
364
        )
365
    else:
366
        raise IndexError(
1✔
367
            "Only integers, slices (`:`), ellipsis (`...`), "
368
            "dpctl.tensor.newaxis (`None`) and integer and "
369
            "boolean arrays are valid indices."
370
        )
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