Skip to content

Commit

Permalink
implement dpnp.max and dpnp.min using dpctl.tensor functions (#1602)
Browse files Browse the repository at this point in the history
* implement dpnp.max and dpnp.min using dpctl.tensor functions

* address comments

* fix a few issues

* fix doc-string

* add axis==None condition for zero-size array

* add new tests to improve coverage

* update tests to reduce duplication
  • Loading branch information
vtavana authored Nov 8, 2023
1 parent db127d4 commit 79cb518
Show file tree
Hide file tree
Showing 15 changed files with 318 additions and 347 deletions.
1 change: 1 addition & 0 deletions .github/workflows/conda-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ env:
# TODO: to add test_arraymanipulation.py back to the scope once crash on Windows is gone
TEST_SCOPE: >-
test_arraycreation.py
test_amin_amax.py
test_dot.py
test_dparray.py
test_copy.py
Expand Down
26 changes: 12 additions & 14 deletions dpnp/backend/include/dpnp_iface_fptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,20 +212,18 @@ enum class DPNPFuncName : size_t
DPNP_FN_MATRIX_RANK_EXT, /**< Used in numpy.linalg.matrix_rank() impl,
requires extra parameters */
DPNP_FN_MAX, /**< Used in numpy.max() impl */
DPNP_FN_MAX_EXT, /**< Used in numpy.max() impl, requires extra parameters */
DPNP_FN_MAXIMUM, /**< Used in numpy.fmax() impl */
DPNP_FN_MAXIMUM_EXT, /**< Used in numpy.fmax() impl , requires extra
parameters */
DPNP_FN_MEAN, /**< Used in numpy.mean() impl */
DPNP_FN_MEDIAN, /**< Used in numpy.median() impl */
DPNP_FN_MEDIAN_EXT, /**< Used in numpy.median() impl, requires extra
parameters */
DPNP_FN_MIN, /**< Used in numpy.min() impl */
DPNP_FN_MIN_EXT, /**< Used in numpy.min() impl, requires extra parameters */
DPNP_FN_MINIMUM, /**< Used in numpy.fmin() impl */
DPNP_FN_MINIMUM_EXT, /**< Used in numpy.fmax() impl, requires extra
parameters */
DPNP_FN_MODF, /**< Used in numpy.modf() impl */
DPNP_FN_MAXIMUM, /**< Used in numpy.fmax() impl */
DPNP_FN_MAXIMUM_EXT, /**< Used in numpy.fmax() impl , requires extra
parameters */
DPNP_FN_MEAN, /**< Used in numpy.mean() impl */
DPNP_FN_MEDIAN, /**< Used in numpy.median() impl */
DPNP_FN_MEDIAN_EXT, /**< Used in numpy.median() impl, requires extra
parameters */
DPNP_FN_MIN, /**< Used in numpy.min() impl */
DPNP_FN_MINIMUM, /**< Used in numpy.fmin() impl */
DPNP_FN_MINIMUM_EXT, /**< Used in numpy.fmax() impl, requires extra
parameters */
DPNP_FN_MODF, /**< Used in numpy.modf() impl */
DPNP_FN_MODF_EXT, /**< Used in numpy.modf() impl, requires extra parameters
*/
DPNP_FN_MULTIPLY, /**< Used in numpy.multiply() impl */
Expand Down
42 changes: 0 additions & 42 deletions dpnp/backend/kernels/dpnp_krnl_statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,18 +503,6 @@ void (*dpnp_max_default_c)(void *,
const shape_elem_type *,
size_t) = dpnp_max_c<_DataType>;

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

template <typename _DataType, typename _ResultType>
DPCTLSyclEventRef dpnp_mean_c(DPCTLSyclQueueRef q_ref,
void *array1_in,
Expand Down Expand Up @@ -887,18 +875,6 @@ void (*dpnp_min_default_c)(void *,
const shape_elem_type *,
size_t) = dpnp_min_c<_DataType>;

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

template <typename _DataType>
DPCTLSyclEventRef dpnp_nanvar_c(DPCTLSyclQueueRef q_ref,
void *array1_in,
Expand Down Expand Up @@ -1283,15 +1259,6 @@ void func_map_init_statistics(func_map_t &fmap)
fmap[DPNPFuncName::DPNP_FN_MAX][eft_DBL][eft_DBL] = {
eft_DBL, (void *)dpnp_max_default_c<double>};

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

fmap[DPNPFuncName::DPNP_FN_MEAN][eft_INT][eft_INT] = {
eft_DBL, (void *)dpnp_mean_default_c<int32_t, double>};
fmap[DPNPFuncName::DPNP_FN_MEAN][eft_LNG][eft_LNG] = {
Expand Down Expand Up @@ -1340,15 +1307,6 @@ void func_map_init_statistics(func_map_t &fmap)
fmap[DPNPFuncName::DPNP_FN_MIN][eft_DBL][eft_DBL] = {
eft_DBL, (void *)dpnp_min_default_c<double>};

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

fmap[DPNPFuncName::DPNP_FN_NANVAR][eft_INT][eft_INT] = {
eft_INT, (void *)dpnp_nanvar_default_c<int32_t>};
fmap[DPNPFuncName::DPNP_FN_NANVAR][eft_LNG][eft_LNG] = {
Expand Down
10 changes: 0 additions & 10 deletions dpnp/dpnp_algo/dpnp_algo.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,10 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
DPNP_FN_MATMUL_EXT
DPNP_FN_MATRIX_RANK
DPNP_FN_MATRIX_RANK_EXT
DPNP_FN_MAX
DPNP_FN_MAX_EXT
DPNP_FN_MAXIMUM
DPNP_FN_MAXIMUM_EXT
DPNP_FN_MEDIAN
DPNP_FN_MEDIAN_EXT
DPNP_FN_MIN
DPNP_FN_MIN_EXT
DPNP_FN_MINIMUM
DPNP_FN_MINIMUM_EXT
DPNP_FN_MODF
Expand Down Expand Up @@ -369,12 +365,6 @@ Array manipulation routines
cpdef dpnp_descriptor dpnp_repeat(dpnp_descriptor array1, repeats, axes=*)


"""
Statistics functions
"""
cpdef dpnp_descriptor dpnp_min(dpnp_descriptor a, axis)


"""
Sorting functions
"""
Expand Down
171 changes: 0 additions & 171 deletions dpnp/dpnp_algo/dpnp_algo_statistics.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ and the rest of the library
__all__ += [
"dpnp_average",
"dpnp_correlate",
"dpnp_max",
"dpnp_median",
"dpnp_min",
"dpnp_nanvar",
"dpnp_std",
"dpnp_var",
Expand All @@ -64,16 +62,6 @@ ctypedef c_dpctl.DPCTLSyclEventRef(*custom_statistic_1in_1out_func_ptr_t)(c_dpct
void *, void * , shape_elem_type * , size_t,
shape_elem_type * , size_t,
const c_dpctl.DPCTLEventVectorRef)
ctypedef c_dpctl.DPCTLSyclEventRef(*custom_statistic_1in_1out_func_ptr_t_max)(c_dpctl.DPCTLSyclQueueRef,
void *,
void * ,
const size_t,
shape_elem_type * ,
size_t,
shape_elem_type * ,
size_t,
const c_dpctl.DPCTLEventVectorRef)


cdef utils.dpnp_descriptor call_fptr_custom_std_var_1in_1out(DPNPFuncName fptr_name, utils.dpnp_descriptor x1, ddof):
cdef shape_type_c x1_shape = x1.shape
Expand Down Expand Up @@ -177,86 +165,6 @@ cpdef utils.dpnp_descriptor dpnp_correlate(utils.dpnp_descriptor x1, utils.dpnp_
return result


cdef utils.dpnp_descriptor _dpnp_max(utils.dpnp_descriptor x1, _axis_, shape_type_c result_shape):
cdef shape_type_c x1_shape = x1.shape
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(x1.dtype)

cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_MAX_EXT, param1_type, param1_type)

x1_obj = x1.get_array()

# create 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=x1_obj.sycl_device,
usm_type=x1_obj.usm_type,
sycl_queue=x1_obj.sycl_queue)

result_sycl_queue = result.get_array().sycl_queue

cdef c_dpctl.SyclQueue q = <c_dpctl.SyclQueue> result_sycl_queue
cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref()

cdef custom_statistic_1in_1out_func_ptr_t_max func = <custom_statistic_1in_1out_func_ptr_t_max > kernel_data.ptr
cdef shape_type_c axis
cdef Py_ssize_t axis_size = 0
cdef shape_type_c axis_ = axis

if _axis_ is not None:
axis = _axis_
axis_.reserve(len(axis))
for shape_it in axis:
axis_.push_back(shape_it)
axis_size = len(axis)

cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref,
x1.get_data(),
result.get_data(),
result.size,
x1_shape.data(),
x1.ndim,
axis_.data(),
axis_size,
NULL) # dep_events_ref

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

return result


cpdef utils.dpnp_descriptor dpnp_max(utils.dpnp_descriptor x1, axis):
cdef shape_type_c x1_shape = x1.shape
cdef shape_type_c output_shape

if axis is None:
axis_ = axis
output_shape.push_back(1)
else:
if isinstance(axis, int):
if axis < 0:
axis_ = tuple([x1.ndim - axis])
else:
axis_ = tuple([axis])
else:
_axis_ = []
for i in range(len(axis)):
if axis[i] < 0:
_axis_.append(x1.ndim - axis[i])
else:
_axis_.append(axis[i])
axis_ = tuple(_axis_)

output_shape.resize(len(x1_shape) - len(axis_), 0)
ind = 0
for id, shape_axis in enumerate(x1_shape):
if id not in axis_:
output_shape[ind] = shape_axis
ind += 1

return _dpnp_max(x1, axis_, output_shape)

cpdef utils.dpnp_descriptor dpnp_median(utils.dpnp_descriptor array1):
cdef shape_type_c x1_shape = array1.shape
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype)
Expand Down Expand Up @@ -301,85 +209,6 @@ cpdef utils.dpnp_descriptor dpnp_median(utils.dpnp_descriptor array1):
return result


cpdef utils.dpnp_descriptor _dpnp_min(utils.dpnp_descriptor x1, _axis_, shape_type_c shape_output):
cdef shape_type_c x1_shape = x1.shape
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(x1.dtype)

cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_MIN_EXT, param1_type, param1_type)

x1_obj = x1.get_array()

cdef utils.dpnp_descriptor result = utils.create_output_descriptor(shape_output,
kernel_data.return_type,
None,
device=x1_obj.sycl_device,
usm_type=x1_obj.usm_type,
sycl_queue=x1_obj.sycl_queue)

result_sycl_queue = result.get_array().sycl_queue

cdef c_dpctl.SyclQueue q = <c_dpctl.SyclQueue> result_sycl_queue
cdef c_dpctl.DPCTLSyclQueueRef q_ref = q.get_queue_ref()

cdef custom_statistic_1in_1out_func_ptr_t_max func = <custom_statistic_1in_1out_func_ptr_t_max > kernel_data.ptr
cdef shape_type_c axis
cdef Py_ssize_t axis_size = 0
cdef shape_type_c axis_ = axis

if _axis_ is not None:
axis = _axis_
axis_.reserve(len(axis))
for shape_it in axis:
if shape_it < 0:
raise ValueError("DPNP algo::_dpnp_min(): Negative values in 'shape' are not allowed")
axis_.push_back(shape_it)
axis_size = len(axis)

cdef c_dpctl.DPCTLSyclEventRef event_ref = func(q_ref,
x1.get_data(),
result.get_data(),
result.size,
x1_shape.data(),
x1.ndim,
axis_.data(),
axis_size,
NULL) # dep_events_ref

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

return result


cpdef utils.dpnp_descriptor dpnp_min(utils.dpnp_descriptor x1, axis):
cdef shape_type_c x1_shape = x1.shape
cdef shape_type_c shape_output

if axis is None:
axis_ = axis
shape_output = (1,)
else:
if isinstance(axis, int):
if axis < 0:
axis_ = tuple([x1.ndim - axis])
else:
axis_ = tuple([axis])
else:
_axis_ = []
for i in range(len(axis)):
if axis[i] < 0:
_axis_.append(x1.ndim - axis[i])
else:
_axis_.append(axis[i])
axis_ = tuple(_axis_)

for id, shape_axis in enumerate(x1_shape):
if id not in axis_:
shape_output.push_back(shape_axis)

return _dpnp_min(x1, axis_, shape_output)


cpdef utils.dpnp_descriptor dpnp_nanvar(utils.dpnp_descriptor arr, ddof):
# dpnp_isnan does not support USM array as input in comparison to dpnp.isnan
cdef utils.dpnp_descriptor mask_arr = dpnp.get_dpnp_descriptor(dpnp.isnan(arr.get_pyobj()),
Expand Down
2 changes: 0 additions & 2 deletions dpnp/dpnp_algo/dpnp_elementwise_common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# cython: language_level=3
# distutils: language = c++
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2023, Intel Corporation
Expand Down
25 changes: 16 additions & 9 deletions dpnp/dpnp_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
# *****************************************************************************

import dpctl.tensor as dpt
import numpy

import dpnp

Expand Down Expand Up @@ -939,11 +938,15 @@ def max(
self,
axis=None,
out=None,
keepdims=numpy._NoValue,
initial=numpy._NoValue,
where=numpy._NoValue,
keepdims=False,
initial=None,
where=True,
):
"""Return the maximum along an axis."""
"""
Return the maximum along an axis.
Refer to :obj:`dpnp.max` for full documentation.
"""

return dpnp.max(self, axis, out, keepdims, initial, where)

Expand All @@ -956,11 +959,15 @@ def min(
self,
axis=None,
out=None,
keepdims=numpy._NoValue,
initial=numpy._NoValue,
where=numpy._NoValue,
keepdims=False,
initial=None,
where=True,
):
"""Return the minimum along a given axis."""
"""
Return the minimum along a given axis.
Refer to :obj:`dpnp.min` for full documentation.
"""

return dpnp.min(self, axis, out, keepdims, initial, where)

Expand Down
Loading

0 comments on commit 79cb518

Please sign in to comment.