From a9ff9bad661bf414289eaa5574214c26a743d121 Mon Sep 17 00:00:00 2001 From: "Komarova, Evseniia" Date: Wed, 6 Nov 2024 22:33:26 +0100 Subject: [PATCH 1/2] Add dpnp.byte_bounds implementation --- doc/reference/misc.rst | 3 +- dpnp/__init__.py | 4 + dpnp/dpnp_iface_utils.py | 75 +++++++++++++++++++ tests/test_array_utils.py | 39 ++++++++++ tests/third_party/cupy/misc_tests/__init__.py | 0 .../cupy/misc_tests/test_byte_bounds.py | 75 +++++++++++++++++++ 6 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 dpnp/dpnp_iface_utils.py create mode 100644 tests/test_array_utils.py create mode 100644 tests/third_party/cupy/misc_tests/__init__.py create mode 100644 tests/third_party/cupy/misc_tests/test_byte_bounds.py diff --git a/doc/reference/misc.rst b/doc/reference/misc.rst index 6a9f03fc4dae..2fa35e76c056 100644 --- a/doc/reference/misc.rst +++ b/doc/reference/misc.rst @@ -10,7 +10,8 @@ Utility :toctree: generated/ :nosignatures: + dpnp.broadcast_shapes + dpnp.byte_bounds dpnp.get_include dpnp.show_config dpnp.show_runtime - dpnp.broadcast_shapes diff --git a/dpnp/__init__.py b/dpnp/__init__.py index 165e57a1bb44..4339bd56c8b3 100644 --- a/dpnp/__init__.py +++ b/dpnp/__init__.py @@ -54,9 +54,13 @@ from dpnp.dpnp_iface_types import * from dpnp.dpnp_iface import * from dpnp.dpnp_iface import __all__ as _iface__all__ +from dpnp.dpnp_iface_utils import * +from dpnp.dpnp_iface_utils import __all__ as _ifaceutils__all__ from dpnp._version import get_versions __all__ = _iface__all__ +__all__ += _ifaceutils__all__ + __version__ = get_versions()["version"] del get_versions diff --git a/dpnp/dpnp_iface_utils.py b/dpnp/dpnp_iface_utils.py new file mode 100644 index 000000000000..9bb3051ac955 --- /dev/null +++ b/dpnp/dpnp_iface_utils.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# ***************************************************************************** +# Copyright (c) 2024, Intel Corporation +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# - Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# - Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# ***************************************************************************** + +""" +Interface of the utils function of the DPNP + +Notes +----- +This module is a face or public interface file for the library + +""" + +import dpnp + +__all__ = ["byte_bounds"] + + +def byte_bounds(a): + """ + Returns a 2-tuple with pointers to the end-points of the array. + + For full documentation refer to + :obj:`numpy.lib.array_utils.byte_bounds`. + + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array + + Returns + ------- + (low, high) : tuple of 2 integers + The first integer is the first byte of the array, the second integer is + just past the last byte of the array. If `a` is not contiguous it will + not use every byte between the (`low`, `high`) values. + + Examples + -------- + >>> import dpnp as np + >>> I = np.eye(2, dtype=np.complex64); + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + >>> I = np.eye(2); + >>> low, high = np.byte_bounds(I) + >>> high - low == I.size*I.itemsize + True + + """ + + # pylint: disable=protected-access + return dpnp.get_usm_ndarray(a)._byte_bounds diff --git a/tests/test_array_utils.py b/tests/test_array_utils.py new file mode 100644 index 000000000000..eebbb03de8ca --- /dev/null +++ b/tests/test_array_utils.py @@ -0,0 +1,39 @@ +import dpnp + + +def test_byte_bounds(): + a = dpnp.zeros((3, 4), dtype=dpnp.int64, usm_type="shared") + values = dpnp.arange(12, dtype="int64") + for i in range(3): + a[i, :] = values[i * 4 : (i + 1) * 4] + low, high = dpnp.byte_bounds(a) + assert (high - low) == (a.size * a.itemsize) + + +def test_unusual_order_positive_stride(): + a = dpnp.zeros((3, 4), dtype=dpnp.int64, usm_type="shared") + values = dpnp.arange(12, dtype="int64") + for i in range(3): + a[i, :] = values[i * 4 : (i + 1) * 4] + b = a.T + low, high = dpnp.byte_bounds(b) + assert (high - low) == (b.size * b.itemsize) + + +def test_unusual_order_negative_stride(): + a = dpnp.zeros((3, 4), dtype=dpnp.int64, usm_type="shared") + values = dpnp.arange(12, dtype="int64") + for i in range(3): + a[i, :] = values[i * 4 : (i + 1) * 4] + b = a.T[::-1] + low, high = dpnp.byte_bounds(b) + assert (high - low) == (b.size * b.itemsize) + + +def test_strided(): + a = dpnp.zeros(12, dtype=dpnp.int64, usm_type="shared") + a[:] = dpnp.arange(12, dtype="int64") + b = a[::2] + low, high = dpnp.byte_bounds(b) + expected_byte_diff = b.size * 2 * b.itemsize - b.itemsize + assert (high - low) == expected_byte_diff diff --git a/tests/third_party/cupy/misc_tests/__init__.py b/tests/third_party/cupy/misc_tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/third_party/cupy/misc_tests/test_byte_bounds.py b/tests/third_party/cupy/misc_tests/test_byte_bounds.py new file mode 100644 index 000000000000..c341d30b36db --- /dev/null +++ b/tests/third_party/cupy/misc_tests/test_byte_bounds.py @@ -0,0 +1,75 @@ +import dpnp as cupy + + +def test_1d_contiguous(): + a = cupy.zeros(12, dtype=cupy.int64) + itemsize = a.itemsize + a_low = a.get_array()._pointer + a_high = a.get_array()._pointer + 12 * itemsize + assert cupy.byte_bounds(a) == (a_low, a_high) + + +def test_2d_contiguous(): + a = cupy.zeros((4, 7), dtype=cupy.int64) + itemsize = a.itemsize + a_low = a.get_array()._pointer + a_high = a.get_array()._pointer + 4 * 7 * itemsize + assert cupy.byte_bounds(a) == (a_low, a_high) + + +def test_1d_noncontiguous_pos_stride(): + a = cupy.zeros(12, dtype=cupy.int64) + itemsize = a.itemsize + b = a[::2] + b_low = b.get_array()._pointer + b_high = b.get_array()._pointer + 11 * itemsize # a[10] + assert cupy.byte_bounds(b) == (b_low, b_high) + + +def test_2d_noncontiguous_pos_stride(): + a = cupy.zeros((4, 7), dtype=cupy.int64) + b = a[::2, ::2] + itemsize = b.itemsize + b_low = a.get_array()._pointer + b_high = b.get_array()._pointer + 3 * 7 * itemsize # a[2][6] + assert cupy.byte_bounds(b) == (b_low, b_high) + + +def test_1d_contiguous_neg_stride(): + a = cupy.zeros(12, dtype=cupy.int64) + b = a[::-1] + itemsize = b.itemsize + b_low = b.get_array()._pointer - 11 * itemsize + b_high = b.get_array()._pointer + 1 * itemsize + assert cupy.byte_bounds(b) == (b_low, b_high) + + +def test_2d_noncontiguous_neg_stride(): + a = cupy.zeros((4, 7), dtype=cupy.int64) + b = a[::-2, ::-2] # strides = (-56, -8), shape = (2, 4) + itemsize = b.itemsize + b_low = ( + b.get_array()._pointer + - 2 * 7 * itemsize * (2 - 1) + - 2 * itemsize * (4 - 1) + ) + b_high = b.get_array()._pointer + 1 * itemsize + assert cupy.byte_bounds(b) == (b_low, b_high) + + +def test_2d_noncontiguous_posneg_stride_1(): + a = cupy.zeros((4, 7), dtype=cupy.int64) + b = a[::1, ::-1] # strides = (28, -4), shape=(4, 7) + itemsize = b.itemsize + b_low = b.get_array()._pointer - itemsize * (7 - 1) + b_high = b.get_array()._pointer + 1 * itemsize + 7 * itemsize * (4 - 1) + assert cupy.byte_bounds(b) == (b_low, b_high) + + +def test_2d_noncontiguous_posneg_stride_2(): + a = cupy.zeros((4, 7), dtype=cupy.int64) + b = a[::2, ::-2] # strides = (56, -8), shape=(2, 4) + itemsize = b.itemsize + b_low = b.get_array()._pointer - 2 * itemsize * (4 - 1) + b_high = b.get_array()._pointer + 1 * itemsize + 2 * 7 * itemsize * (2 - 1) + assert cupy.byte_bounds(b) == (b_low, b_high) From d80d13a3006107cefeafd7fa90b4481abb88c8ce Mon Sep 17 00:00:00 2001 From: Evseniia Komarova <70146207+ekomarova@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:41:02 +0100 Subject: [PATCH 2/2] Update func description to render the doc correctly --- dpnp/dpnp_iface_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dpnp/dpnp_iface_utils.py b/dpnp/dpnp_iface_utils.py index 9bb3051ac955..41eaf3fa2650 100644 --- a/dpnp/dpnp_iface_utils.py +++ b/dpnp/dpnp_iface_utils.py @@ -42,8 +42,7 @@ def byte_bounds(a): """ Returns a 2-tuple with pointers to the end-points of the array. - For full documentation refer to - :obj:`numpy.lib.array_utils.byte_bounds`. + For full documentation refer to :obj:`numpy.lib.array_utils.byte_bounds`. Parameters ----------