Skip to content

Commit b6cba98

Browse files
committed
Rework transpose methods to use dpctl.tensor functions (#1389)
* Rework transpose methods to call dpctl.tensor functions * Applied review comments & added more tests
1 parent a9b9ffa commit b6cba98

11 files changed

+140
-166
lines changed

dpnp/backend/include/dpnp_iface_fptr.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,6 @@ enum class DPNPFuncName : size_t
360360
DPNP_FN_TANH, /**< Used in numpy.tanh() impl */
361361
DPNP_FN_TANH_EXT, /**< Used in numpy.tanh() impl, requires extra parameters */
362362
DPNP_FN_TRANSPOSE, /**< Used in numpy.transpose() impl */
363-
DPNP_FN_TRANSPOSE_EXT, /**< Used in numpy.transpose() impl, requires extra parameters */
364363
DPNP_FN_TRACE, /**< Used in numpy.trace() impl */
365364
DPNP_FN_TRACE_EXT, /**< Used in numpy.trace() impl, requires extra parameters */
366365
DPNP_FN_TRAPZ, /**< Used in numpy.trapz() impl */

dpnp/backend/kernels/dpnp_krnl_manipulation.cpp

+2-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//*****************************************************************************
2-
// Copyright (c) 2016-2020, Intel Corporation
2+
// Copyright (c) 2016-2023, Intel Corporation
33
// All rights reserved.
44
//
55
// Redistribution and use in source and binary forms, with or without
@@ -211,6 +211,7 @@ void dpnp_elemwise_transpose_c(void* array1_in,
211211
size,
212212
dep_event_vec_ref);
213213
DPCTLEvent_WaitAndThrow(event_ref);
214+
DPCTLEvent_Delete(event_ref);
214215
}
215216

216217
template <typename _DataType>
@@ -222,17 +223,6 @@ void (*dpnp_elemwise_transpose_default_c)(void*,
222223
void*,
223224
size_t) = dpnp_elemwise_transpose_c<_DataType>;
224225

225-
template <typename _DataType>
226-
DPCTLSyclEventRef (*dpnp_elemwise_transpose_ext_c)(DPCTLSyclQueueRef,
227-
void*,
228-
const shape_elem_type*,
229-
const shape_elem_type*,
230-
const shape_elem_type*,
231-
size_t,
232-
void*,
233-
size_t,
234-
const DPCTLEventVectorRef) = dpnp_elemwise_transpose_c<_DataType>;
235-
236226
void func_map_init_manipulation(func_map_t& fmap)
237227
{
238228
fmap[DPNPFuncName::DPNP_FN_REPEAT][eft_INT][eft_INT] = {eft_INT, (void*)dpnp_repeat_default_c<int32_t>};
@@ -253,15 +243,5 @@ void func_map_init_manipulation(func_map_t& fmap)
253243
(void*)dpnp_elemwise_transpose_default_c<float>};
254244
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE][eft_DBL][eft_DBL] = {eft_DBL,
255245
(void*)dpnp_elemwise_transpose_default_c<double>};
256-
257-
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_INT][eft_INT] = {eft_INT,
258-
(void*)dpnp_elemwise_transpose_ext_c<int32_t>};
259-
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_LNG][eft_LNG] = {eft_LNG,
260-
(void*)dpnp_elemwise_transpose_ext_c<int64_t>};
261-
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_FLT][eft_FLT] = {eft_FLT,
262-
(void*)dpnp_elemwise_transpose_ext_c<float>};
263-
fmap[DPNPFuncName::DPNP_FN_TRANSPOSE_EXT][eft_DBL][eft_DBL] = {eft_DBL,
264-
(void*)dpnp_elemwise_transpose_ext_c<double>};
265-
266246
return;
267247
}

dpnp/dpnp_algo/dpnp_algo.pxd

