From e52683387b6576c15db4ce7371a7de70dbd69a2f Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 20 Dec 2023 13:08:35 +0100 Subject: [PATCH 1/9] Implemented column_stack, dstack and row_stack --- dpnp/dpnp_iface_manipulation.py | 118 ++++++++++++++++++ .../cupy/manipulation_tests/test_join.py | 29 ++--- 2 files changed, 125 insertions(+), 22 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 7ee53bca3775..90fd5d169ef5 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -57,8 +57,10 @@ "broadcast_arrays", "broadcast_to", "can_cast", + "column_stack", "concatenate", "copyto", + "dstack", "expand_dims", "flip", "fliplr", @@ -71,6 +73,7 @@ "result_type", "roll", "rollaxis", + "row_stack", "shape", "squeeze", "stack", @@ -444,6 +447,61 @@ def can_cast(from_, to, casting="safe"): return dpt.can_cast(dtype_from, to, casting) +def column_stack(tup): + """ + Stacks 1-D and 2-D arrays as columns into a 2-D array. + + Take a sequence of 1-D arrays and stack them as columns to make a single + 2-D array. 2-D arrays are stacked as-is, just like with :obj:`dpnp.hstack`. + 1-D arrays are turned into 2-D columns first. + + For full documentation refer to :obj:`numpy.column_stack`. + + Parameters + ---------- + tup : {dpnp.ndarray, usm_ndarray} + A sequence of 1-D or 2-D arrays to stack. All of them must have + the same first dimension. + + Returns + ------- + out : dpnp.ndarray + The array formed by stacking the given arrays. + + See Also + -------- + :obj:`dpnp.stack` : Stack a sequence of arrays along a new axis. + :obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise). + :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). + :obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis. + + Examples + -------- + >>> import dpnp as np + >>> a = np.array((1, 2, 3)) + >>> b = np.array((2, 3, 4)) + >>> np.column_stack((a, b)) + array([[1, 2], + [2, 3], + [3, 4]]) + + """ + + arrays = [] + for v in tup: + dpnp.check_supported_arrays_type(v) + + if v.ndim == 1: + v = v[:, dpnp.newaxis] + elif v.ndim != 2: + raise ValueError( + "Only 1 or 2 dimensional arrays can be column stacked" + ) + + arrays.append(v) + return dpnp.concatenate(arrays, 1) + + def concatenate( arrays, /, *, axis=0, out=None, dtype=None, casting="same_kind" ): @@ -601,6 +659,63 @@ def copyto(dst, src, casting="same_kind", where=True): dst_usm[mask_usm] = src_usm[mask_usm] +def dstack(tup): + """ + Stack arrays in sequence depth wise (along third axis). + + This is equivalent to concatenation along the third axis after 2-D arrays + of shape `(M, N)` have been reshaped to `(M, N, 1)` and 1-D arrays of shape + `(N,)` have been reshaped to `(1, N, 1)`. Rebuilds arrays divided by + `dsplit`. + + For full documentation refer to :obj:`numpy.dstack`. + + Parameters + ---------- + tup : {dpnp.ndarray, usm_ndarray} + One or more array-like sequences. The arrays must have the same shape + along all but the third axis. 1-D or 2-D arrays must have the same shape. + + Returns + ------- + out : dpnp.ndarray + The array formed by stacking the given arrays, will be at least 3-D. + + See Also + -------- + :obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis. + :obj:`dpnp.stack` : Join a sequence of arrays along a new axis. + :obj:`dpnp.block` : Assemble an nd-array from nested lists of blocks. + :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). + :obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise). + :obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array. + :obj:`dpnp.dsplit` : Split array along third axis. + + Examples + -------- + >>> import dpnp as np + >>> a = np.array((1, 2, 3)) + >>> b = np.array((2, 3, 4)) + >>> np.dstack((a, b)) + array([[[1, 2], + [2, 3], + [3, 4]]]) + + >>> a = np.array([[1], [2], [3]]) + >>> b = np.array([[2], [3], [4]]) + >>> np.dstack((a, b)) + array([[[1, 2]], + [[2, 3]], + [[3, 4]]]) + + """ + + arrs = atleast_3d(*tup) + if not isinstance(arrs, list): + arrs = [arrs] + return dpnp.concatenate(arrs, axis=2) + + def expand_dims(a, axis): """ Expand the shape of an array. @@ -1738,3 +1853,6 @@ def vstack(tup, *, dtype=None, casting="same_kind"): if not isinstance(arrs, list): arrs = [arrs] return dpnp.concatenate(arrs, axis=0, dtype=dtype, casting=casting) + + +row_stack = vstack diff --git a/tests/third_party/cupy/manipulation_tests/test_join.py b/tests/third_party/cupy/manipulation_tests/test_join.py index 6f8eb33fa27d..105ccece4841 100644 --- a/tests/third_party/cupy/manipulation_tests/test_join.py +++ b/tests/third_party/cupy/manipulation_tests/test_join.py @@ -1,14 +1,12 @@ -import unittest - import numpy import pytest import dpnp as cupy +from tests.helper import has_support_aspect64 from tests.third_party.cupy import testing -class TestJoin(unittest.TestCase): - @pytest.mark.skip("dpnp.column_stack() is not implemented yet") +class TestJoin: @testing.for_all_dtypes(name="dtype1") @testing.for_all_dtypes(name="dtype2") @testing.numpy_cupy_array_equal() @@ -18,21 +16,18 @@ def test_column_stack(self, xp, dtype1, dtype2): c = testing.shaped_arange((4, 2), xp, dtype1) return xp.column_stack((a, b, c)) - @pytest.mark.skip("dpnp.column_stack() is not implemented yet") def test_column_stack_wrong_ndim1(self): a = cupy.zeros(()) b = cupy.zeros((3,)) with pytest.raises(ValueError): cupy.column_stack((a, b)) - @pytest.mark.skip("dpnp.column_stack() is not implemented yet") def test_column_stack_wrong_ndim2(self): a = cupy.zeros((3, 2, 3)) b = cupy.zeros((3, 2)) with pytest.raises(ValueError): cupy.column_stack((a, b)) - @pytest.mark.skip("dpnp.column_stack() is not implemented yet") def test_column_stack_wrong_shape(self): a = cupy.zeros((3, 2)) b = cupy.zeros((4, 3)) @@ -87,9 +82,8 @@ def test_concatenate_large_4(self, xp, dtype): b = testing.shaped_reverse_arange((2, 3, 4), xp, dtype) return xp.concatenate((a, b) * 10, axis=-1) - @pytest.mark.skip("TODO: remove once dpctl #1325 is resolved") @testing.for_all_dtypes(name="dtype") - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_array_equal(type_check=has_support_aspect64()) def test_concatenate_large_5(self, xp, dtype): a = testing.shaped_arange((2, 3, 4), xp, dtype) b = testing.shaped_reverse_arange((2, 3, 4), xp, "i") @@ -113,8 +107,7 @@ def test_concatenate_large_f_contiguous(self, xp, dtype): e = testing.shaped_arange((2, 3, 2), xp, dtype) return xp.concatenate((a, b, c, d, e) * 2, axis=-1) - @pytest.mark.skip("TODO: remove once dpctl #1325 is resolved") - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_array_equal(type_check=has_support_aspect64()) def test_concatenate_many_multi_dtype(self, xp): a = testing.shaped_arange((2, 1), xp, "i") b = testing.shaped_arange((2, 1), xp, "f") @@ -191,9 +184,8 @@ def test_concatenate_out_invalid_dtype(self): with pytest.raises(TypeError): xp.concatenate((a, b, c), axis=1, out=out) - @pytest.mark.skip("TODO: remove once dpctl #1325 is resolved") @testing.for_all_dtypes_combination(names=["dtype1", "dtype2"]) - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_array_equal(type_check=has_support_aspect64()) def test_concatenate_different_dtype(self, xp, dtype1, dtype2): a = testing.shaped_arange((3, 4), xp, dtype1) b = testing.shaped_arange((3, 4), xp, dtype2) @@ -235,7 +227,6 @@ def test_concatenate_casting(self, xp, dtype1, dtype2, casting): b = testing.shaped_arange((3, 4), xp, dtype1) return xp.concatenate((a, b), dtype=dtype2, casting=casting) - @pytest.mark.skip("dpnp.dstack() is not implemented yet") @testing.numpy_cupy_array_equal() def test_dstack(self, xp): a = testing.shaped_arange((1, 3, 2), xp) @@ -243,19 +234,16 @@ def test_dstack(self, xp): c = testing.shaped_arange((1, 3), xp) return xp.dstack((a, b, c)) - @pytest.mark.skip("dpnp.dstack() is not implemented yet") @testing.numpy_cupy_array_equal() def test_dstack_single_element(self, xp): a = testing.shaped_arange((1, 2, 3), xp) return xp.dstack((a,)) - @pytest.mark.skip("dpnp.dstack() is not implemented yet") @testing.numpy_cupy_array_equal() def test_dstack_single_element_2(self, xp): a = testing.shaped_arange((1, 2), xp) return xp.dstack((a,)) - @pytest.mark.skip("dpnp.dstack() is not implemented yet") @testing.numpy_cupy_array_equal() def test_dstack_single_element_3(self, xp): a = testing.shaped_arange((1,), xp) @@ -473,33 +461,30 @@ def test_stack_dtype(self, xp, dtype1, dtype2): def test_stack_casting(self, xp, dtype1, dtype2, casting): a = testing.shaped_arange((3, 4), xp, dtype1) b = testing.shaped_arange((3, 4), xp, dtype1) + # may raise TypeError or ComplexWarning return xp.stack((a, b), dtype=dtype2, casting=casting) - @pytest.mark.skip("dpnp.row_stack() is not implemented yet") @testing.for_all_dtypes(name="dtype1") @testing.for_all_dtypes(name="dtype2") - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_array_equal(type_check=has_support_aspect64()) def test_row_stack(self, xp, dtype1, dtype2): a = testing.shaped_arange((4, 3), xp, dtype1) b = testing.shaped_arange((3,), xp, dtype2) c = testing.shaped_arange((2, 3), xp, dtype1) return xp.row_stack((a, b, c)) - @pytest.mark.skip("dpnp.row_stack() is not implemented yet") def test_row_stack_wrong_ndim1(self): a = cupy.zeros(()) b = cupy.zeros((3,)) with pytest.raises(ValueError): cupy.row_stack((a, b)) - @pytest.mark.skip("dpnp.row_stack() is not implemented yet") def test_row_stack_wrong_ndim2(self): a = cupy.zeros((3, 2, 3)) b = cupy.zeros((3, 2)) with pytest.raises(ValueError): cupy.row_stack((a, b)) - @pytest.mark.skip("dpnp.row_stack() is not implemented yet") def test_row_stack_wrong_shape(self): a = cupy.zeros((3, 2)) b = cupy.zeros((4, 3)) From 816da753274495c3f160c358a2f4f89bf291e3bf Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 20 Dec 2023 14:26:10 +0100 Subject: [PATCH 2/9] Updated docstring of all manipulation functions --- dpnp/dpnp_iface_manipulation.py | 398 ++++++++++++++++++++------------ 1 file changed, 244 insertions(+), 154 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 90fd5d169ef5..3536a491cdee 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -91,16 +91,30 @@ def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None): For full documentation refer to :obj:`numpy.asfarray`. - Notes - ----- - If `dtype` is ``None``, :obj:`dpnp.bool` or one of the `int` dtypes, - it is replaced with the default floating type (:obj:`dpnp.float64` - if a device supports it, or :obj:`dpnp.float32` type otherwise). + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + The input array. + dtype : str or dtype object, optional + Float type code to coerce input array `a`. If `dtype` is ``None``, + :obj:`dpnp.bool` or one of the `int` dtypesis it is replaced with + the default floating type (:obj:`dpnp.float64` if a device supports it, + or :obj:`dpnp.float32` type otherwise). + device : {None, string, SyclDevice, SyclQueue}, optional + An array API concept of device where the output array is created. + The `device` can be ``None`` (the default), an OneAPI filter selector + string, an instance of :class:`dpctl.SyclDevice` corresponding to + a non-partitioned SYCL device, an instance of :class:`dpctl.SyclQueue`, + or a `Device` object returned by :obj:`dpnp.ndarray.device` property. + usm_type : {None, "device", "shared", "host"}, optional + The type of SYCL USM allocation for the output array. + sycl_queue : {None, SyclQueue}, optional + A SYCL queue to use for output array allocation and copying. Returns ------- - y : dpnp.ndarray - The input a as a float ndarray. + out : dpnp.ndarray + The input `a` as a float ndarray. Examples -------- @@ -118,7 +132,7 @@ def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None): a, sycl_queue=sycl_queue, device=device ) - if dtype is None or not numpy.issubdtype(dtype, dpnp.inexact): + if dtype is None or not dpnp.issubdtype(dtype, dpnp.inexact): dtype = dpnp.default_float_type(sycl_queue=_sycl_queue) return dpnp.asarray( @@ -320,16 +334,18 @@ def broadcast_arrays(*args, subok=False): For full documentation refer to :obj:`numpy.broadcast_arrays`. + Parameters + ---------- + args : {dpnp.ndarray, usm_ndarray} + A list of arrays to broadcast. + Returns ------- - broadcasted : list of dpnp.ndarray - These arrays are views on the original arrays. + out : {dpnp.ndarray} + A list of arrays which are views on the original arrays from `args`. Limitations ----------- - Parameter `args` is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Otherwise ``TypeError`` exception will be raised. Parameter `subok` is supported with default value. Otherwise ``NotImplementedError`` exception will be raised. @@ -355,12 +371,8 @@ def broadcast_arrays(*args, subok=False): if len(args) == 0: return [] - dpt_arrays = dpt.broadcast_arrays( - *[dpnp.get_usm_ndarray(array) for array in args] - ) - return [ - dpnp_array._create_from_usm_ndarray(usm_arr) for usm_arr in dpt_arrays - ] + usm_arrays = dpt.broadcast_arrays(*[dpnp.get_usm_ndarray(a) for a in args]) + return [dpnp_array._create_from_usm_ndarray(a) for a in usm_arrays] def broadcast_to(array, /, shape, subok=False): @@ -369,19 +381,23 @@ def broadcast_to(array, /, shape, subok=False): For full documentation refer to :obj:`numpy.broadcast_to`. + Parameters + ---------- + array : {dpnp.ndarray, usm_ndarray} + The array to broadcast. + shape : tuple or int + The shape of the desired array. A single integer ``i`` is interpreted + as ``(i,)``. + Returns ------- - y : dpnp.ndarray + out : dpnp.ndarray An array having a specified shape. Must have the same data type as `array`. Limitations ----------- - Parameter `array` is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Otherwise ``TypeError`` exception will be raised. Parameter `subok` is supported with default value. Otherwise ``NotImplementedError`` exception will be raised. - Input array data types of `array` is limited by supported DPNP :ref:`Data types`. See Also -------- @@ -389,9 +405,9 @@ def broadcast_to(array, /, shape, subok=False): Examples -------- - >>> import dpnp as dp - >>> x = dp.array([1, 2, 3]) - >>> dp.broadcast_to(x, (3, 3)) + >>> import dpnp as np + >>> x = np.array([1, 2, 3]) + >>> np.broadcast_to(x, (3, 3)) array([[1, 2, 3], [1, 2, 3], [1, 2, 3]]) @@ -401,8 +417,8 @@ def broadcast_to(array, /, shape, subok=False): if subok is not False: raise NotImplementedError(f"subok={subok} is currently not supported") - dpt_array = dpnp.get_usm_ndarray(array) - new_array = dpt.broadcast_to(dpt_array, shape) + usm_array = dpnp.get_usm_ndarray(array) + new_array = dpt.broadcast_to(usm_array, shape) return dpnp_array._create_from_usm_ndarray(new_array) @@ -410,14 +426,11 @@ def can_cast(from_, to, casting="safe"): """ Returns ``True`` if cast between data types can occur according to the casting rule. - If `from` is a scalar or array scalar, also returns ``True`` if the scalar value can - be cast without overflow or truncation to an integer. - For full documentation refer to :obj:`numpy.can_cast`. Parameters ---------- - from : dpnp.array, dtype + from_ : {dpnp.ndarray, usm_ndarray, dtype, dtype specifier} Source data type. to : dtype Target data type. @@ -427,12 +440,62 @@ def can_cast(from_, to, casting="safe"): Returns ------- out: bool - True if cast can occur according to the casting rule. + ``True`` if cast can occur according to the casting rule, + ``False`` otherwise. See Also -------- - :obj:`dpnp.result_type` : Returns the type that results from applying the NumPy - type promotion rules to the arguments. + :obj:`dpnp.result_type` : Returns the type that results from applying + the NumPy type promotion rules to the arguments. + + Examples + -------- + Basic examples + + >>> import dpnp as np + >>> np.can_cast(np.int32, np.int64) + True + >>> np.can_cast(np.float64, complex) + True + >>> np.can_cast(complex, float) + False + + >>> np.can_cast('i8', 'f8') + True + >>> np.can_cast('i8', 'f4') + False + + Array scalar checks the value, array does not + + >>> np.can_cast(np.array(1000.0), np.float32) + True + >>> np.can_cast(np.array([1000.0]), np.float32) + False + + Using the casting rules + + >>> np.can_cast('i8', 'i8', 'no') + True + >>> np.can_cast('i8', 'no') + False + + >>> np.can_cast('i8', 'equiv') + True + >>> np.can_cast('i8', 'equiv') + False + + >>> np.can_cast('i8', 'safe') + True + >>> np.can_cast('i4', 'safe') + False + + >>> np.can_cast('i4', 'same_kind') + True + >>> np.can_cast('u4', 'same_kind') + False + + >>> np.can_cast('u4', 'unsafe') + True """ @@ -471,6 +534,7 @@ def column_stack(tup): See Also -------- :obj:`dpnp.stack` : Stack a sequence of arrays along a new axis. + :obj:`dpnp.dstack` : Stack arrays in sequence depth wise (along third axis). :obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise). :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). :obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis. @@ -589,14 +653,18 @@ def copyto(dst, src, casting="same_kind", where=True): For full documentation refer to :obj:`numpy.copyto`. - Limitations - ----------- - The `dst` parameter is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - The `where` parameter is supported as either :class:`dpnp.ndarray`, - :class:`dpctl.tensor.usm_ndarray` or scalar. - Otherwise ``TypeError`` exception will be raised. - Input array data types are limited by supported DPNP :ref:`Data types`. + Parameters + ---------- + dst : {dpnp.ndarray, usm_ndarray} + The array into which values are copied. + src : array_like + The array from which values are copied. + casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional + Controls what kind of data casting may occur when copying. + where : {dpnp.ndarray, usm_ndarray, scalar} of bool, optional + A boolean array or a scalar which is broadcasted to match + the dimensions of `dst`, and selects elements to copy + from `src` to `dst` wherever it contains the value ``True``. Examples -------- @@ -684,11 +752,11 @@ def dstack(tup): See Also -------- :obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis. - :obj:`dpnp.stack` : Join a sequence of arrays along a new axis. - :obj:`dpnp.block` : Assemble an nd-array from nested lists of blocks. :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). :obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise). :obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array. + :obj:`dpnp.stack` : Join a sequence of arrays along a new axis. + :obj:`dpnp.block` : Assemble an nd-array from nested lists of blocks. :obj:`dpnp.dsplit` : Split array along third axis. Examples @@ -725,19 +793,19 @@ def expand_dims(a, axis): For full documentation refer to :obj:`numpy.expand_dims`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + axis : int or tuple of ints + Position in the expanded axes where the new axis (or axes) is placed. + Returns ------- out : dpnp.ndarray An array with the number of dimensions increased. A view is returned whenever possible. - Limitations - ----------- - Parameters `a` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. - Notes ----- If `a` has rank (i.e, number of dimensions) `N`, a valid `axis` must reside @@ -798,9 +866,9 @@ def expand_dims(a, axis): """ - dpt_array = dpnp.get_usm_ndarray(a) + usm_array = dpnp.get_usm_ndarray(a) return dpnp_array._create_from_usm_ndarray( - dpt.expand_dims(dpt_array, axis=axis) + dpt.expand_dims(usm_array, axis=axis) ) @@ -812,18 +880,22 @@ def flip(m, axis=None): For full documentation refer to :obj:`numpy.flip`. + Parameters + ---------- + m : {dpnp.ndarray, usm_ndarray} + Input array. + axis : None or int or tuple of ints, optional + Axis or axes along which to flip over. The default, + ``axis=None``, will flip over all of the axes of the input array. + If `axis` is negative it counts from the last to the first axis. + If `axis` is a tuple of ints, flipping is performed on all of the axes + specified in the tuple. + Returns ------- out : dpnp.ndarray A view of `m` with the entries of axis reversed. - Limitations - ----------- - Parameters `m` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. - See Also -------- :obj:`dpnp.flipud` : Flip an array vertically (axis=0). @@ -878,18 +950,16 @@ def fliplr(m): For full documentation refer to :obj:`numpy.fliplr`. + Parameters + ---------- + m : {dpnp.ndarray, usm_ndarray} + Input array, must be at least 2-D. + Returns ------- out : dpnp.ndarray A view of `m` with the columns reversed. - Limitations - ----------- - Parameters `m` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. - See Also -------- :obj:`dpnp.flipud` : Flip an array vertically (axis=0). @@ -930,18 +1000,16 @@ def flipud(m): For full documentation refer to :obj:`numpy.flipud`. + Parameters + ---------- + m : {dpnp.ndarray, usm_ndarray} + Input array. + Returns ------- out : dpnp.ndarray A view of `m` with the rows reversed. - Limitations - ----------- - Parameters `m` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. - See Also -------- :obj:`dpnp.fliplr` : Flip array in the left/right direction. @@ -1002,6 +1070,8 @@ def hstack(tup, *, dtype=None, casting="same_kind"): :obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis. :obj:`dpnp.stack` : Join a sequence of arrays along a new axis. :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). + :obj:`dpnp.dstack` : Stack arrays in sequence depth wise (along third dimension). + :obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array. :obj:`dpnp.block` : Assemble an nd-array from nested lists of blocks. :obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal size. @@ -1042,20 +1112,20 @@ def moveaxis(a, source, destination): For full documentation refer to :obj:`numpy.moveaxis`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + The array whose axes should be reordered. + source : int or sequence of int + Original positions of the axes to move. These must be unique. + destination : int or sequence of int + Destination positions for each of the original axes. These must also be + unique. + Returns ------- out : dpnp.ndarray - Array with moved axes. - The returned array will have the same data and - the same USM allocation type as `a`. - - Limitations - ----------- - Parameters `a` is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exception - will be raised. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. + Array with moved axes. This array is a view of the input array. See Also -------- @@ -1073,9 +1143,9 @@ def moveaxis(a, source, destination): """ - dpt_array = dpnp.get_usm_ndarray(a) + usm_array = dpnp.get_usm_ndarray(a) return dpnp_array._create_from_usm_ndarray( - dpt.moveaxis(dpt_array, source, destination) + dpt.moveaxis(usm_array, source, destination) ) @@ -1101,7 +1171,7 @@ def ravel(a, order="C"): Returns ------- out : dpnp_array - `out` is a contiguous 1-D array of the same subtype as `a`, with shape (a.size,) + A contiguous 1-D array of the same subtype as `a`, with shape (a.size,). See Also -------- @@ -1199,7 +1269,7 @@ def reshape(a, /, newshape, order="C", copy=None): inferred from the length of the array and remaining dimensions. order : {'C', 'F'}, optional Read the elements of `a` using this index order, and place the - elements into the reshaped array using this index order. 'C' + elements into the reshaped array using this index order. 'C' means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest. 'F' means to read / write the @@ -1217,7 +1287,7 @@ def reshape(a, /, newshape, order="C", copy=None): Returns ------- - y : dpnp.ndarray + out : dpnp.ndarray This will be a new view object if possible; otherwise, it will be a copy. Note there is no guarantee of the *memory layout* (C- or Fortran- contiguous) of the returned array. @@ -1270,7 +1340,7 @@ def result_type(*arrays_and_dtypes): Parameters ---------- - arrays_and_dtypes : list of arrays and dtypes + arrays_and_dtypes : {dpnp.ndarray, usm_ndarray, dtype} An arbitrary length sequence of arrays or dtypes. Returns @@ -1278,11 +1348,6 @@ def result_type(*arrays_and_dtypes): out : dtype The result type. - Limitations - ----------- - An array in the input list is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Examples -------- >>> import dpnp as dp @@ -1314,20 +1379,27 @@ def roll(x, shift, axis=None): For full documentation refer to :obj:`numpy.roll`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + shift : int or tuple of ints + The number of places by which elements are shifted. If a tuple, + then `axis` must be a tuple of the same size, and each of the + given axes is shifted by the corresponding number. If an int + while `axis` is a tuple of ints, then the same value is used for + all given axes. + axis : int or tuple of ints, optional + Axis or axes along which elements are shifted. By default, the + array is flattened before shifting, after which the original + shape is restored. + Returns ------- - dpnp.ndarray + out : dpnp.ndarray An array with the same data type as `x` and whose elements, relative to `x`, are shifted. - Limitations - ----------- - Parameter `x` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exception - will be raised. - Input array data types are limited by supported DPNP :ref:`Data types`. - - See Also -------- :obj:`dpnp.moveaxis` : Move array axes to new positions. @@ -1356,9 +1428,9 @@ def roll(x, shift, axis=None): """ if axis is None: return roll(x.reshape(-1), shift, 0).reshape(x.shape) - dpt_array = dpnp.get_usm_ndarray(x) + usm_array = dpnp.get_usm_ndarray(x) return dpnp_array._create_from_usm_ndarray( - dpt.roll(dpt_array, shift=shift, axis=axis) + dpt.roll(usm_array, shift=shift, axis=axis) ) @@ -1368,19 +1440,25 @@ def rollaxis(x, axis, start=0): For full documentation refer to :obj:`numpy.rollaxis`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + axis : int + The axis to be rolled. The positions of the other axes do not + change relative to one another. + start : int, optional + When ``start <= axis``, the axis is rolled back until it lies in + this position. When ``start > axis``, the axis is rolled until it + lies before this position. The default, ``0``, results in a "complete" + roll. + Returns ------- - dpnp.ndarray + out : dpnp.ndarray An array with the same data type as `x` where the specified axis has been repositioned to the desired position. - Limitations - ----------- - Parameter `x` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. Otherwise ``TypeError`` exception - will be raised. - Input array data types are limited by supported DPNP :ref:`Data types`. - See Also -------- :obj:`dpnp.moveaxis` : Move array axes to new positions. @@ -1411,8 +1489,8 @@ def rollaxis(x, axis, start=0): start -= 1 if axis == start: return x - dpt_array = dpnp.get_usm_ndarray(x) - return dpnp.moveaxis(dpt_array, source=axis, destination=start) + usm_array = dpnp.get_usm_ndarray(x) + return dpnp.moveaxis(usm_array, source=axis, destination=start) def shape(a): @@ -1464,22 +1542,22 @@ def squeeze(a, /, axis=None): For full documentation refer to :obj:`numpy.squeeze`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input data. + axis : None or int or tuple of ints, optional + Selects a subset of the entries of length one in the shape. + If an axis is selected with shape entry greater than one, + an error is raised. + Returns ------- out : dpnp.ndarray - Output array is a view, if possible, - and a copy otherwise, but with all or a subset of the - dimensions of length 1 removed. Output has the same data - type as the input, is allocated on the same device as the - input and has the same USM allocation type as the input - array `a`. - - Limitations - ----------- - Parameters `a` is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. + Output array is a view, if possible, and a copy otherwise, but with all + or a subset of the dimensions of length 1 removed. Output has the same + data type as the input, is allocated on the same device as the input + and has the same USM allocation type as the input array `a`. Examples -------- @@ -1500,9 +1578,9 @@ def squeeze(a, /, axis=None): """ - dpt_array = dpnp.get_usm_ndarray(a) + usm_array = dpnp.get_usm_ndarray(a) return dpnp_array._create_from_usm_ndarray( - dpt.squeeze(dpt_array, axis=axis) + dpt.squeeze(usm_array, axis=axis) ) @@ -1535,6 +1613,10 @@ def stack(arrays, /, *, axis=0, out=None, dtype=None, casting="same_kind"): See Also -------- :obj:`dpnp.concatenate` : Join a sequence of arrays along an existing axis. + :obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise). + :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). + :obj:`dpnp.dstack` : Stack arrays in sequence depth wise (along third dimension). + :obj:`dpnp.column_stack` : Stack 1-D arrays as columns into a 2-D array. :obj:`dpnp.block` : Assemble an nd-array from nested lists of blocks. :obj:`dpnp.split` : Split array into a list of multiple sub-arrays of equal size. @@ -1586,19 +1668,21 @@ def swapaxes(a, axis1, axis2): For full documentation refer to :obj:`numpy.swapaxes`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + axis1 : int + First axis. + axis2 : int + Second axis. + Returns ------- out : dpnp.ndarray An array with with swapped axes. A view is returned whenever possible. - Limitations - ----------- - Parameters `a` is supported either as :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. - Otherwise ``TypeError`` exception will be raised. - Notes ----- If `a` has rank (i.e., number of dimensions) `N`, @@ -1627,9 +1711,9 @@ def swapaxes(a, axis1, axis2): """ - dpt_array = dpnp.get_usm_ndarray(a) + usm_array = dpnp.get_usm_ndarray(a) return dpnp_array._create_from_usm_ndarray( - dpt.swapaxes(dpt_array, axis1=axis1, axis2=axis2) + dpt.swapaxes(usm_array, axis1=axis1, axis2=axis2) ) @@ -1657,14 +1741,14 @@ def tile(A, reps): Parameters ---------- - A : dpnp.ndarray + A : {dpnp.ndarray, usm_ndarray} The input array. - reps : array_like + reps : int or tuple of ints The number of repetitions of `A` along each axis. Returns ------- - c : dpnp.ndarray + out : dpnp.ndarray The tiled output array. See Also @@ -1707,8 +1791,8 @@ def tile(A, reps): """ - dpt_array = dpnp.get_usm_ndarray(A) - return dpnp_array._create_from_usm_ndarray(dpt.tile(dpt_array, reps)) + usm_array = dpnp.get_usm_ndarray(A) + return dpnp_array._create_from_usm_ndarray(dpt.tile(usm_array, reps)) def transpose(a, axes=None): @@ -1717,16 +1801,22 @@ def transpose(a, axes=None): For full documentation refer to :obj:`numpy.transpose`. + Parameters + ---------- + a : {dpnp.ndarray, usm_ndarray} + Input array. + axes : tuple or list of ints, optional + If specified, it must be a tuple or list which contains a permutation + of [0, 1, ..., N-1] where N is the number of axes of `a`. + The `i`'th axis of the returned array will correspond to the axis + numbered ``axes[i]`` of the input. If not specified, defaults to + ``range(a.ndim)[::-1]``, which reverses the order of the axes. + Returns ------- - y : dpnp.ndarray + out : dpnp.ndarray `a` with its axes permuted. A view is returned whenever possible. - Limitations - ----------- - Input array is supported as either :class:`dpnp.ndarray` - or :class:`dpctl.tensor.usm_ndarray`. - See Also -------- :obj:`dpnp.ndarray.transpose` : Equivalent method. From 09a196739e29236f5c0e7401730e3148cb788007 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 20 Dec 2023 15:34:08 +0100 Subject: [PATCH 3/9] Added tests --- dpnp/dpnp_iface_manipulation.py | 46 ++- tests/test_arraymanipulation.py | 593 ++++++++++++++++++-------------- tests/test_sycl_queue.py | 32 ++ tests/test_usm_type.py | 24 ++ 4 files changed, 417 insertions(+), 278 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 3536a491cdee..cedae7492240 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -85,6 +85,16 @@ ] +def _check_stack_arrays(arrays): + """Validate a sequence type of arrays to stack.""" + + if not hasattr(arrays, "__getitem__"): + raise TypeError( + 'arrays to stack must be passed as a "sequence" type ' + "such as list or tuple." + ) + + def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None): """ Return an array converted to a float type. @@ -551,6 +561,8 @@ def column_stack(tup): """ + _check_stack_arrays(tup) + arrays = [] for v in tup: dpnp.check_supported_arrays_type(v) @@ -563,7 +575,7 @@ def column_stack(tup): ) arrays.append(v) - return dpnp.concatenate(arrays, 1) + return dpnp.concatenate(arrays, axis=1) def concatenate( @@ -778,6 +790,8 @@ def dstack(tup): """ + _check_stack_arrays(tup) + arrs = atleast_3d(*tup) if not isinstance(arrs, list): arrs = [arrs] @@ -1078,27 +1092,26 @@ def hstack(tup, *, dtype=None, casting="same_kind"): Examples -------- >>> import dpnp as np - >>> a = np.array((1,2,3)) - >>> b = np.array((4,5,6)) - >>> np.hstack((a,b)) + >>> a = np.array((1, 2, 3)) + >>> b = np.array((4, 5, 6)) + >>> np.hstack((a, b)) array([1, 2, 3, 4, 5, 6]) - >>> a = np.array([[1],[2],[3]]) - >>> b = np.array([[4],[5],[6]]) - >>> np.hstack((a,b)) + >>> a = np.array([[1], [2], [3]]) + >>> b = np.array([[4], [5], [6]]) + >>> np.hstack((a, b)) array([[1, 4], [2, 5], [3, 6]]) """ - if not hasattr(tup, "__getitem__"): - raise TypeError( - "Arrays to stack must be passed as a sequence type such as list or tuple." - ) + _check_stack_arrays(tup) + arrs = dpnp.atleast_1d(*tup) if not isinstance(arrs, list): arrs = [arrs] + # As a special case, dimension 0 of 1-dimensional arrays is "horizontal" if arrs and arrs[0].ndim == 1: return dpnp.concatenate(arrs, axis=0, dtype=dtype, casting=casting) @@ -1646,6 +1659,8 @@ def stack(arrays, /, *, axis=0, out=None, dtype=None, casting="same_kind"): """ + _check_stack_arrays(arrays) + if dtype is not None and out is not None: raise TypeError( "stack() only takes `out` or `dtype` as an argument, but both were provided." @@ -1887,6 +1902,9 @@ def vstack(tup, *, dtype=None, casting="same_kind"): """ Stack arrays in sequence vertically (row wise). + :obj:`dpnp.row_stack` is an alias for :obj:`dpnp.vstack`. + They are the same function. + For full documentation refer to :obj:`numpy.vstack`. Parameters @@ -1935,10 +1953,8 @@ def vstack(tup, *, dtype=None, casting="same_kind"): """ - if not hasattr(tup, "__getitem__"): - raise TypeError( - "Arrays to stack must be passed as a sequence type such as list or tuple." - ) + _check_stack_arrays(tup) + arrs = dpnp.atleast_2d(*tup) if not isinstance(arrs, list): arrs = [arrs] diff --git a/tests/test_arraymanipulation.py b/tests/test_arraymanipulation.py index 03ebf0bab561..69116ef86921 100644 --- a/tests/test_arraymanipulation.py +++ b/tests/test_arraymanipulation.py @@ -5,7 +5,6 @@ assert_array_equal, assert_equal, assert_raises, - assert_warns, ) import dpnp @@ -13,117 +12,130 @@ from .helper import get_all_dtypes, get_float_complex_dtypes -@pytest.mark.parametrize("dtype", get_all_dtypes()) -@pytest.mark.parametrize( - "data", [[1, 2, 3], [1.0, 2.0, 3.0]], ids=["[1, 2, 3]", "[1., 2., 3.]"] -) -def test_asfarray(dtype, data): - expected = numpy.asfarray(data, dtype) - result = dpnp.asfarray(data, dtype) +class TestAtleast1d: + def test_0D_array(self): + a = dpnp.array(1) + b = dpnp.array(2) + res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] + desired = [dpnp.array([1]), dpnp.array([2])] + assert_array_equal(res, desired) - assert_array_equal(result, expected) + def test_1D_array(self): + a = dpnp.array([1, 2]) + b = dpnp.array([2, 3]) + res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] + desired = [dpnp.array([1, 2]), dpnp.array([2, 3])] + assert_array_equal(res, desired) + def test_2D_array(self): + a = dpnp.array([[1, 2], [1, 2]]) + b = dpnp.array([[2, 3], [2, 3]]) + res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] + desired = [a, b] + assert_array_equal(res, desired) -@pytest.mark.parametrize("dtype", get_all_dtypes()) -@pytest.mark.parametrize("data", [[1.0, 2.0, 3.0]], ids=["[1., 2., 3.]"]) -@pytest.mark.parametrize("data_dtype", get_all_dtypes(no_none=True)) -def test_asfarray2(dtype, data, data_dtype): - expected = numpy.asfarray(numpy.array(data, dtype=data_dtype), dtype) - result = dpnp.asfarray(dpnp.array(data, dtype=data_dtype), dtype) + def test_3D_array(self): + a = dpnp.array([[1, 2], [1, 2]]) + b = dpnp.array([[2, 3], [2, 3]]) + a = dpnp.array([a, a]) + b = dpnp.array([b, b]) + res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] + desired = [a, b] + assert_array_equal(res, desired) - assert_array_equal(result, expected) +class TestAtleast2d: + def test_0D_array(self): + a = dpnp.array(1) + b = dpnp.array(2) + res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] + desired = [dpnp.array([[1]]), dpnp.array([[2]])] + assert_array_equal(res, desired) -class TestDims: - @pytest.mark.parametrize("dt", get_all_dtypes()) - @pytest.mark.parametrize( - "sh", [(0,), (1,), (3,)], ids=["(0,)", "(1,)", "(3,)"] - ) - def test_broadcast_array(self, sh, dt): - np_a = numpy.array(0, dtype=dt) - dp_a = dpnp.array(0, dtype=dt) - func = lambda xp, a: xp.broadcast_to(a, sh) + def test_1D_array(self): + a = dpnp.array([1, 2]) + b = dpnp.array([2, 3]) + res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] + desired = [dpnp.array([[1, 2]]), dpnp.array([[2, 3]])] + assert_array_equal(res, desired) - assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + def test_2D_array(self): + a = dpnp.array([[1, 2], [1, 2]]) + b = dpnp.array([[2, 3], [2, 3]]) + res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] + desired = [a, b] + assert_array_equal(res, desired) - @pytest.mark.parametrize("dt", get_all_dtypes()) - @pytest.mark.parametrize( - "sh", [(1,), (2,), (1, 2, 3)], ids=["(1,)", "(2,)", "(1, 2, 3)"] - ) - def test_broadcast_ones(self, sh, dt): - np_a = numpy.ones(1, dtype=dt) - dp_a = dpnp.ones(1, dtype=dt) - func = lambda xp, a: xp.broadcast_to(a, sh) + def test_3D_array(self): + a = dpnp.array([[1, 2], [1, 2]]) + b = dpnp.array([[2, 3], [2, 3]]) + a = dpnp.array([a, a]) + b = dpnp.array([b, b]) + res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] + desired = [a, b] + assert_array_equal(res, desired) - assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) - @pytest.mark.parametrize("dt", get_all_dtypes(no_bool=True)) - @pytest.mark.parametrize( - "sh", [(3,), (1, 3), (2, 3)], ids=["(3,)", "(1, 3)", "(2, 3)"] - ) - def test_broadcast_arange(self, sh, dt): - np_a = numpy.arange(3, dtype=dt) - dp_a = dpnp.arange(3, dtype=dt) - func = lambda xp, a: xp.broadcast_to(a, sh) +class TestAtleast3d: + def test_0D_array(self): + a = dpnp.array(1) + b = dpnp.array(2) + res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] + desired = [dpnp.array([[[1]]]), dpnp.array([[[2]]])] + assert_array_equal(res, desired) - assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + def test_1D_array(self): + a = dpnp.array([1, 2]) + b = dpnp.array([2, 3]) + res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] + desired = [dpnp.array([[[1], [2]]]), dpnp.array([[[2], [3]]])] + assert_array_equal(res, desired) - @pytest.mark.parametrize("dt", get_all_dtypes()) - @pytest.mark.parametrize( - "sh1, sh2", - [ - pytest.param([0], [0], id="(0)"), - pytest.param([1], [1], id="(1)"), - pytest.param([1], [2], id="(2)"), - ], - ) - def test_broadcast_not_tuple(self, sh1, sh2, dt): - np_a = numpy.ones(sh1, dtype=dt) - dp_a = dpnp.ones(sh1, dtype=dt) - func = lambda xp, a: xp.broadcast_to(a, sh2) + def test_2D_array(self): + a = dpnp.array([[1, 2], [1, 2]]) + b = dpnp.array([[2, 3], [2, 3]]) + res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] + desired = [a[:, :, dpnp.newaxis], b[:, :, dpnp.newaxis]] + assert_array_equal(res, desired) - assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + def test_3D_array(self): + a = dpnp.array([[1, 2], [1, 2]]) + b = dpnp.array([[2, 3], [2, 3]]) + a = dpnp.array([a, a]) + b = dpnp.array([b, b]) + res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] + desired = [a, b] + assert_array_equal(res, desired) - @pytest.mark.parametrize("dt", get_all_dtypes()) - @pytest.mark.parametrize( - "sh1, sh2", - [ - pytest.param([1], (0,), id="(0,)"), - pytest.param((1, 2), (0, 2), id="(0, 2)"), - pytest.param((2, 1), (2, 0), id="(2, 0)"), - ], - ) - def test_broadcast_zero_shape(self, sh1, sh2, dt): - np_a = numpy.ones(sh1, dtype=dt) - dp_a = dpnp.ones(sh1, dtype=dt) - func = lambda xp, a: xp.broadcast_to(a, sh2) - assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) +class TestColumnStack: + def test_non_iterable(self): + with pytest.raises(TypeError): + dpnp.column_stack(1) @pytest.mark.parametrize( - "sh1, sh2", + "data1, data2", [ - pytest.param((0,), (), id="(0,)-()"), - pytest.param((1,), (), id="(1,)-()"), - pytest.param((3,), (), id="(3,)-()"), - pytest.param((3,), (1,), id="(3,)-(1,)"), - pytest.param((3,), (2,), id="(3,)-(2,)"), - pytest.param((3,), (4,), id="(3,)-(4,)"), - pytest.param((1, 2), (2, 1), id="(1, 2)-(2, 1)"), - pytest.param((1, 2), (1,), id="(1, 2)-(1,)"), - pytest.param((1,), -1, id="(1,)--1"), - pytest.param((1,), (-1,), id="(1,)-(-1,)"), - pytest.param((1, 2), (-1, 2), id="(1, 2)-(-1, 2)"), + pytest.param((1, 2, 3), (2, 3, 4), id="1D arrays"), + pytest.param([[1], [2], [3]], [[2], [3], [4]], id="2D arrays"), ], ) - def test_broadcast_raise(self, sh1, sh2): - np_a = numpy.zeros(sh1) - dp_a = dpnp.zeros(sh1) - func = lambda xp, a: xp.broadcast_to(a, sh2) + @pytest.mark.parametrize("dtype", get_all_dtypes()) + def test_1d_2d_arrays(self, data1, data2, dtype): + np_a = numpy.array(data1, dtype=dtype) + np_b = numpy.array(data2, dtype=dtype) + dp_a = dpnp.array(np_a, dtype=dtype) + dp_b = dpnp.array(np_b, dtype=dtype) - with pytest.raises(ValueError): - func(numpy, np_a) - func(dpnp, dp_a) + np_res = numpy.column_stack((np_a, np_b)) + dp_res = dpnp.column_stack((dp_a, dp_b)) + assert_array_equal(dp_res.asnumpy(), np_res) + + def test_generator(self): + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.column_stack((dpnp.arange(3) for _ in range(2))) + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.column_stack(map(lambda x: x, dpnp.ones((3, 2)))) class TestConcatenate: @@ -344,6 +356,136 @@ def test_concatenate_casting(self, dtype, casting): assert_array_equal(dp_res.asnumpy(), np_res) + def test_concatenate_out_dtype(self): + x = dpnp.ones((5, 5)) + out = dpnp.empty_like(x) + with pytest.raises(TypeError): + dpnp.concatenate([x], out=out, dtype="i4") + + +class TestDims: + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize( + "sh", [(0,), (1,), (3,)], ids=["(0,)", "(1,)", "(3,)"] + ) + def test_broadcast_array(self, sh, dt): + np_a = numpy.array(0, dtype=dt) + dp_a = dpnp.array(0, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize( + "sh", [(1,), (2,), (1, 2, 3)], ids=["(1,)", "(2,)", "(1, 2, 3)"] + ) + def test_broadcast_ones(self, sh, dt): + np_a = numpy.ones(1, dtype=dt) + dp_a = dpnp.ones(1, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes(no_bool=True)) + @pytest.mark.parametrize( + "sh", [(3,), (1, 3), (2, 3)], ids=["(3,)", "(1, 3)", "(2, 3)"] + ) + def test_broadcast_arange(self, sh, dt): + np_a = numpy.arange(3, dtype=dt) + dp_a = dpnp.arange(3, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize( + "sh1, sh2", + [ + pytest.param([0], [0], id="(0)"), + pytest.param([1], [1], id="(1)"), + pytest.param([1], [2], id="(2)"), + ], + ) + def test_broadcast_not_tuple(self, sh1, sh2, dt): + np_a = numpy.ones(sh1, dtype=dt) + dp_a = dpnp.ones(sh1, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh2) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize( + "sh1, sh2", + [ + pytest.param([1], (0,), id="(0,)"), + pytest.param((1, 2), (0, 2), id="(0, 2)"), + pytest.param((2, 1), (2, 0), id="(2, 0)"), + ], + ) + def test_broadcast_zero_shape(self, sh1, sh2, dt): + np_a = numpy.ones(sh1, dtype=dt) + dp_a = dpnp.ones(sh1, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh2) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize( + "sh1, sh2", + [ + pytest.param((0,), (), id="(0,)-()"), + pytest.param((1,), (), id="(1,)-()"), + pytest.param((3,), (), id="(3,)-()"), + pytest.param((3,), (1,), id="(3,)-(1,)"), + pytest.param((3,), (2,), id="(3,)-(2,)"), + pytest.param((3,), (4,), id="(3,)-(4,)"), + pytest.param((1, 2), (2, 1), id="(1, 2)-(2, 1)"), + pytest.param((1, 2), (1,), id="(1, 2)-(1,)"), + pytest.param((1,), -1, id="(1,)--1"), + pytest.param((1,), (-1,), id="(1,)-(-1,)"), + pytest.param((1, 2), (-1, 2), id="(1, 2)-(-1, 2)"), + ], + ) + def test_broadcast_raise(self, sh1, sh2): + np_a = numpy.zeros(sh1) + dp_a = dpnp.zeros(sh1) + func = lambda xp, a: xp.broadcast_to(a, sh2) + + with pytest.raises(ValueError): + func(numpy, np_a) + func(dpnp, dp_a) + + +class TestDstack: + def test_non_iterable(self): + with pytest.raises(TypeError): + dpnp.dstack(1) + + @pytest.mark.parametrize( + "data1, data2", + [ + pytest.param(1, 2, id="0D arrays"), + pytest.param([1], [2], id="1D arrays"), + pytest.param([[1], [2]], [[1], [2]], id="2D arrays"), + pytest.param([1, 2], [1, 2], id="1D arrays-2"), + ], + ) + @pytest.mark.parametrize("dtype", get_all_dtypes()) + def test_arrays(self, data1, data2, dtype): + np_a = numpy.array(data1, dtype=dtype) + np_b = numpy.array(data2, dtype=dtype) + dp_a = dpnp.array(np_a, dtype=dtype) + dp_b = dpnp.array(np_b, dtype=dtype) + + np_res = numpy.dstack([np_a, np_b]) + dp_res = dpnp.dstack([dp_a, dp_b]) + assert_array_equal(dp_res.asnumpy(), np_res) + + def test_generator(self): + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.dstack((dpnp.arange(3) for _ in range(2))) + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.dstack(map(lambda x: x, dpnp.ones((3, 2)))) + class TestHstack: def test_non_iterable(self): @@ -374,9 +516,9 @@ def test_2D_array(self): assert_array_equal(res, desired) def test_generator(self): - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="arrays to stack must be"): dpnp.hstack((dpnp.arange(3) for _ in range(2))) - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="arrays to stack must be"): dpnp.hstack(map(lambda x: x, dpnp.ones((3, 2)))) def test_one_element(self): @@ -385,6 +527,71 @@ def test_one_element(self): assert_array_equal(res, a) +class TestRollaxis: + data = [ + (0, 0), + (0, 1), + (0, 2), + (0, 3), + (0, 4), + (1, 0), + (1, 1), + (1, 2), + (1, 3), + (1, 4), + (2, 0), + (2, 1), + (2, 2), + (2, 3), + (2, 4), + (3, 0), + (3, 1), + (3, 2), + (3, 3), + (3, 4), + ] + + @pytest.mark.parametrize( + ("axis", "start"), + [ + (-5, 0), + (0, -5), + (4, 0), + (0, 5), + ], + ) + def test_exceptions(self, axis, start): + a = dpnp.arange(1 * 2 * 3 * 4).reshape(1, 2, 3, 4) + assert_raises(ValueError, dpnp.rollaxis, a, axis, start) + + def test_results(self): + np_a = numpy.arange(1 * 2 * 3 * 4).reshape(1, 2, 3, 4) + dp_a = dpnp.array(np_a) + for i, j in self.data: + # positive axis, positive start + res = dpnp.rollaxis(dp_a, axis=i, start=j) + exp = numpy.rollaxis(np_a, axis=i, start=j) + assert res.shape == exp.shape + + # negative axis, positive start + ip = i + 1 + res = dpnp.rollaxis(dp_a, axis=-ip, start=j) + exp = numpy.rollaxis(np_a, axis=-ip, start=j) + assert res.shape == exp.shape + + # positive axis, negative start + jp = j + 1 if j < 4 else j + res = dpnp.rollaxis(dp_a, axis=i, start=-jp) + exp = numpy.rollaxis(np_a, axis=i, start=-jp) + assert res.shape == exp.shape + + # negative axis, negative start + ip = i + 1 + jp = j + 1 if j < 4 else j + res = dpnp.rollaxis(dp_a, axis=-ip, start=-jp) + exp = numpy.rollaxis(np_a, axis=-ip, start=-jp) + + class TestStack: def test_non_iterable_input(self): with pytest.raises(TypeError): @@ -573,6 +780,18 @@ def test_invalid_casting_dtype(self, arr_dtype, dtype): dtype=dtype, ) + def test_stack_out_dtype(self): + x = dpnp.ones((5, 5)) + out = dpnp.empty_like(x) + with pytest.raises(TypeError): + dpnp.stack([x], out=out, dtype="i4") + + def test_generator(self): + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.stack((dpnp.arange(3) for _ in range(2))) + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.stack(map(lambda x: x, dpnp.ones((3, 2)))) + class TestVstack: def test_non_iterable(self): @@ -610,169 +829,31 @@ def test_2D_array2(self): assert_array_equal(res, desired) def test_generator(self): - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="arrays to stack must be"): dpnp.vstack((dpnp.arange(3) for _ in range(2))) + with pytest.raises(TypeError, match="arrays to stack must be"): + dpnp.vstack(map(lambda x: x, dpnp.ones((3, 2)))) -class TestAtleast1d: - def test_0D_array(self): - a = dpnp.array(1) - b = dpnp.array(2) - res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] - desired = [dpnp.array([1]), dpnp.array([2])] - assert_array_equal(res, desired) - - def test_1D_array(self): - a = dpnp.array([1, 2]) - b = dpnp.array([2, 3]) - res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] - desired = [dpnp.array([1, 2]), dpnp.array([2, 3])] - assert_array_equal(res, desired) - - def test_2D_array(self): - a = dpnp.array([[1, 2], [1, 2]]) - b = dpnp.array([[2, 3], [2, 3]]) - res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] - desired = [a, b] - assert_array_equal(res, desired) - - def test_3D_array(self): - a = dpnp.array([[1, 2], [1, 2]]) - b = dpnp.array([[2, 3], [2, 3]]) - a = dpnp.array([a, a]) - b = dpnp.array([b, b]) - res = [dpnp.atleast_1d(a), dpnp.atleast_1d(b)] - desired = [a, b] - assert_array_equal(res, desired) - - -class TestRollaxis: - data = [ - (0, 0), - (0, 1), - (0, 2), - (0, 3), - (0, 4), - (1, 0), - (1, 1), - (1, 2), - (1, 3), - (1, 4), - (2, 0), - (2, 1), - (2, 2), - (2, 3), - (2, 4), - (3, 0), - (3, 1), - (3, 2), - (3, 3), - (3, 4), - ] - - @pytest.mark.parametrize( - ("axis", "start"), - [ - (-5, 0), - (0, -5), - (4, 0), - (0, 5), - ], - ) - def test_exceptions(self, axis, start): - a = dpnp.arange(1 * 2 * 3 * 4).reshape(1, 2, 3, 4) - assert_raises(ValueError, dpnp.rollaxis, a, axis, start) - - def test_results(self): - np_a = numpy.arange(1 * 2 * 3 * 4).reshape(1, 2, 3, 4) - dp_a = dpnp.array(np_a) - for i, j in self.data: - # positive axis, positive start - res = dpnp.rollaxis(dp_a, axis=i, start=j) - exp = numpy.rollaxis(np_a, axis=i, start=j) - assert res.shape == exp.shape - - # negative axis, positive start - ip = i + 1 - res = dpnp.rollaxis(dp_a, axis=-ip, start=j) - exp = numpy.rollaxis(np_a, axis=-ip, start=j) - assert res.shape == exp.shape - - # positive axis, negative start - jp = j + 1 if j < 4 else j - res = dpnp.rollaxis(dp_a, axis=i, start=-jp) - exp = numpy.rollaxis(np_a, axis=i, start=-jp) - assert res.shape == exp.shape - - # negative axis, negative start - ip = i + 1 - jp = j + 1 if j < 4 else j - res = dpnp.rollaxis(dp_a, axis=-ip, start=-jp) - exp = numpy.rollaxis(np_a, axis=-ip, start=-jp) - - -class TestAtleast2d: - def test_0D_array(self): - a = dpnp.array(1) - b = dpnp.array(2) - res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] - desired = [dpnp.array([[1]]), dpnp.array([[2]])] - assert_array_equal(res, desired) - - def test_1D_array(self): - a = dpnp.array([1, 2]) - b = dpnp.array([2, 3]) - res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] - desired = [dpnp.array([[1, 2]]), dpnp.array([[2, 3]])] - assert_array_equal(res, desired) - - def test_2D_array(self): - a = dpnp.array([[1, 2], [1, 2]]) - b = dpnp.array([[2, 3], [2, 3]]) - res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] - desired = [a, b] - assert_array_equal(res, desired) - - def test_3D_array(self): - a = dpnp.array([[1, 2], [1, 2]]) - b = dpnp.array([[2, 3], [2, 3]]) - a = dpnp.array([a, a]) - b = dpnp.array([b, b]) - res = [dpnp.atleast_2d(a), dpnp.atleast_2d(b)] - desired = [a, b] - assert_array_equal(res, desired) - +@pytest.mark.parametrize("dtype", get_all_dtypes()) +@pytest.mark.parametrize( + "data", [[1, 2, 3], [1.0, 2.0, 3.0]], ids=["[1, 2, 3]", "[1., 2., 3.]"] +) +def test_asfarray(dtype, data): + expected = numpy.asfarray(data, dtype) + result = dpnp.asfarray(data, dtype) -class TestAtleast3d: - def test_0D_array(self): - a = dpnp.array(1) - b = dpnp.array(2) - res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] - desired = [dpnp.array([[[1]]]), dpnp.array([[[2]]])] - assert_array_equal(res, desired) + assert_array_equal(result, expected) - def test_1D_array(self): - a = dpnp.array([1, 2]) - b = dpnp.array([2, 3]) - res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] - desired = [dpnp.array([[[1], [2]]]), dpnp.array([[[2], [3]]])] - assert_array_equal(res, desired) - def test_2D_array(self): - a = dpnp.array([[1, 2], [1, 2]]) - b = dpnp.array([[2, 3], [2, 3]]) - res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] - desired = [a[:, :, dpnp.newaxis], b[:, :, dpnp.newaxis]] - assert_array_equal(res, desired) +@pytest.mark.parametrize("dtype", get_all_dtypes()) +@pytest.mark.parametrize("data", [[1.0, 2.0, 3.0]], ids=["[1., 2., 3.]"]) +@pytest.mark.parametrize("data_dtype", get_all_dtypes(no_none=True)) +def test_asfarray2(dtype, data, data_dtype): + expected = numpy.asfarray(numpy.array(data, dtype=data_dtype), dtype) + result = dpnp.asfarray(dpnp.array(data, dtype=data_dtype), dtype) - def test_3D_array(self): - a = dpnp.array([[1, 2], [1, 2]]) - b = dpnp.array([[2, 3], [2, 3]]) - a = dpnp.array([a, a]) - b = dpnp.array([b, b]) - res = [dpnp.atleast_3d(a), dpnp.atleast_3d(b)] - desired = [a, b] - assert_array_equal(res, desired) + assert_array_equal(result, expected) def assert_broadcast_correct(input_shapes): @@ -1045,17 +1126,3 @@ def test_repeat_strided_repeats(): res = dpnp.repeat(x, reps) assert res.shape == x.shape assert dpnp.all(res == x) - - -def test_concatenate_out_dtype(): - x = dpnp.ones((5, 5)) - out = dpnp.empty_like(x) - with pytest.raises(TypeError): - dpnp.concatenate([x], out=out, dtype="i4") - - -def test_stack_out_dtype(): - x = dpnp.ones((5, 5)) - out = dpnp.empty_like(x) - with pytest.raises(TypeError): - dpnp.stack([x], out=out, dtype="i4") diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 19104d7bd434..09275d63db63 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1283,6 +1283,38 @@ def test_broadcast_to(device): assert_sycl_queue_equal(x.sycl_queue, y.sycl_queue) +@pytest.mark.parametrize( + "func,data1,data2", + [ + pytest.param("column_stack", (1, 2, 3), (2, 3, 4)), + pytest.param("concatenate", [[1, 2], [3, 4]], [[5, 6]]), + pytest.param("dstack", [[1], [2], [3]], [[2], [3], [4]]), + pytest.param("hstack", (1, 2, 3), (4, 5, 6)), + pytest.param("row_stack", [[7], [1], [2], [3]], [[2], [3], [9], [4]]), + pytest.param("stack", [1, 2, 3], [4, 5, 6]), + pytest.param("vstack", [0, 1, 2, 3], [4, 5, 6, 7]), + ], +) +@pytest.mark.parametrize( + "device", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +def test_concat_stack(func, data1, data2, device): + x1_orig = numpy.array(data1) + x2_orig = numpy.array(data2) + expected = getattr(numpy, func)((x1_orig, x2_orig)) + + x1 = dpnp.array(data1, device=device) + x2 = dpnp.array(data2, device=device) + result = getattr(dpnp, func)((x1, x2)) + + assert_allclose(result, expected) + + assert_sycl_queue_equal(result.sycl_queue, x1.sycl_queue) + assert_sycl_queue_equal(result.sycl_queue, x2.sycl_queue) + + @pytest.mark.parametrize( "device_x", valid_devices, diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index fa2931cc5054..c1c3a013a865 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -473,6 +473,30 @@ def test_broadcast_to(usm_type): assert x.usm_type == y.usm_type +@pytest.mark.parametrize( + "func,data1,data2", + [ + pytest.param("column_stack", (1, 2, 3), (2, 3, 4)), + pytest.param("concatenate", [[1, 2], [3, 4]], [[5, 6]]), + pytest.param("dstack", [[1], [2], [3]], [[2], [3], [4]]), + pytest.param("hstack", (1, 2, 3), (4, 5, 6)), + pytest.param("row_stack", [[7], [1], [2], [3]], [[2], [3], [9], [4]]), + pytest.param("stack", [1, 2, 3], [4, 5, 6]), + pytest.param("vstack", [0, 1, 2, 3], [4, 5, 6, 7]), + ], +) +@pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) +@pytest.mark.parametrize("usm_type_y", list_of_usm_types, ids=list_of_usm_types) +def test_concat_stack(func, data1, data2, usm_type_x, usm_type_y): + x = dp.array(data1, usm_type=usm_type_x) + y = dp.array(data2, usm_type=usm_type_y) + z = getattr(dp, func)((x, y)) + + assert x.usm_type == usm_type_x + assert y.usm_type == usm_type_y + assert z.usm_type == du.get_coerced_usm_type([usm_type_x, usm_type_y]) + + @pytest.mark.parametrize("func", ["take", "take_along_axis"]) @pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types) @pytest.mark.parametrize( From 4c079a6a0601d3dd71da3e746d8c5f14b48541cc Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Wed, 20 Dec 2023 16:56:47 +0100 Subject: [PATCH 4/9] Muted test causing crash on CPU due to known issue --- tests/third_party/cupy/manipulation_tests/test_join.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/third_party/cupy/manipulation_tests/test_join.py b/tests/third_party/cupy/manipulation_tests/test_join.py index 105ccece4841..d239e76e3168 100644 --- a/tests/third_party/cupy/manipulation_tests/test_join.py +++ b/tests/third_party/cupy/manipulation_tests/test_join.py @@ -107,6 +107,7 @@ def test_concatenate_large_f_contiguous(self, xp, dtype): e = testing.shaped_arange((2, 3, 2), xp, dtype) return xp.concatenate((a, b, c, d, e) * 2, axis=-1) + @pytest.mark.skip(reason="lead to crash due to reported issue in OCL RT") @testing.numpy_cupy_array_equal(type_check=has_support_aspect64()) def test_concatenate_many_multi_dtype(self, xp): a = testing.shaped_arange((2, 1), xp, "i") From b5002a0783156a920ea79c9f1b1786209b5e9442 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 21 Dec 2023 01:51:59 +0100 Subject: [PATCH 5/9] Disable type check in a test for column_stack --- tests/third_party/cupy/manipulation_tests/test_join.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/third_party/cupy/manipulation_tests/test_join.py b/tests/third_party/cupy/manipulation_tests/test_join.py index d239e76e3168..72340355c19d 100644 --- a/tests/third_party/cupy/manipulation_tests/test_join.py +++ b/tests/third_party/cupy/manipulation_tests/test_join.py @@ -9,7 +9,7 @@ class TestJoin: @testing.for_all_dtypes(name="dtype1") @testing.for_all_dtypes(name="dtype2") - @testing.numpy_cupy_array_equal() + @testing.numpy_cupy_array_equal(type_check=has_support_aspect64()) def test_column_stack(self, xp, dtype1, dtype2): a = testing.shaped_arange((4, 3), xp, dtype1) b = testing.shaped_arange((4,), xp, dtype2) From 10972fefbe820a5d69cf07af08bc1040a2a548e9 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 21 Dec 2023 07:47:34 +0100 Subject: [PATCH 6/9] Corrected result data type from dpnp.prod on Gen9 --- dpnp/dpnp_iface_mathematical.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 53e4e619091e..20c5c922dbee 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -2119,7 +2119,7 @@ def prod( du.intel_device_info(a.sycl_device).get("device_id", 0) & 0xFF00 ) if _any_complex and device_mask in [0x3E00, 0x9B00]: - return call_origin( + res = call_origin( numpy.prod, a, axis=axis, @@ -2129,6 +2129,10 @@ def prod( initial=initial, where=where, ) + if dpnp.isscalar(res): + # numpy may return a scalar, convert it back to dpnp array + return dpnp.array(res, sycl_queue=a.sycl_queue, usm_type=a.usm_type) + return res elif initial is not None: raise NotImplementedError( "initial keyword argument is only supported with its default value." From 8d45b5adb712c0ed8712b9414a49d4ea3dbe5b56 Mon Sep 17 00:00:00 2001 From: Anton <100830759+antonwolfy@users.noreply.github.com> Date: Fri, 22 Dec 2023 09:37:03 +0100 Subject: [PATCH 7/9] Update dpnp/dpnp_iface_manipulation.py Co-authored-by: vtavana <120411540+vtavana@users.noreply.github.com> --- dpnp/dpnp_iface_manipulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 01abeb16ef5b..975881979745 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -105,7 +105,7 @@ def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None): The input array. dtype : str or dtype object, optional Float type code to coerce input array `a`. If `dtype` is ``None``, - :obj:`dpnp.bool` or one of the `int` dtypesis it is replaced with + :obj:`dpnp.bool` or one of the `int` dtypes, it is replaced with the default floating type (:obj:`dpnp.float64` if a device supports it, or :obj:`dpnp.float32` type otherwise). device : {None, string, SyclDevice, SyclQueue}, optional From 062477ac83bfbefa313acf785ae3d1fd2acd138b Mon Sep 17 00:00:00 2001 From: Anton <100830759+antonwolfy@users.noreply.github.com> Date: Fri, 22 Dec 2023 09:37:11 +0100 Subject: [PATCH 8/9] Update dpnp/dpnp_iface_manipulation.py Co-authored-by: vtavana <120411540+vtavana@users.noreply.github.com> --- dpnp/dpnp_iface_manipulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 975881979745..981e3f6c2a5b 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -744,7 +744,7 @@ def dstack(tup): This is equivalent to concatenation along the third axis after 2-D arrays of shape `(M, N)` have been reshaped to `(M, N, 1)` and 1-D arrays of shape `(N,)` have been reshaped to `(1, N, 1)`. Rebuilds arrays divided by - `dsplit`. + :obj:`dpnp.dsplit`. For full documentation refer to :obj:`numpy.dstack`. From dba7e03ab135914b4f7756070eeb5f7df06e9a38 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Fri, 22 Dec 2023 14:51:16 +0100 Subject: [PATCH 9/9] Updated docstrings to address review comments --- dpnp/dpnp_iface_manipulation.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 981e3f6c2a5b..9efb2aa04f17 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -101,8 +101,14 @@ def asfarray(a, dtype=None, *, device=None, usm_type=None, sycl_queue=None): Parameters ---------- - a : {dpnp.ndarray, usm_ndarray} - The input array. + a : array_like + Input data, in any form that can be converted to an array. + This includes an instance of :class:`dpnp.ndarray` or + :class:`dpctl.tensor.usm_ndarray`, an object representing + SYCL USM allocation and implementing `__sycl_usm_array_interface__` + protocol, an instance of :class:`numpy.ndarray`, an object supporting + Python buffer protocol, a Python scalar, or a (possibly nested) + sequence of Python scalars. dtype : str or dtype object, optional Float type code to coerce input array `a`. If `dtype` is ``None``, :obj:`dpnp.bool` or one of the `int` dtypes, it is replaced with @@ -349,7 +355,7 @@ def broadcast_arrays(*args, subok=False): Returns ------- - out : {dpnp.ndarray} + out : list of dpnp.ndarray A list of arrays which are views on the original arrays from `args`. Limitations @@ -541,7 +547,7 @@ def column_stack(tup): See Also -------- - :obj:`dpnp.stack` : Stack a sequence of arrays along a new axis. + :obj:`dpnp.stack` : Join a sequence of arrays along a new axis. :obj:`dpnp.dstack` : Stack arrays in sequence depth wise (along third axis). :obj:`dpnp.hstack` : Stack arrays in sequence horizontally (column wise). :obj:`dpnp.vstack` : Stack arrays in sequence vertically (row wise). @@ -1351,7 +1357,7 @@ def result_type(*arrays_and_dtypes): Parameters ---------- - arrays_and_dtypes : {dpnp.ndarray, usm_ndarray, dtype} + arrays_and_dtypes : list of {dpnp.ndarray, usm_ndarray, dtype} An arbitrary length sequence of arrays or dtypes. Returns