From 440fe6a3fd0f54a53679e2e2ae3fd9b30110d216 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Wed, 1 Nov 2023 22:35:36 -0500 Subject: [PATCH 1/4] Leverage dpctl.tensor.repeat() implementation --- dpnp/backend/include/dpnp_iface_fptr.hpp | 4 - .../kernels/dpnp_krnl_manipulation.cpp | 18 --- dpnp/dpnp_algo/CMakeLists.txt | 1 - dpnp/dpnp_algo/dpnp_algo.pxd | 12 -- dpnp/dpnp_algo/dpnp_algo.pyx | 49 -------- dpnp/dpnp_algo/dpnp_algo_manipulation.pxi | 80 ------------- dpnp/dpnp_array.py | 73 +++++++++++- dpnp/dpnp_iface_manipulation.py | 98 ++++++++++------ dpnp/linalg/dpnp_algo_linalg.pyx | 6 +- tests/skipped_tests.tbl | 9 -- tests/skipped_tests_gpu.tbl | 10 -- tests/test_arraymanipulation.py | 111 ++++++++++++++++++ tests/test_dparray.py | 13 ++ .../cupy/manipulation_tests/test_shape.py | 11 +- 14 files changed, 267 insertions(+), 228 deletions(-) delete mode 100644 dpnp/dpnp_algo/dpnp_algo_manipulation.pxi diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 3df04000413..311e6597250 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -178,8 +178,6 @@ enum class DPNPFuncName : size_t DPNP_FN_FILL_DIAGONAL_EXT, /**< Used in numpy.fill_diagonal() impl, requires extra parameters */ DPNP_FN_FLATTEN, /**< Used in numpy.flatten() impl */ - DPNP_FN_FLATTEN_EXT, /**< Used in numpy.flatten() impl, requires extra - parameters */ DPNP_FN_FLOOR, /**< Used in numpy.floor() impl */ DPNP_FN_FLOOR_DIVIDE, /**< Used in numpy.floor_divide() impl */ DPNP_FN_FLOOR_DIVIDE_EXT, /**< Used in numpy.floor_divide() impl, requires @@ -265,8 +263,6 @@ enum class DPNPFuncName : size_t DPNP_FN_RECIP_EXT, /**< Used in numpy.recip() impl, requires extra parameters */ DPNP_FN_REPEAT, /**< Used in numpy.repeat() impl */ - DPNP_FN_REPEAT_EXT, /**< Used in numpy.repeat() impl, requires extra - parameters */ DPNP_FN_RIGHT_SHIFT, /**< Used in numpy.right_shift() impl */ DPNP_FN_RNG_BETA, /**< Used in numpy.random.beta() impl */ DPNP_FN_RNG_BETA_EXT, /**< Used in numpy.random.beta() impl, requires extra diff --git a/dpnp/backend/kernels/dpnp_krnl_manipulation.cpp b/dpnp/backend/kernels/dpnp_krnl_manipulation.cpp index 12e275e90b9..315e1c211f9 100644 --- a/dpnp/backend/kernels/dpnp_krnl_manipulation.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_manipulation.cpp @@ -103,15 +103,6 @@ void (*dpnp_repeat_default_c)(const void *, const size_t, const size_t) = dpnp_repeat_c<_DataType>; -template -DPCTLSyclEventRef (*dpnp_repeat_ext_c)(DPCTLSyclQueueRef, - const void *, - void *, - const size_t, - const size_t, - const DPCTLEventVectorRef) = - dpnp_repeat_c<_DataType>; - template class dpnp_elemwise_transpose_c_kernel; @@ -232,15 +223,6 @@ void func_map_init_manipulation(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_REPEAT][eft_DBL][eft_DBL] = { eft_DBL, (void *)dpnp_repeat_default_c}; - fmap[DPNPFuncName::DPNP_FN_REPEAT_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_repeat_ext_c}; - fmap[DPNPFuncName::DPNP_FN_REPEAT_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_repeat_ext_c}; - fmap[DPNPFuncName::DPNP_FN_REPEAT_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_repeat_ext_c}; - fmap[DPNPFuncName::DPNP_FN_REPEAT_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_repeat_ext_c}; - fmap[DPNPFuncName::DPNP_FN_TRANSPOSE][eft_INT][eft_INT] = { eft_INT, (void *)dpnp_elemwise_transpose_default_c}; fmap[DPNPFuncName::DPNP_FN_TRANSPOSE][eft_LNG][eft_LNG] = { diff --git a/dpnp/dpnp_algo/CMakeLists.txt b/dpnp/dpnp_algo/CMakeLists.txt index 8aa419220de..ad91b4babf9 100644 --- a/dpnp/dpnp_algo/CMakeLists.txt +++ b/dpnp/dpnp_algo/CMakeLists.txt @@ -1,7 +1,6 @@ set(dpnp_algo_pyx_deps ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_linearalgebra.pxi - ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_manipulation.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_counting.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_statistics.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_trigonometric.pxi diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index da6aef0ccd9..065d3502daf 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -94,8 +94,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_FFT_RFFT_EXT DPNP_FN_FILL_DIAGONAL DPNP_FN_FILL_DIAGONAL_EXT - DPNP_FN_FLATTEN - DPNP_FN_FLATTEN_EXT DPNP_FN_FMOD DPNP_FN_FMOD_EXT DPNP_FN_FULL @@ -138,8 +136,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_RADIANS_EXT DPNP_FN_RECIP DPNP_FN_RECIP_EXT - DPNP_FN_REPEAT - DPNP_FN_REPEAT_EXT DPNP_FN_RNG_BETA DPNP_FN_RNG_BETA_EXT DPNP_FN_RNG_BINOMIAL @@ -331,8 +327,6 @@ ctypedef c_dpctl.DPCTLSyclEventRef(*dpnp_reduction_c_t)(c_dpctl.DPCTLSyclQueueRe const long*, const c_dpctl.DPCTLEventVectorRef) -cpdef dpnp_descriptor dpnp_flatten(dpnp_descriptor x1) - """ Internal functions @@ -367,12 +361,6 @@ cpdef dpnp_descriptor dpnp_fmax(dpnp_descriptor x1_obj, dpnp_descriptor x2_obj, dpnp_descriptor out=*, object where=*) cpdef dpnp_descriptor dpnp_fmin(dpnp_descriptor x1_obj, dpnp_descriptor x2_obj, object dtype=*, dpnp_descriptor out=*, object where=*) -""" -Array manipulation routines -""" -cpdef dpnp_descriptor dpnp_repeat(dpnp_descriptor array1, repeats, axes=*) - - """ Statistics functions """ diff --git a/dpnp/dpnp_algo/dpnp_algo.pyx b/dpnp/dpnp_algo/dpnp_algo.pyx index 2d3be5f88a0..5138e72ee83 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pyx +++ b/dpnp/dpnp_algo/dpnp_algo.pyx @@ -54,7 +54,6 @@ import operator import numpy __all__ = [ - "dpnp_flatten", "dpnp_queue_initialize", ] @@ -64,7 +63,6 @@ include "dpnp_algo_counting.pxi" include "dpnp_algo_indexing.pxi" include "dpnp_algo_linearalgebra.pxi" include "dpnp_algo_logic.pxi" -include "dpnp_algo_manipulation.pxi" include "dpnp_algo_mathematical.pxi" include "dpnp_algo_searching.pxi" include "dpnp_algo_sorting.pxi" @@ -82,53 +80,6 @@ ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_dpnp_flatten_t)(c_dpctl.DPCTLSyclQueueR const c_dpctl.DPCTLEventVectorRef) -cpdef utils.dpnp_descriptor dpnp_flatten(utils.dpnp_descriptor x1): - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(x1.dtype) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_FLATTEN_EXT, param1_type, param1_type) - - cdef shape_type_c x1_shape = x1.shape - cdef shape_type_c x1_strides = utils.strides_to_vector(x1.strides, x1_shape) - - x1_obj = x1.get_array() - - # create result array with type given by FPTR data - cdef shape_type_c result_shape = (x1.size,) - cdef utils.dpnp_descriptor result = utils.create_output_descriptor(result_shape, - kernel_data.return_type, - None, - device=x1_obj.sycl_device, - usm_type=x1_obj.usm_type, - sycl_queue=x1_obj.sycl_queue) - - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef shape_type_c result_strides = utils.strides_to_vector(result.strides, result_shape) - - cdef fptr_dpnp_flatten_t func = kernel_data.ptr - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - result.get_data(), - result.size, - result.ndim, - result_shape.data(), - result_strides.data(), - x1.get_data(), - x1.size, - x1.ndim, - x1_shape.data(), - x1_strides.data(), - NULL, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result - - cpdef dpnp_queue_initialize(): """ Initialize SYCL queue which will be used for any library operations. diff --git a/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi b/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi deleted file mode 100644 index 7a517ac261f..00000000000 --- a/dpnp/dpnp_algo/dpnp_algo_manipulation.pxi +++ /dev/null @@ -1,80 +0,0 @@ -# cython: language_level=3 -# cython: linetrace=True -# -*- coding: utf-8 -*- -# ***************************************************************************** -# Copyright (c) 2016-2023, 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. -# ***************************************************************************** - -"""Module Backend (Array manipulation routines) - -This module contains interface functions between C backend layer -and the rest of the library - -""" - -# NO IMPORTs here. All imports must be placed into main "dpnp_algo.pyx" file - -__all__ += [ - "dpnp_repeat", -] - - -# C function pointer to the C library template functions -ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_dpnp_repeat_t)(c_dpctl.DPCTLSyclQueueRef, - const void *, void * , const size_t , const size_t, - const c_dpctl.DPCTLEventVectorRef) - - -cpdef utils.dpnp_descriptor dpnp_repeat(utils.dpnp_descriptor array1, repeats, axes=None): - cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype) - - cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_REPEAT_EXT, param1_type, param1_type) - - array1_obj = array1.get_array() - - # create result array with type given by FPTR data - cdef shape_type_c result_shape = (array1.size * repeats, ) - cdef utils.dpnp_descriptor result = utils.create_output_descriptor(result_shape, - kernel_data.return_type, - None, - device=array1_obj.sycl_device, - usm_type=array1_obj.usm_type, - sycl_queue=array1_obj.sycl_queue) - result_sycl_queue = result.get_array().sycl_queue - - cdef c_dpctl.SyclQueue q = result_sycl_queue - cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref() - - cdef fptr_dpnp_repeat_t func = kernel_data.ptr - cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref, - array1.get_data(), - result.get_data(), - repeats, - array1.size, - NULL) # dep_events_ref - - with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref) - c_dpctl.DPCTLEvent_Delete(event_ref) - - return result diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index ce80de31be5..dd4739c81ef 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -1045,7 +1045,47 @@ def put(self, indices, vals, /, *, axis=None, mode="wrap"): return dpnp.put(self, indices, vals, axis=axis, mode=mode) - # 'ravel', + def ravel(self, order="C"): + """ + Return a contiguous flattened array. + + For full documentation refer to :obj:`numpy.ndarray.ravel`. + + Parameters + ---------- + order : {'C', 'F'}, optional + The elements of a are read using this index order. ``C`` means to index + the elements in row-major, C-style order, with the last axis index + changing fastest, back to the first axis index changing slowest. ``F`` + means to index the elements in column-major, Fortran-style order, with + the first index changing fastest, and the last index changing slowest. + By default, ``C`` index order is used. + + Returns + ------- + y : dpnp_array + `y` is a contiguous 1-D array of the same subtype as a, with shape (a.size,) + + See Also + -------- + :obj:`dpnp.reshape` : Change the shape of an array without changing its data. + + Examples + -------- + >>> import dpnp as np + >>> x = np.array([[1, 2, 3], [4, 5, 6]]) + >>> x.ravel() + array([1, 2, 3, 4, 5, 6]) + + >>> x.reshape(-1) + array([1, 2, 3, 4, 5, 6]) + + >>> x.ravel(order='F') + array([1, 4, 2, 5, 3, 6]) + + """ + + return dpnp.ravel(self, order=order) @property def real(self): @@ -1082,7 +1122,36 @@ def real(self, value): """ dpnp.copyto(self._array_obj.real, value) - # 'repeat', + def repeat(self, repeats, axis=None): + """ + Repeat elements of an array. + + For full documentation refer to :obj:`numpy.ndarray.repeat`. + + Parameters + ---------- + repeat : Union[int, Tuple[int, ...]] + The number of repetitions for each element. + `repeats` is broadcasted to fit the shape of the given axis. + axis : Optional[int] + The axis along which to repeat values. The `axis` is required + if input array has more than one dimension. + + Returns + ------- + out : dpnp_array + Array with repeated elements. + + Examples + -------- + >>> import dpnp as np + >>> x = np.array([3]) + >>> x.repeat(4) + array([3, 3, 3, 3]) + + """ + + return dpnp.repeat(self, repeats, axis=axis) def reshape(self, *sh, **kwargs): """ diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 3c2e18a5d4c..3759ceb7274 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -969,27 +969,44 @@ def ravel(a, order="C"): For full documentation refer to :obj:`numpy.ravel`. - Limitations - ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. + Parameters + ---------- + x : {dpnp_array, usm_ndarray} + Input array. The elements in a are read in the order specified by order, + and packed as a 1-D array. + order : {'C', 'F'}, optional + The elements of a are read using this index order. ``C`` means to index + the elements in row-major, C-style order, with the last axis index + changing fastest, back to the first axis index changing slowest. ``F`` + means to index the elements in column-major, Fortran-style order, with + the first index changing fastest, and the last index changing slowest. + By default, ``C`` index order is used. + + Returns + ------- + y : dpnp_array + `y` is a contiguous 1-D array of the same subtype as a, with shape (a.size,) + + See Also + -------- + :obj:`dpnp.reshape` : Change the shape of an array without changing its data. Examples -------- >>> import dpnp as np >>> x = np.array([[1, 2, 3], [4, 5, 6]]) - >>> out = np.ravel(x) - >>> [i for i in out] - [1, 2, 3, 4, 5, 6] + >>> np.ravel(x) + array([1, 2, 3, 4, 5, 6]) - """ + >>> x.reshape(-1) + array([1, 2, 3, 4, 5, 6]) - a_desc = dpnp.get_dpnp_descriptor(a, copy_when_nondefault_queue=False) - if a_desc: - return dpnp_flatten(a_desc).get_pyobj() + >>> np.ravel(x, order='F') + array([1, 4, 2, 5, 3, 6]) - return call_origin(numpy.ravel, a, order=order) + """ + + return dpnp.reshape(a, -1, order=order) def repeat(a, repeats, axis=None): @@ -998,39 +1015,44 @@ def repeat(a, repeats, axis=None): For full documentation refer to :obj:`numpy.repeat`. - Limitations - ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Parameter `axis` is supported with value either ``None`` or ``0``. - Dimension of input array are supported to be less than ``2``. - Otherwise the function will be executed sequentially on CPU. - If `repeats` is ``tuple`` or ``list``, should be ``len(repeats) > 1``. - Input array data types are limited by supported DPNP :ref:`Data types`. + Parameters + ---------- + x : {dpnp_array, usm_ndarray} + Input array. + repeat : Union[int, Tuple[int, ...]] + The number of repetitions for each element. + `repeats` is broadcasted to fit the shape of the given axis. + axis : Optional[int] + The axis along which to repeat values. The `axis` is required + if input array has more than one dimension. - .. seealso:: :obj:`numpy.tile` tile an array. + Returns + ------- + out : dpnp_array + Array with repeated elements. + + See Also + -------- + :obj:`dpnp.tile` : Construct an array by repeating A the number of times given by reps. Examples -------- >>> import dpnp as np - >>> x = np.repeat(3, 4) - >>> [i for i in x] - [3, 3, 3, 3] + >>> x = np.array([3]) + >>> np.repeat(x, 4) + array([3, 3, 3, 3]) """ - a_desc = dpnp.get_dpnp_descriptor(a, copy_when_nondefault_queue=False) - if a_desc: - if axis is not None and axis != 0: - pass - elif a_desc.ndim >= 2: - pass - elif not dpnp.isscalar(repeats) and len(repeats) > 1: - pass - else: - repeat_val = repeats if dpnp.isscalar(repeats) else repeats[0] - return dpnp_repeat(a_desc, repeat_val, axis).get_pyobj() - - return call_origin(numpy.repeat, a, repeats, axis) + rep = repeats + if isinstance(repeats, dpnp_array): + rep = dpnp.get_usm_ndarray(repeats) + if axis is None and a.ndim > 1: + usm_arr = dpnp.get_usm_ndarray(a.flatten()) + else: + usm_arr = dpnp.get_usm_ndarray(a) + usm_arr = dpt.repeat(usm_arr, rep, axis=axis) + return dpnp_array._create_from_usm_ndarray(usm_arr) def reshape(a, /, newshape, order="C", copy=None): diff --git a/dpnp/linalg/dpnp_algo_linalg.pyx b/dpnp/linalg/dpnp_algo_linalg.pyx index 31eff554dc2..c86b869acd3 100644 --- a/dpnp/linalg/dpnp_algo_linalg.pyx +++ b/dpnp/linalg/dpnp_algo_linalg.pyx @@ -118,7 +118,8 @@ cpdef utils.dpnp_descriptor dpnp_cholesky(utils.dpnp_descriptor input_): cpdef object dpnp_cond(object input, object p): if p in ('f', 'fro'): - input = dpnp.ravel(input, order='K') + # TODO: change order='K' when support is implemented + input = dpnp.ravel(input, order='C') sqnorm = dpnp.dot(input, input) res = dpnp.sqrt(sqnorm) ret = dpnp.array([res]) @@ -368,7 +369,8 @@ cpdef object dpnp_norm(object input, ord=None, axis=None): (ord in ('f', 'fro') and ndim == 2) or (ord == 2 and ndim == 1)): - input = dpnp.ravel(input, order='K') + # TODO: change order='K' when support is implemented + input = dpnp.ravel(input, order='C') sqnorm = dpnp.dot(input, input) ret = dpnp.sqrt([sqnorm], dtype=res_type) return dpnp.array(ret.reshape(1, *ret.shape), dtype=res_type) diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index c1b4fcb37c9..55c67b94d83 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -424,15 +424,6 @@ tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_par tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_param_2_{shapes=[(3, 2), (3, 4)]}::test_invalid_broadcast tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_param_3_{shapes=[(0,), (2,)]}::test_invalid_broadcast -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_ravel2 -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_ravel3 -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_external_ravel -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_ravel -tests/third_party/cupy/manipulation_tests/test_shape.py::TestReshape::test_reshape_zerosize -tests/third_party/cupy/manipulation_tests/test_shape.py::TestReshape::test_reshape_zerosize2 - -tests/third_party/cupy/manipulation_tests/test_tiling.py::TestRepeatRepeatsNdarray::test_func -tests/third_party/cupy/manipulation_tests/test_tiling.py::TestRepeatRepeatsNdarray::test_method tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary2_param_457_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), dtype=float64, name='fmod', use_dtype=False}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary2_param_465_{arg1=array([[1, 2, 3], [4, 5, 6]], dtype=int32), arg2=array([[0, 1, 2], [3, 4, 5]]), dtype=float64, name='fmod', use_dtype=False}::test_binary tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticBinary2_param_537_{arg1=array([[1, 2, 3], [4, 5, 6]]), arg2=array([[0, 1, 2], [3, 4, 5]], dtype=int32), dtype=float64, name='fmod', use_dtype=False}::test_binary diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index e1be1a64647..538ad05743a 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -565,16 +565,6 @@ tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_par tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_param_2_{shapes=[(3, 2), (3, 4)]}::test_invalid_broadcast tests/third_party/cupy/manipulation_tests/test_dims.py::TestInvalidBroadcast_param_3_{shapes=[(0,), (2,)]}::test_invalid_broadcast -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_ravel2 -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_ravel3 -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_external_ravel -tests/third_party/cupy/manipulation_tests/test_shape.py::TestRavel::test_ravel -tests/third_party/cupy/manipulation_tests/test_shape.py::TestReshape::test_reshape_zerosize -tests/third_party/cupy/manipulation_tests/test_shape.py::TestReshape::test_reshape_zerosize2 - -tests/third_party/cupy/manipulation_tests/test_tiling.py::TestRepeatRepeatsNdarray::test_func -tests/third_party/cupy/manipulation_tests/test_tiling.py::TestRepeatRepeatsNdarray::test_method - tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticRaisesWithNumpyInput_param_3_{name='angle', nargs=1}::test_raises_with_numpy_input tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2 diff --git a/tests/test_arraymanipulation.py b/tests/test_arraymanipulation.py index bf61634e52c..74409f54c26 100644 --- a/tests/test_arraymanipulation.py +++ b/tests/test_arraymanipulation.py @@ -939,3 +939,114 @@ def test_can_cast(): assert dpnp.can_cast(X, "float32") == numpy.can_cast(X_np, "float32") assert dpnp.can_cast(X, dpnp.int32) == numpy.can_cast(X_np, numpy.int32) assert dpnp.can_cast(X, dpnp.int64) == numpy.can_cast(X_np, numpy.int64) + + +def test_repeat_scalar_sequence_agreement(): + x = dpnp.arange(5, dtype="i4") + expected_res = dpnp.empty(10, dtype="i4") + expected_res[1::2], expected_res[::2] = x, x + + # scalar case + reps = 2 + res = dpnp.repeat(x, reps) + assert dpnp.all(res == expected_res) + + # tuple + reps = (2, 2, 2, 2, 2) + res = dpnp.repeat(x, reps) + assert dpnp.all(res == expected_res) + + +def test_repeat_as_broadcasting(): + reps = 5 + x = dpnp.arange(reps, dtype="i4") + x1 = x[:, dpnp.newaxis] + expected_res = dpnp.broadcast_to(x1, (reps, reps)) + + res = dpnp.repeat(x1, reps, axis=1) + assert dpnp.all(res == expected_res) + + x2 = x[dpnp.newaxis, :] + expected_res = dpnp.broadcast_to(x2, (reps, reps)) + + res = dpnp.repeat(x2, reps, axis=0) + assert dpnp.all(res == expected_res) + + +def test_repeat_axes(): + reps = 2 + x = dpnp.reshape(dpnp.arange(5 * 10, dtype="i4"), (5, 10)) + expected_res = dpnp.empty((x.shape[0] * 2, x.shape[1]), dtype=x.dtype) + expected_res[::2, :], expected_res[1::2] = x, x + res = dpnp.repeat(x, reps, axis=0) + assert dpnp.all(res == expected_res) + + expected_res = dpnp.empty((x.shape[0], x.shape[1] * 2), dtype=x.dtype) + expected_res[:, ::2], expected_res[:, 1::2] = x, x + res = dpnp.repeat(x, reps, axis=1) + assert dpnp.all(res == expected_res) + + +def test_repeat_size_0_outputs(): + x = dpnp.ones((3, 0, 5), dtype="i4") + reps = 10 + res = dpnp.repeat(x, reps, axis=0) + assert res.size == 0 + assert res.shape == (30, 0, 5) + + res = dpnp.repeat(x, reps, axis=1) + assert res.size == 0 + assert res.shape == (3, 0, 5) + + res = dpnp.repeat(x, (2, 2, 2), axis=0) + assert res.size == 0 + assert res.shape == (6, 0, 5) + + x = dpnp.ones((3, 2, 5)) + res = dpnp.repeat(x, 0, axis=1) + assert res.size == 0 + assert res.shape == (3, 0, 5) + + x = dpnp.ones((3, 2, 5)) + res = dpnp.repeat(x, (0, 0), axis=1) + assert res.size == 0 + assert res.shape == (3, 0, 5) + + +def test_repeat_strides(): + reps = 2 + x = dpnp.reshape(dpnp.arange(10 * 10, dtype="i4"), (10, 10)) + x1 = x[:, ::-2] + expected_res = dpnp.empty((10, 10), dtype="i4") + expected_res[:, ::2], expected_res[:, 1::2] = x1, x1 + res = dpnp.repeat(x1, reps, axis=1) + assert dpnp.all(res == expected_res) + res = dpnp.repeat(x1, (reps,) * x1.shape[1], axis=1) + assert dpnp.all(res == expected_res) + + x1 = x[::-2, :] + expected_res = dpnp.empty((10, 10), dtype="i4") + expected_res[::2, :], expected_res[1::2, :] = x1, x1 + res = dpnp.repeat(x1, reps, axis=0) + assert dpnp.all(res == expected_res) + res = dpnp.repeat(x1, (reps,) * x1.shape[0], axis=0) + assert dpnp.all(res == expected_res) + + +def test_repeat_casting(): + x = dpnp.arange(5, dtype="i4") + # i4 is cast to i8 + reps = dpnp.ones(5, dtype="i4") + res = dpnp.repeat(x, reps) + assert res.shape == x.shape + assert dpnp.all(res == x) + + +def test_repeat_strided_repeats(): + x = dpnp.arange(5, dtype="i4") + reps = dpnp.ones(10, dtype="i8") + reps[::2] = 0 + reps = reps[::-2] + res = dpnp.repeat(x, reps) + assert res.shape == x.shape + assert dpnp.all(res == x) diff --git a/tests/test_dparray.py b/tests/test_dparray.py index e3f4e80a4cb..3c57d44bf91 100644 --- a/tests/test_dparray.py +++ b/tests/test_dparray.py @@ -233,3 +233,16 @@ def test_array_as_index(shape, index_dtype): ind_arr = dpnp.ones(shape, dtype=index_dtype) a = numpy.arange(ind_arr.size + 1) assert a[tuple(ind_arr)] == a[1] + + +def test_ravel(): + a = dpnp.ones((2, 2)) + b = a.ravel() + a[0, 0] = 5 + assert_array_equal(a.ravel(), b) + + +def test_repeat(): + numpy_array = numpy.arange(4).repeat(3) + dpnp_array = dpnp.arange(4).repeat(3) + assert_array_equal(numpy_array, dpnp_array) diff --git a/tests/third_party/cupy/manipulation_tests/test_shape.py b/tests/third_party/cupy/manipulation_tests/test_shape.py index 37e29ae3a36..9b672b97553 100644 --- a/tests/third_party/cupy/manipulation_tests/test_shape.py +++ b/tests/third_party/cupy/manipulation_tests/test_shape.py @@ -108,6 +108,7 @@ def test_reshape_zerosize_invalid_unknown(self): with pytest.raises(ValueError): a.reshape((-1, 0)) + @pytest.mark.skip("array.base is not implemented") @testing.numpy_cupy_array_equal() def test_reshape_zerosize(self, xp): a = xp.zeros((0,)) @@ -115,6 +116,7 @@ def test_reshape_zerosize(self, xp): assert b.base is a return b + @pytest.mark.skip("array.base is not implemented") @testing.for_orders(_supported_orders) @testing.numpy_cupy_array_equal(strides_check=True) def test_reshape_zerosize2(self, xp, order): @@ -157,20 +159,23 @@ def test_ndim_limit2(self, dtype, order): @testing.gpu class TestRavel(unittest.TestCase): - @testing.for_orders("CFA") + @testing.for_orders("CF") + # order = 'A' is out of support currently @testing.numpy_cupy_array_equal() def test_ravel(self, xp, order): a = testing.shaped_arange((2, 3, 4), xp) a = a.transpose(2, 0, 1) return a.ravel(order) - @testing.for_orders("CFA") + @testing.for_orders("CF") + # order = 'A' is out of support currently @testing.numpy_cupy_array_equal() def test_ravel2(self, xp, order): a = testing.shaped_arange((2, 3, 4), xp) return a.ravel(order) - @testing.for_orders("CFA") + @testing.for_orders("CF") + # order = 'A' is out of support currently @testing.numpy_cupy_array_equal() def test_ravel3(self, xp, order): a = testing.shaped_arange((2, 3, 4), xp) From 3c2d3300c3f714b34dacfeb739c8c2c7d6f933f8 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Fri, 3 Nov 2023 10:46:25 -0500 Subject: [PATCH 2/4] clean up flatten function --- dpnp/backend/kernels/dpnp_krnl_elemwise.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp index 5b0b9b04753..ec11be0db1d 100644 --- a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp @@ -940,19 +940,6 @@ static void func_map_init_elemwise_1arg_1type(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_FLATTEN][eft_C128][eft_C128] = { eft_C128, (void *)dpnp_copy_c_default>}; - fmap[DPNPFuncName::DPNP_FN_FLATTEN_EXT][eft_BLN][eft_BLN] = { - eft_BLN, (void *)dpnp_copy_c_ext}; - fmap[DPNPFuncName::DPNP_FN_FLATTEN_EXT][eft_INT][eft_INT] = { - eft_INT, (void *)dpnp_copy_c_ext}; - fmap[DPNPFuncName::DPNP_FN_FLATTEN_EXT][eft_LNG][eft_LNG] = { - eft_LNG, (void *)dpnp_copy_c_ext}; - fmap[DPNPFuncName::DPNP_FN_FLATTEN_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_copy_c_ext}; - fmap[DPNPFuncName::DPNP_FN_FLATTEN_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_copy_c_ext}; - fmap[DPNPFuncName::DPNP_FN_FLATTEN_EXT][eft_C128][eft_C128] = { - eft_C128, (void *)dpnp_copy_c_ext>}; - fmap[DPNPFuncName::DPNP_FN_NEGATIVE][eft_INT][eft_INT] = { eft_INT, (void *)dpnp_negative_c_default}; fmap[DPNPFuncName::DPNP_FN_NEGATIVE][eft_LNG][eft_LNG] = { From 237a5f15388502050e070cbde2acff8da94c1d19 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Wed, 15 Nov 2023 17:17:25 -0600 Subject: [PATCH 3/4] address comments --- dpnp/dpnp_array.py | 57 ++------------------------------- dpnp/dpnp_iface_manipulation.py | 33 ++++++++++++------- 2 files changed, 24 insertions(+), 66 deletions(-) diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index e9f19593301..f6bd27a99a2 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -1054,39 +1054,7 @@ def ravel(self, order="C"): """ Return a contiguous flattened array. - For full documentation refer to :obj:`numpy.ndarray.ravel`. - - Parameters - ---------- - order : {'C', 'F'}, optional - The elements of a are read using this index order. ``C`` means to index - the elements in row-major, C-style order, with the last axis index - changing fastest, back to the first axis index changing slowest. ``F`` - means to index the elements in column-major, Fortran-style order, with - the first index changing fastest, and the last index changing slowest. - By default, ``C`` index order is used. - - Returns - ------- - y : dpnp_array - `y` is a contiguous 1-D array of the same subtype as a, with shape (a.size,) - - See Also - -------- - :obj:`dpnp.reshape` : Change the shape of an array without changing its data. - - Examples - -------- - >>> import dpnp as np - >>> x = np.array([[1, 2, 3], [4, 5, 6]]) - >>> x.ravel() - array([1, 2, 3, 4, 5, 6]) - - >>> x.reshape(-1) - array([1, 2, 3, 4, 5, 6]) - - >>> x.ravel(order='F') - array([1, 4, 2, 5, 3, 6]) + For full documentation refer to :obj:`dpnp.ravel`. """ @@ -1131,28 +1099,7 @@ def repeat(self, repeats, axis=None): """ Repeat elements of an array. - For full documentation refer to :obj:`numpy.ndarray.repeat`. - - Parameters - ---------- - repeat : Union[int, Tuple[int, ...]] - The number of repetitions for each element. - `repeats` is broadcasted to fit the shape of the given axis. - axis : Optional[int] - The axis along which to repeat values. The `axis` is required - if input array has more than one dimension. - - Returns - ------- - out : dpnp_array - Array with repeated elements. - - Examples - -------- - >>> import dpnp as np - >>> x = np.array([3]) - >>> x.repeat(4) - array([3, 3, 3, 3]) + For full documentation refer to :obj:`dpnp.repeat`. """ diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 49e9e8731a1..6941af2829e 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -979,10 +979,10 @@ def ravel(a, order="C"): Parameters ---------- x : {dpnp_array, usm_ndarray} - Input array. The elements in a are read in the order specified by order, + Input array. The elements in `a` are read in the order specified by order, and packed as a 1-D array. order : {'C', 'F'}, optional - The elements of a are read using this index order. ``C`` means to index + The elements of `a` are read using this index order. ``C`` means to index the elements in row-major, C-style order, with the last axis index changing fastest, back to the first axis index changing slowest. ``F`` means to index the elements in column-major, Fortran-style order, with @@ -991,8 +991,8 @@ def ravel(a, order="C"): Returns ------- - y : dpnp_array - `y` is a contiguous 1-D array of the same subtype as a, with shape (a.size,) + out : dpnp_array + `out` is a contiguous 1-D array of the same subtype as `a`, with shape (a.size,) See Also -------- @@ -1026,17 +1026,17 @@ def repeat(a, repeats, axis=None): ---------- x : {dpnp_array, usm_ndarray} Input array. - repeat : Union[int, Tuple[int, ...]] - The number of repetitions for each element. - `repeats` is broadcasted to fit the shape of the given axis. - axis : Optional[int] - The axis along which to repeat values. The `axis` is required - if input array has more than one dimension. + repeat : int or array of int + The number of repetitions for each element. `repeats` is broadcasted to fit + the shape of the given axis. + axis : int, optional + The axis along which to repeat values. By default, use the flattened input array, + and return a flat output array. Returns ------- out : dpnp_array - Array with repeated elements. + Output array which has the same shape as `a`, except along the given axis. See Also -------- @@ -1049,6 +1049,17 @@ def repeat(a, repeats, axis=None): >>> np.repeat(x, 4) array([3, 3, 3, 3]) + >>> x = np.array([[1,2], [3,4]]) + >>> np.repeat(x, 2) + array([1, 1, 2, 2, 3, 3, 4, 4]) + >>> np.repeat(x, 3, axis=1) + array([[1, 1, 1, 2, 2, 2], + [3, 3, 3, 4, 4, 4]]) + >>> np.repeat(x, [1, 2], axis=0) + array([[1, 2], + [3, 4], + [3, 4]]) + """ rep = repeats From b81bfb98bdfab2a0d57011358512a9d0e8da5f7a Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Wed, 15 Nov 2023 20:56:14 -0800 Subject: [PATCH 4/4] muted tests for diagflat for scalars --- tests/third_party/cupy/creation_tests/test_matrix.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/third_party/cupy/creation_tests/test_matrix.py b/tests/third_party/cupy/creation_tests/test_matrix.py index e51a33c8c03..7123989d7c5 100644 --- a/tests/third_party/cupy/creation_tests/test_matrix.py +++ b/tests/third_party/cupy/creation_tests/test_matrix.py @@ -92,17 +92,17 @@ def test_diagflat3(self, xp): a = testing.shaped_arange((3, 3), xp) return xp.diagflat(a, -2) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") + @pytest.mark.skip("Scalar input is not supported") @testing.numpy_cupy_array_equal() def test_diagflat_from_scalar(self, xp): return xp.diagflat(3) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") + @pytest.mark.skip("Scalar input is not supported") @testing.numpy_cupy_array_equal() def test_diagflat_from_scalar_with_k0(self, xp): return xp.diagflat(3, 0) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") + @pytest.mark.skip("Scalar input is not supported") @testing.numpy_cupy_array_equal() def test_diagflat_from_scalar_with_k1(self, xp): return xp.diagflat(3, 1)