-2
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
338338
DPNP_FN_TRACE
339339
DPNP_FN_TRACE_EXT
340340
DPNP_FN_TRANSPOSE
341-
DPNP_FN_TRANSPOSE_EXT
342341
DPNP_FN_TRAPZ
343342
DPNP_FN_TRAPZ_EXT
344343
DPNP_FN_TRI
@@ -551,7 +550,6 @@ cpdef dpnp_descriptor dpnp_subtract(dpnp_descriptor x1_obj, dpnp_descriptor x2_o
551550
Array manipulation routines
552551
"""
553552
cpdef dpnp_descriptor dpnp_repeat(dpnp_descriptor array1, repeats, axes=*)
554-
cpdef dpnp_descriptor dpnp_transpose(dpnp_descriptor array1, axes=*)
555553

556554

557555
"""

dpnp/dpnp_algo/dpnp_algo_manipulation.pxi

-74
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,10 @@ __all__ += [
4242
"dpnp_expand_dims",
4343
"dpnp_repeat",
4444
"dpnp_reshape",
45-
"dpnp_transpose",
4645
]
4746

4847

4948
# C function pointer to the C library template functions
50-
ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_custom_elemwise_transpose_1in_1out_t)(c_dpctl.DPCTLSyclQueueRef,
51-
void * ,
52-
shape_elem_type * ,
53-
shape_elem_type * ,
54-
shape_elem_type * ,
55-
size_t,
56-
void * ,
57-
size_t,
58-
const c_dpctl.DPCTLEventVectorRef)
5949
ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_dpnp_repeat_t)(c_dpctl.DPCTLSyclQueueRef,
6050
const void *, void * , const size_t , const size_t,
6151
const c_dpctl.DPCTLEventVectorRef)
@@ -229,67 +219,3 @@ cpdef utils.dpnp_descriptor dpnp_reshape(utils.dpnp_descriptor array1, newshape,
229219
usm_type=array1_obj.usm_type,
230220
sycl_queue=array1_obj.sycl_queue),
231221
copy_when_nondefault_queue=False)
232-
233-
234-
cpdef utils.dpnp_descriptor dpnp_transpose(utils.dpnp_descriptor array1, axes=None):
235-
cdef shape_type_c input_shape = array1.shape
236-
cdef size_t input_shape_size = array1.ndim
237-
cdef shape_type_c result_shape = shape_type_c(input_shape_size, 1)
238-
239-
cdef shape_type_c permute_axes
240-
if axes is None:
241-
"""
242-
template to do transpose a tensor
243-
input_shape=[2, 3, 4]
244-
permute_axes=[2, 1, 0]
245-
after application `permute_axes` to `input_shape` result:
246-
result_shape=[4, 3, 2]
247-
248-
'do nothing' axes variable is `permute_axes=[0, 1, 2]`
249-
250-
test: pytest tests/third_party/cupy/manipulation_tests/test_transpose.py::TestTranspose::test_external_transpose_all
251-
"""
252-
permute_axes = list(reversed([i for i in range(input_shape_size)]))
253-
else:
254-
permute_axes = utils.normalize_axis(axes, input_shape_size)
255-
256-
for i in range(input_shape_size):
257-
""" construct output shape """
258-
result_shape[i] = input_shape[permute_axes[i]]
259-
260-
# convert string type names (array.dtype) to C enum DPNPFuncType
261-
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype)
262-
263-
# get the FPTR data structure
264-
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_TRANSPOSE_EXT, param1_type, param1_type)
265-
266-
array1_obj = array1.get_array()
267-
268-
# ceate result array with type given by FPTR data
269-
cdef utils.dpnp_descriptor result = utils.create_output_descriptor(result_shape,
270-
kernel_data.return_type,
271-
None,
272-
device=array1_obj.sycl_device,
273-
usm_type=array1_obj.usm_type,
274-
sycl_queue=array1_obj.sycl_queue)
275-
result_sycl_queue = result.get_array().sycl_queue
276-
277-
cdef c_dpctl.SyclQueue q = <c_dpctl.SyclQueue> result_sycl_queue
278-
cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref()
279-
280-
cdef fptr_custom_elemwise_transpose_1in_1out_t func = <fptr_custom_elemwise_transpose_1in_1out_t > kernel_data.ptr
281-
# call FPTR function
282-
cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref,
283-
array1.get_data(),
284-
input_shape.data(),
285-
result_shape.data(),
286-
permute_axes.data(),
287-
input_shape_size,
288-
result.get_data(),
289-
array1.size,
290-
NULL) # dep_events_ref
291-
292-
with nogil: c_dpctl.DPCTLEvent_WaitAndThrow(event_ref)
293-
c_dpctl.DPCTLEvent_Delete(event_ref)
294-
295-
return result

