Skip to content

Commit

Permalink
Rework transpose methods to use dpctl.tensor functions (#1389)
Browse files Browse the repository at this point in the history
* Rework transpose methods to call dpctl.tensor functions

* Applied review comments & added more tests
  • Loading branch information
antonwolfy committed Jun 15, 2023
1 parent a9b9ffa commit b6cba98
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 166 deletions.
1 change: 0 additions & 1 deletion dpnp/backend/include/dpnp_iface_fptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@ enum class DPNPFuncName : size_t
DPNP_FN_TANH, /**< Used in numpy.tanh() impl */
DPNP_FN_TANH_EXT, /**< Used in numpy.tanh() impl, requires extra parameters */
DPNP_FN_TRANSPOSE, /**< Used in numpy.transpose() impl */
DPNP_FN_TRANSPOSE_EXT, /**< Used in numpy.transpose() impl, requires extra parameters */
DPNP_FN_TRACE, /**< Used in numpy.trace() impl */
DPNP_FN_TRACE_EXT, /**< Used in numpy.trace() impl, requires extra parameters */
DPNP_FN_TRAPZ, /**< Used in numpy.trapz() impl */
Expand Down
24 changes: 2 additions & 22 deletions dpnp/backend/kernels/dpnp_krnl_manipulation.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//*****************************************************************************
// Copyright (c) 2016-2020, Intel Corporation
// Copyright (c) 2016-2023, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -211,6 +211,7 @@ void dpnp_elemwise_transpose_c(void* array1_in,
size,
dep_event_vec_ref);
DPCTLEvent_WaitAndThrow(event_ref);
DPCTLEvent_Delete(event_ref);
}

template <typename _DataType>
Expand All @@ -222,17 +223,6 @@ void (*dpnp_elemwise_transpose_default_c)(void*,
void*,
size_t) = dpnp_elemwise_transpose_c<_DataType>;

template <typename _DataType>
DPCTLSyclEventRef (*dpnp_elemwise_transpose_ext_c)(DPCTLSyclQueueRef,
void*,
const shape_elem_type*,
const shape_elem_type*,
const shape_elem_type*,
size_t,
void*,
size_t,
const DPCTLEventVectorRef) = dpnp_elemwise_transpose_c<_DataType>;

void func_map_init_manipulation(func_map_t& fmap)
{
fmap[DPNPFuncName::DPNP_FN_REPEAT][eft_INT][eft_INT] = {eft_INT, (void*)dpnp_repeat_default_c<int32_t>};
Expand All @@ -253,15 +243,5 @@ void func_map_init_manipulation(func_map_t& fmap)
(void*)dpnp_elemwise_transpose_default_c<float>};
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE][eft_DBL][eft_DBL] = {eft_DBL,
(void*)dpnp_elemwise_transpose_default_c<double>};

fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_INT][eft_INT] = {eft_INT,
(void*)dpnp_elemwise_transpose_ext_c<int32_t>};
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_LNG][eft_LNG] = {eft_LNG,
(void*)dpnp_elemwise_transpose_ext_c<int64_t>};
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_FLT][eft_FLT] = {eft_FLT,
(void*)dpnp_elemwise_transpose_ext_c<float>};
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_DBL][eft_DBL] = {eft_DBL,
(void*)dpnp_elemwise_transpose_ext_c<double>};

return;
}
2 changes: 0 additions & 2 deletions dpnp/dpnp_algo/dpnp_algo.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
DPNP_FN_TRACE
DPNP_FN_TRACE_EXT
DPNP_FN_TRANSPOSE
DPNP_FN_TRANSPOSE_EXT
DPNP_FN_TRAPZ
DPNP_FN_TRAPZ_EXT
DPNP_FN_TRI
Expand Down Expand Up @@ -551,7 +550,6 @@ cpdef dpnp_descriptor dpnp_subtract(dpnp_descriptor x1_obj, dpnp_descriptor x2_o
Array manipulation routines
"""
cpdef dpnp_descriptor dpnp_repeat(dpnp_descriptor array1, repeats, axes=*)
cpdef dpnp_descriptor dpnp_transpose(dpnp_descriptor array1, axes=*)


"""
Expand Down
74 changes: 0 additions & 74 deletions dpnp/dpnp_algo/dpnp_algo_manipulation.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,10 @@ __all__ += [
"dpnp_expand_dims",
"dpnp_repeat",
"dpnp_reshape",
"dpnp_transpose",
]


# C function pointer to the C library template functions
ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_custom_elemwise_transpose_1in_1out_t)(c_dpctl.DPCTLSyclQueueRef,
void * ,
shape_elem_type * ,
shape_elem_type * ,
shape_elem_type * ,
size_t,
void * ,
size_t,
const c_dpctl.DPCTLEventVectorRef)
ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_dpnp_repeat_t)(c_dpctl.DPCTLSyclQueueRef,
const void *, void * , const size_t , const size_t,
const c_dpctl.DPCTLEventVectorRef)
Expand Down Expand Up @@ -229,67 +219,3 @@ cpdef utils.dpnp_descriptor dpnp_reshape(utils.dpnp_descriptor array1, newshape,
usm_type=array1_obj.usm_type,
sycl_queue=array1_obj.sycl_queue),
copy_when_nondefault_queue=False)


