Skip to content

Commit 11f251d

Browse files
Add dpnp.byte_bounds implementation (#2155)
* Add dpnp.byte_bounds implementation * Update func description to render the doc correctly --------- Co-authored-by: Anton <[email protected]>
1 parent 81047fa commit 11f251d

File tree

6 files changed

+194
-1
lines changed

6 files changed

+194
-1
lines changed

doc/reference/misc.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ Utility
1010
:toctree: generated/
1111
:nosignatures:
1212

13+
dpnp.broadcast_shapes
14+
dpnp.byte_bounds
1315
dpnp.get_include
1416
dpnp.show_config
1517
dpnp.show_runtime
16-
dpnp.broadcast_shapes

dpnp/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@
5454
from dpnp.dpnp_iface_types import *
5555
from dpnp.dpnp_iface import *
5656
from dpnp.dpnp_iface import __all__ as _iface__all__
57+
from dpnp.dpnp_iface_utils import *
58+
from dpnp.dpnp_iface_utils import __all__ as _ifaceutils__all__
5759
from dpnp._version import get_versions
5860

5961
__all__ = _iface__all__
62+
__all__ += _ifaceutils__all__
63+
6064

6165
__version__ = get_versions()["version"]
6266
del get_versions

dpnp/dpnp_iface_utils.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# -*- coding: utf-8 -*-
2+
# *****************************************************************************
3+
# Copyright (c) 2024, Intel Corporation
4+
# All rights reserved.
5+
#
6+
# Redistribution and use in source and binary forms, with or without
7+
# modification, are permitted provided that the following conditions are met:
8+
# - Redistributions of source code must retain the above copyright notice,
9+
# this list of conditions and the following disclaimer.
10+
# - Redistributions in binary form must reproduce the above copyright notice,
11+
# this list of conditions and the following disclaimer in the documentation
12+
# and/or other materials provided with the distribution.
13+
#
14+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24+
# THE POSSIBILITY OF SUCH DAMAGE.
25+
# *****************************************************************************
26+
27+
"""
28+
Interface of the utils function of the DPNP
29+
30+
Notes
31+
-----
32+
This module is a face or public interface file for the library
33+
34+
"""
35+
36+
import dpnp
37+
38+
__all__ = ["byte_bounds"]
39+
40+
41+
def byte_bounds(a):
42+
"""
43+
Returns a 2-tuple with pointers to the end-points of the array.
44+
45+
For full documentation refer to :obj:`numpy.lib.array_utils.byte_bounds`.
46+
47+
Parameters
48+
----------
49+
a : {dpnp.ndarray, usm_ndarray}
50+
Input array
51+
52+
Returns
53+
-------
54+
(low, high) : tuple of 2 integers
55+
The first integer is the first byte of the array, the second integer is
56+
just past the last byte of the array. If `a` is not contiguous it will
57+
not use every byte between the (`low`, `high`) values.
58+
59+
Examples
60+
--------
61+
>>> import dpnp as np
62+
>>> I = np.eye(2, dtype=np.complex64);
63+
>>> low, high = np.byte_bounds(I)
64+
>>> high - low == I.size*I.itemsize
65+
True
66+
>>> I = np.eye(2);
67+
>>> low, high = np.byte_bounds(I)
68+
>>> high - low == I.size*I.itemsize
69+
True
70+
71+
"""
72+
73+
# pylint: disable=protected-access
74+
return dpnp.get_usm_ndarray(a)._byte_bounds

tests/test_array_utils.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import dpnp
2+
3+
4+
def test_byte_bounds():
5+
a = dpnp.zeros((3, 4), dtype=dpnp.int64, usm_type="shared")
6+
values = dpnp.arange(12, dtype="int64")
7+
for i in range(3):
8+
a[i, :] = values[i * 4 : (i + 1) * 4]
9+
low, high = dpnp.byte_bounds(a)
10+
assert (high - low) == (a.size * a.itemsize)
11+
12+
13+
def test_unusual_order_positive_stride():
14+
a = dpnp.zeros((3, 4), dtype=dpnp.int64, usm_type="shared")
15+
values = dpnp.arange(12, dtype="int64")
16+
for i in range(3):
17+
a[i, :] = values[i * 4 : (i + 1) * 4]
18+
b = a.T
19+
low, high = dpnp.byte_bounds(b)
20+
assert (high - low) == (b.size * b.itemsize)
21+
22+
23+
def test_unusual_order_negative_stride():
24+
a = dpnp.zeros((3, 4), dtype=dpnp.int64, usm_type="shared")
25+
values = dpnp.arange(12, dtype="int64")
26+
for i in range(3):
27+
a[i, :] = values[i * 4 : (i + 1) * 4]
28+
b = a.T[::-1]
29+
low, high = dpnp.byte_bounds(b)
30+
assert (high - low) == (b.size * b.itemsize)
31+
32+
33+
def test_strided():
34+
a = dpnp.zeros(12, dtype=dpnp.int64, usm_type="shared")
35+
a[:] = dpnp.arange(12, dtype="int64")
36+
b = a[::2]
37+
low, high = dpnp.byte_bounds(b)
38+
expected_byte_diff = b.size * 2 * b.itemsize - b.itemsize
39+
assert (high - low) == expected_byte_diff

tests/third_party/cupy/misc_tests/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import dpnp as cupy
2+
3+
4+
def test_1d_contiguous():
5+
a = cupy.zeros(12, dtype=cupy.int64)
6+
itemsize = a.itemsize
7+
a_low = a.get_array()._pointer
8+
a_high = a.get_array()._pointer + 12 * itemsize
9+
assert cupy.byte_bounds(a) == (a_low, a_high)
10+
11+
12+
def test_2d_contiguous():
13+
a = cupy.zeros((4, 7), dtype=cupy.int64)
14+
itemsize = a.itemsize
15+
a_low = a.get_array()._pointer
16+
a_high = a.get_array()._pointer + 4 * 7 * itemsize
17+
assert cupy.byte_bounds(a) == (a_low, a_high)
18+
19+
20+
def test_1d_noncontiguous_pos_stride():
21+
a = cupy.zeros(12, dtype=cupy.int64)
22+
itemsize = a.itemsize
23+
b = a[::2]
24+
b_low = b.get_array()._pointer
25+
b_high = b.get_array()._pointer + 11 * itemsize # a[10]
26+
assert cupy.byte_bounds(b) == (b_low, b_high)
27+
28+
29+
def test_2d_noncontiguous_pos_stride():
30+
a = cupy.zeros((4, 7), dtype=cupy.int64)
31+
b = a[::2, ::2]
32+
itemsize = b.itemsize
33+
b_low = a.get_array()._pointer
34+
b_high = b.get_array()._pointer + 3 * 7 * itemsize # a[2][6]
35+
assert cupy.byte_bounds(b) == (b_low, b_high)
36+
37+
38+
def test_1d_contiguous_neg_stride():
39+
a = cupy.zeros(12, dtype=cupy.int64)
40+
b = a[::-1]
41+
itemsize = b.itemsize
42+
b_low = b.get_array()._pointer - 11 * itemsize
43+
b_high = b.get_array()._pointer + 1 * itemsize
44+
assert cupy.byte_bounds(b) == (b_low, b_high)
45+
46+
47+
def test_2d_noncontiguous_neg_stride():
48+
a = cupy.zeros((4, 7), dtype=cupy.int64)
49+
b = a[::-2, ::-2] # strides = (-56, -8), shape = (2, 4)
50+
itemsize = b.itemsize
51+
b_low = (
52+
b.get_array()._pointer
53+
- 2 * 7 * itemsize * (2 - 1)
54+
- 2 * itemsize * (4 - 1)
55+
)
56+
b_high = b.get_array()._pointer + 1 * itemsize
57+
assert cupy.byte_bounds(b) == (b_low, b_high)
58+
59+
60+
def test_2d_noncontiguous_posneg_stride_1():
61+
a = cupy.zeros((4, 7), dtype=cupy.int64)
62+
b = a[::1, ::-1] # strides = (28, -4), shape=(4, 7)
63+
itemsize = b.itemsize
64+
b_low = b.get_array()._pointer - itemsize * (7 - 1)
65+
b_high = b.get_array()._pointer + 1 * itemsize + 7 * itemsize * (4 - 1)
66+
assert cupy.byte_bounds(b) == (b_low, b_high)
67+
68+
69+
def test_2d_noncontiguous_posneg_stride_2():
70+
a = cupy.zeros((4, 7), dtype=cupy.int64)
71+
b = a[::2, ::-2] # strides = (56, -8), shape=(2, 4)
72+
itemsize = b.itemsize
73+
b_low = b.get_array()._pointer - 2 * itemsize * (4 - 1)
74+
b_high = b.get_array()._pointer + 1 * itemsize + 2 * 7 * itemsize * (2 - 1)
75+
assert cupy.byte_bounds(b) == (b_low, b_high)

0 commit comments

Comments
 (0)