dpnp/dpnp_array.py

+54-14
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,8 @@ def get_array(self):
9999

100100
@property
101101
def T(self):
102-
"""Shape-reversed view of the array.
103-
104-
If ndim < 2, then this is just a reference to the array itself.
105-
106-
"""
107-
if self.ndim < 2:
108-
return self
109-
else:
110-
return dpnp.transpose(self)
102+
"""View of the transposed array."""
103+
return self.transpose()
111104

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

10261019
def transpose(self, *axes):
10271020
"""
1028-
Returns a view of the array with axes permuted.
1021+
Returns a view of the array with axes transposed.
10291022
1030-
.. seealso::
1031-
:obj:`dpnp.transpose` for full documentation,
1032-
:meth:`numpy.ndarray.reshape`
1023+
For full documentation refer to :obj:`numpy.ndarray.transpose`.
1024+
1025+
Returns
1026+
-------
1027+
y : dpnp.ndarray
1028+
View of the array with its axes suitably permuted.
1029+
1030+
See Also
1031+
--------
1032+
:obj:`dpnp.transpose` : Equivalent function.
1033+
:obj:`dpnp.ndarray.ndarray.T` : Array property returning the array transposed.
1034+
:obj:`dpnp.ndarray.reshape` : Give a new shape to an array without changing its data.
10331035
1036+
Examples
1037+
--------
1038+
>>> import dpnp as dp
1039+
>>> a = dp.array([[1, 2], [3, 4]])
1040+
>>> a
1041+
array([[1, 2],
1042+
[3, 4]])
1043+
>>> a.transpose()
1044+
array([[1, 3],
1045+
[2, 4]])
1046+
>>> a.transpose((1, 0))
1047+
array([[1, 3],
1048+
[2, 4]])
1049+
1050+
>>> a = dp.array([1, 2, 3, 4])
1051+
>>> a
1052+
array([1, 2, 3, 4])
1053+
>>> a.transpose()
1054+
array([1, 2, 3, 4])
1055+
10341056
"""
10351057

1036-
return dpnp.transpose(self, axes)
1058+
ndim = self.ndim
1059+
if ndim < 2:
1060+
return self
1061+
1062+
axes_len = len(axes)
1063+
if axes_len == 1 and isinstance(axes[0], tuple):
1064+
axes = axes[0]
1065+
1066+
res = self.__new__(dpnp_array)
1067+
if ndim == 2 and axes_len == 0:
1068+
res._array_obj = self._array_obj.T
1069+
else:
1070+
if len(axes) == 0 or axes[0] is None:
1071+
# self.transpose().shape == self.shape[::-1]
1072+
# self.transpose(None).shape == self.shape[::-1]
1073+
axes = tuple((ndim - x - 1) for x in range(ndim))
1074+
1075+
res._array_obj = dpt.permute_dims(self._array_obj, axes)
1076+
return res
10371077