cpdef utils.dpnp_descriptor dpnp_transpose(utils.dpnp_descriptor array1, axes=None):
cdef shape_type_c input_shape = array1.shape
cdef size_t input_shape_size = array1.ndim
cdef shape_type_c result_shape = shape_type_c(input_shape_size, 1)

cdef shape_type_c permute_axes
if axes is None:
"""
template to do transpose a tensor
input_shape=[2, 3, 4]
permute_axes=[2, 1, 0]
after application `permute_axes` to `input_shape` result:
result_shape=[4, 3, 2]
'do nothing' axes variable is `permute_axes=[0, 1, 2]`
test: pytest tests/third_party/cupy/manipulation_tests/test_transpose.py::TestTranspose::test_external_transpose_all
"""
permute_axes = list(reversed([i for i in range(input_shape_size)]))
else:
permute_axes = utils.normalize_axis(axes, input_shape_size)

for i in range(input_shape_size):
""" construct output shape """
result_shape[i] = input_shape[permute_axes[i]]

# convert string type names (array.dtype) to C enum DPNPFuncType
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype)

# get the FPTR data structure
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_TRANSPOSE_EXT, param1_type, param1_type)

array1_obj = array1.get_array()

# ceate result array with type given by FPTR data
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 = <c_dpctl.SyclQueue> result_sycl_queue
cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref()

cdef fptr_custom_elemwise_transpose_1in_1out_t func = <fptr_custom_elemwise_transpose_1in_1out_t > kernel_data.ptr
# call FPTR function
cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref,
array1.get_data(),
input_shape.data(),
result_shape.data(),
permute_axes.data(),
input_shape_size,
result.get_data(),
array1.size,
NULL) # dep_events_ref

with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref)
c_dpctl.DPCTLEvent_Delete(event_ref)

return result
68 changes: 54 additions & 14 deletions dpnp/dpnp_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,8 @@ def get_array(self):

@property
def T(self):
"""Shape-reversed view of the array.
If ndim < 2, then this is just a reference to the array itself.
"""
if self.ndim < 2:
return self
else:
return dpnp.transpose(self)
"""View of the transposed array."""
return self.transpose()

def to_device(self, target_device):
"""
Expand Down Expand Up @@ -1025,15 +1018,62 @@ def take(self, indices, axis=None, out=None, mode='raise'):

def transpose(self, *axes):
"""
Returns a view of the array with axes permuted.
Returns a view of the array with axes transposed.
.. seealso::
:obj:`dpnp.transpose` for full documentation,
:meth:`numpy.ndarray.reshape`
For full documentation refer to :obj:`numpy.ndarray.transpose`.
Returns
-------
y : dpnp.ndarray
View of the array with its axes suitably permuted.
See Also
--------
:obj:`dpnp.transpose` : Equivalent function.
:obj:`dpnp.ndarray.ndarray.T` : Array property returning the array transposed.
:obj:`dpnp.ndarray.reshape` : Give a new shape to an array without changing its data.
Examples
--------
>>> import dpnp as dp
>>> a = dp.array([[1, 2], [3, 4]])
>>> a
array([[1, 2],
[3, 4]])
>>> a.transpose()
array([[1, 3],
[2, 4]])
>>> a.transpose((1, 0))
array([[1, 3],
[2, 4]])
>>> a = dp.array([1, 2, 3, 4])
>>> a
array([1, 2, 3, 4])
>>> a.transpose()
array([1, 2, 3, 4])
"""

return dpnp.transpose(self, axes)
ndim = self.ndim
if ndim < 2:
return self

axes_len = len(axes)
if axes_len == 1 and isinstance(axes[0], tuple):
axes = axes[0]

res = self.__new__(dpnp_array)
if ndim == 2 and axes_len == 0:
res._array_obj = self._array_obj.T
else:
if len(axes) == 0 or axes[0] is None:
# self.transpose().shape == self.shape[::-1]
# self.transpose(None).shape == self.shape[::-1]
axes = tuple((ndim - x - 1) for x in range(ndim))

res._array_obj = dpt.permute_dims(self._array_obj, axes)
return res

def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
"""
Expand Down
79 changes: 45 additions & 34 deletions dpnp/dpnp_iface_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,54 +673,65 @@ def swapaxes(x1, axis1, axis2):
return call_origin(numpy.swapaxes, x1, axis1, axis2)


def transpose(x1, axes=None):
def transpose(a, axes=None):
"""
Reverse or permute the axes of an array; returns the modified array.
Returns an array with axes transposed.
For full documentation refer to :obj:`numpy.transpose`.
Returns
-------
y : dpnp.ndarray
`a` with its axes permuted. A view is returned whenever possible.
Limitations
-----------
Input array is supported as :obj:`dpnp.ndarray`.
Otherwise the function will be executed sequentially on CPU.
Value of the parameter ``axes`` likely to be replaced with ``None``.
Input array data types are limited by supported DPNP :ref:`Data types`.
Input array is supported as either :class:`dpnp.ndarray`
or :class:`dpctl.tensor.usm_ndarray`.
See Also
--------
:obj:`dpnp.ndarray.transpose` : Equivalent method.
:obj:`dpnp.moveaxis` : Move array axes to new positions.
:obj:`dpnp.argsort` : Returns the indices that would sort an array.
Examples
--------
>>> import dpnp as np
>>> x = np.arange(4).reshape((2,2))
>>> x.shape
(2, 2)
>>> [i for i in x]
[0, 1, 2, 3]
>>> out = np.transpose(x)
>>> out.shape
(2, 2)
>>> [i for i in out]
[0, 2, 1, 3]
"""

x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
if x1_desc:
if axes is not None:
if not any(axes):
"""
pytest tests/third_party/cupy/manipulation_tests/test_transpose.py
"""
axes = None

result = dpnp_transpose(x1_desc, axes).get_pyobj()

return result

return call_origin(numpy.transpose, x1, axes=axes)
>>> import dpnp as dp
>>> a = dp.array([[1, 2], [3, 4]])
>>> a
array([[1, 2],
[3, 4]])
>>> dp.transpose(a)
array([[1, 3],
[2, 4]])
>>> a = dp.array([1, 2, 3, 4])
>>> a
array([1, 2, 3, 4])
>>> dp.transpose(a)
array([1, 2, 3, 4])
>>> a = dp.ones((1, 2, 3))
>>> dp.transpose(a, (1, 0, 2)).shape
(2, 1, 3)
>>> a = dp.ones((2, 3, 4, 5))
>>> dp.transpose(a).shape
(5, 4, 3, 2)
"""

if isinstance(a, dpnp_array):
array = a
elif isinstance(a, dpt.usm_ndarray):
array = dpnp_array._create_from_usm_ndarray(a.get_array())
else:
raise TypeError("An array must be any of supported type, but got {}".format(type(a)))

if axes is None:
return array.transpose()
return array.transpose(*axes)


def unique(x1, **kwargs):
Expand Down
3 changes: 1 addition & 2 deletions dpnp/dpnp_iface_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,7 @@ def cov(x1, y=None, rowvar=True, bias=False, ddof=None, fweights=None, aweights=
pass
else:
if not rowvar and x1.shape[0] != 1:
x1 = x1.get_array() if isinstance(x1, dpnp_array) else x1
x1 = dpnp_array._create_from_usm_ndarray(x1.mT)
x1 = x1.T

if not x1.dtype in (dpnp.float32, dpnp.float64):
x1 = dpnp.astype(x1, dpnp.default_float_type(sycl_queue=x1.sycl_queue))
Expand Down
4 changes: 0 additions & 4 deletions tests/skipped_tests.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,6 @@ tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAn
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_astype_strides_swapped
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_astype_type_c_contiguous_no_copy
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_astype_type_f_contiguous_no_copy
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_transposed_fill
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_transposed_flatten
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_flatten
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_flatten_copied
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_isinstance_numpy_copy
Expand Down Expand Up @@ -834,7 +832,6 @@ tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_trunc
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all2
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_keepdims
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_transposed
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_transposed2
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_axes
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_axes2
Expand Down Expand Up @@ -883,7 +880,6 @@ tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_1
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_9_{axis=0, func='nanprod', keepdims=True, shape=(2, 3, 4), transpose_axes=False}::test_nansum_all
tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_9_{axis=0, func='nanprod', keepdims=True, shape=(2, 3, 4), transpose_axes=False}::test_nansum_axis_transposed
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all2
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_transposed2
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_axis
Expand Down
Loading

0 comments on commit b6cba98

Please sign in to comment.