10381078
def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
10391079
"""

dpnp/dpnp_iface_manipulation.py

+45-34
Original file line numberDiff line numberDiff line change
@@ -673,54 +673,65 @@ def swapaxes(x1, axis1, axis2):
673673
return call_origin(numpy.swapaxes, x1, axis1, axis2)
674674

675675

676-
def transpose(x1, axes=None):
676+
def transpose(a, axes=None):
677677
"""
678-
Reverse or permute the axes of an array; returns the modified array.
678+
Returns an array with axes transposed.
679679
680680
For full documentation refer to :obj:`numpy.transpose`.
681681
682+
Returns
683+
-------
684+
y : dpnp.ndarray
685+
`a` with its axes permuted. A view is returned whenever possible.
686+
682687
Limitations
683688
-----------
684-
Input array is supported as :obj:`dpnp.ndarray`.
685-
Otherwise the function will be executed sequentially on CPU.
686-
Value of the parameter ``axes`` likely to be replaced with ``None``.
687-
Input array data types are limited by supported DPNP :ref:`Data types`.
689+
Input array is supported as either :class:`dpnp.ndarray`
690+
or :class:`dpctl.tensor.usm_ndarray`.
688691
689692
See Also
690693
--------
694+
:obj:`dpnp.ndarray.transpose` : Equivalent method.
691695
:obj:`dpnp.moveaxis` : Move array axes to new positions.
692696
:obj:`dpnp.argsort` : Returns the indices that would sort an array.
693697
694698
Examples
695699
--------
696-
>>> import dpnp as np
697-
>>> x = np.arange(4).reshape((2,2))
698-
>>> x.shape
699-
(2, 2)
700-
>>> [i for i in x]
701-
[0, 1, 2, 3]
702-
>>> out = np.transpose(x)
703-
>>> out.shape
704-
(2, 2)
705-
>>> [i for i in out]
706-
[0, 2, 1, 3]
707-
708-
"""
709-
710-
x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False)
711-
if x1_desc:
712-
if axes is not None:
713-
if not any(axes):
714-
"""
715-
pytest tests/third_party/cupy/manipulation_tests/test_transpose.py
716-
"""
717-
axes = None
718-
719-
result = dpnp_transpose(x1_desc, axes).get_pyobj()
720-
721-
return result
722-
723-
return call_origin(numpy.transpose, x1, axes=axes)
700+
>>> import dpnp as dp
701+
>>> a = dp.array([[1, 2], [3, 4]])
702+
>>> a
703+
array([[1, 2],
704+
[3, 4]])
705+
>>> dp.transpose(a)
706+
array([[1, 3],
707+
[2, 4]])
708+
709+
>>> a = dp.array([1, 2, 3, 4])
710+
>>> a
711+
array([1, 2, 3, 4])
712+
>>> dp.transpose(a)
713+
array([1, 2, 3, 4])
714+
715+
>>> a = dp.ones((1, 2, 3))
716+
>>> dp.transpose(a, (1, 0, 2)).shape
717+
(2, 1, 3)
718+
719+
>>> a = dp.ones((2, 3, 4, 5))
720+
>>> dp.transpose(a).shape
721+
(5, 4, 3, 2)
722+
723+
"""
724+
725+
if isinstance(a, dpnp_array):
726+
array = a
727+
elif isinstance(a, dpt.usm_ndarray):
728+
array = dpnp_array._create_from_usm_ndarray(a.get_array())
729+
else:
730+
raise TypeError("An array must be any of supported type, but got {}".format(type(a)))
731+
732+
if axes is None:
733+
return array.transpose()
734+
return array.transpose(*axes)
724735

725736

726737
def unique(x1, **kwargs):

dpnp/dpnp_iface_statistics.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,7 @@ def cov(x1, y=None, rowvar=True, bias=False, ddof=None, fweights=None, aweights=
290290
pass
291291
else:
292292
if not rowvar and x1.shape[0] != 1:
293-
x1 = x1.get_array() if isinstance(x1, dpnp_array) else x1
294-
x1 = dpnp_array._create_from_usm_ndarray(x1.mT)
293+
x1 = x1.T
295294

296295
if not x1.dtype in (dpnp.float32, dpnp.float64):
297296
x1 = dpnp.astype(x1, dpnp.default_float_type(sycl_queue=x1.sycl_queue))

tests/skipped_tests.tbl

-4
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,6 @@ tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAn
232232
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_astype_strides_swapped
233233
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_astype_type_c_contiguous_no_copy
234234
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_astype_type_f_contiguous_no_copy
235-
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_transposed_fill
236-
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_transposed_flatten
237235
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_flatten
238236
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_flatten_copied
239237
tests/third_party/cupy/core_tests/test_ndarray_copy_and_view.py::TestArrayCopyAndView::test_isinstance_numpy_copy
@@ -834,7 +832,6 @@ tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_trunc
834832
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all
835833
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all2
836834
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_keepdims
837-
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_transposed
838835
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_transposed2
839836
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_axes
840837
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_axes2
@@ -883,7 +880,6 @@ tests/third_party/cupy/math_tests/test_sumprod.py::TestNansumNanprodLong_param_1
883880
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
884881
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
885882
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all2
886-
tests/third_party/cupy/math_tests/test_sumprod.py::TestSumprod::test_sum_all_transposed2
887883
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim
888884
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont
889885
tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_axis

0 commit comments

Comments
 (0)