diff --git a/dpnp/backend/extensions/ufunc/CMakeLists.txt b/dpnp/backend/extensions/ufunc/CMakeLists.txt index bc9262578227..9a3fa0fa1823 100644 --- a/dpnp/backend/extensions/ufunc/CMakeLists.txt +++ b/dpnp/backend/extensions/ufunc/CMakeLists.txt @@ -25,6 +25,7 @@ set(_elementwise_sources ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/common.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/degrees.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/fabs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/fmax.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/fmin.cpp diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp b/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp index bd59c2b61185..ae2735208535 100644 --- a/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp @@ -25,6 +25,7 @@ #include +#include "degrees.hpp" #include "fabs.hpp" #include "fmax.hpp" #include "fmin.hpp" @@ -40,6 +41,7 @@ namespace dpnp::extensions::ufunc */ void init_elementwise_functions(py::module_ m) { + init_degrees(m); init_fabs(m); init_fmax(m); init_fmin(m); diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/degrees.cpp b/dpnp/backend/extensions/ufunc/elementwise_functions/degrees.cpp new file mode 100644 index 000000000000..bb5c46c2db98 --- /dev/null +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/degrees.cpp @@ -0,0 +1,127 @@ +//***************************************************************************** +// Copyright (c) 2024, Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//***************************************************************************** + +#include + +#include "dpctl4pybind11.hpp" + +#include "degrees.hpp" +#include "kernels/elementwise_functions/degrees.hpp" +#include "populate.hpp" + +// include a local copy of elementwise common header from dpctl tensor: +// dpctl/tensor/libtensor/source/elementwise_functions/elementwise_functions.hpp +// TODO: replace by including dpctl header once available +#include "../../elementwise_functions/elementwise_functions.hpp" + +// dpctl tensor headers +#include "kernels/elementwise_functions/common.hpp" +#include "utils/type_dispatch.hpp" + +namespace dpnp::extensions::ufunc +{ +namespace py = pybind11; +namespace py_int = dpnp::extensions::py_internal; + +namespace impl +{ +namespace ew_cmn_ns = dpctl::tensor::kernels::elementwise_common; +namespace td_ns = dpctl::tensor::type_dispatch; + +/** + * @brief A factory to define pairs of supported types for which + * sycl::degrees function is available. + * + * @tparam T Type of input vector `a` and of result vector `y`. + */ +template +struct OutputType +{ + using value_type = + typename std::disjunction, + td_ns::TypeMapResultEntry, + td_ns::TypeMapResultEntry, + td_ns::DefaultResultEntry>::result_type; +}; + +using dpnp::kernels::degrees::DegreesFunctor; + +template +using ContigFunctor = ew_cmn_ns::UnaryContigFunctor, + vec_sz, + n_vecs, + enable_sg_loadstore>; + +template +using StridedFunctor = ew_cmn_ns:: + UnaryStridedFunctor>; + +using ew_cmn_ns::unary_contig_impl_fn_ptr_t; +using ew_cmn_ns::unary_strided_impl_fn_ptr_t; + +static unary_contig_impl_fn_ptr_t + degrees_contig_dispatch_vector[td_ns::num_types]; +static int degrees_output_typeid_vector[td_ns::num_types]; +static unary_strided_impl_fn_ptr_t + degrees_strided_dispatch_vector[td_ns::num_types]; + +MACRO_POPULATE_DISPATCH_VECTORS(degrees); +} // namespace impl + +void init_degrees(py::module_ m) +{ + using arrayT = dpctl::tensor::usm_ndarray; + using event_vecT = std::vector; + { + impl::populate_degrees_dispatch_vectors(); + using impl::degrees_contig_dispatch_vector; + using impl::degrees_output_typeid_vector; + using impl::degrees_strided_dispatch_vector; + + auto degrees_pyapi = [&](const arrayT &src, const arrayT &dst, + sycl::queue &exec_q, + const event_vecT &depends = {}) { + return py_int::py_unary_ufunc(src, dst, exec_q, depends, + degrees_output_typeid_vector, + degrees_contig_dispatch_vector, + degrees_strided_dispatch_vector); + }; + m.def("_degrees", degrees_pyapi, "", py::arg("src"), py::arg("dst"), + py::arg("sycl_queue"), py::arg("depends") = py::list()); + + auto degrees_result_type_pyapi = [&](const py::dtype &dtype) { + return py_int::py_unary_ufunc_result_type( + dtype, degrees_output_typeid_vector); + }; + m.def("_degrees_result_type", degrees_result_type_pyapi); + } +} +} // namespace dpnp::extensions::ufunc diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/degrees.hpp b/dpnp/backend/extensions/ufunc/elementwise_functions/degrees.hpp new file mode 100644 index 000000000000..7e234ecb5061 --- /dev/null +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/degrees.hpp @@ -0,0 +1,35 @@ +//***************************************************************************** +// Copyright (c) 2024, Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//***************************************************************************** + +#pragma once + +#include + +namespace py = pybind11; + +namespace dpnp::extensions::ufunc +{ +void init_degrees(py::module_ m); +} // namespace dpnp::extensions::ufunc diff --git a/dpnp/backend/include/dpnp_gen_1arg_2type_tbl.hpp b/dpnp/backend/include/dpnp_gen_1arg_2type_tbl.hpp index a0d2b456f78c..5efb489ba366 100644 --- a/dpnp/backend/include/dpnp_gen_1arg_2type_tbl.hpp +++ b/dpnp/backend/include/dpnp_gen_1arg_2type_tbl.hpp @@ -86,9 +86,6 @@ #endif MACRO_1ARG_2TYPES_OP(dpnp_copyto_c, input_elem, q.submit(kernel_func)) -MACRO_1ARG_2TYPES_OP(dpnp_degrees_c, - sycl::degrees(input_elem), - q.submit(kernel_func)) MACRO_1ARG_2TYPES_OP(dpnp_sqrt_c, sycl::sqrt(input_elem), oneapi::mkl::vm::sqrt(q, input1_size, input1_data, result)) diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 9e5cc2b7b9b5..47d913e51bcc 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -78,9 +78,6 @@ enum class DPNPFuncName : size_t parameters */ DPNP_FN_COUNT_NONZERO, /**< Used in numpy.count_nonzero() impl */ DPNP_FN_COV, /**< Used in numpy.cov() impl */ - DPNP_FN_DEGREES, /**< Used in numpy.degrees() impl */ - DPNP_FN_DEGREES_EXT, /**< Used in numpy.degrees() impl, requires extra - parameters */ DPNP_FN_DOT, /**< Used in numpy.dot() impl */ DPNP_FN_DOT_EXT, /**< Used in numpy.dot() impl, requires extra parameters */ DPNP_FN_EDIFF1D, /**< Used in numpy.ediff1d() impl */ diff --git a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp index a1b6dbed3c41..4a02c1dfe43c 100644 --- a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp @@ -307,36 +307,6 @@ static void func_map_init_elemwise_1arg_2type(func_map_t &fmap) fmap[DPNPFuncName::DPNP_FN_COPYTO_EXT][eft_FLT][eft_FLT] = { eft_FLT, (void *)dpnp_copyto_c_ext}; - fmap[DPNPFuncName::DPNP_FN_DEGREES][eft_INT][eft_INT] = { - eft_DBL, (void *)dpnp_degrees_c_default}; - fmap[DPNPFuncName::DPNP_FN_DEGREES][eft_LNG][eft_LNG] = { - eft_DBL, (void *)dpnp_degrees_c_default}; - fmap[DPNPFuncName::DPNP_FN_DEGREES][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_degrees_c_default}; - fmap[DPNPFuncName::DPNP_FN_DEGREES][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_degrees_c_default}; - - fmap[DPNPFuncName::DPNP_FN_DEGREES_EXT][eft_INT][eft_INT] = { - get_default_floating_type(), - (void *)dpnp_degrees_c_ext< - int32_t, func_type_map_t::find_type>, - get_default_floating_type(), - (void *)dpnp_degrees_c_ext< - int32_t, func_type_map_t::find_type< - get_default_floating_type()>>}; - fmap[DPNPFuncName::DPNP_FN_DEGREES_EXT][eft_LNG][eft_LNG] = { - get_default_floating_type(), - (void *)dpnp_degrees_c_ext< - int64_t, func_type_map_t::find_type>, - get_default_floating_type(), - (void *)dpnp_degrees_c_ext< - int64_t, func_type_map_t::find_type< - get_default_floating_type()>>}; - fmap[DPNPFuncName::DPNP_FN_DEGREES_EXT][eft_FLT][eft_FLT] = { - eft_FLT, (void *)dpnp_degrees_c_ext}; - fmap[DPNPFuncName::DPNP_FN_DEGREES_EXT][eft_DBL][eft_DBL] = { - eft_DBL, (void *)dpnp_degrees_c_ext}; - fmap[DPNPFuncName::DPNP_FN_SQRT][eft_INT][eft_INT] = { eft_DBL, (void *)dpnp_sqrt_c_default}; fmap[DPNPFuncName::DPNP_FN_SQRT][eft_LNG][eft_LNG] = { diff --git a/dpnp/backend/kernels/elementwise_functions/degrees.hpp b/dpnp/backend/kernels/elementwise_functions/degrees.hpp new file mode 100644 index 000000000000..b8f37e362bcb --- /dev/null +++ b/dpnp/backend/kernels/elementwise_functions/degrees.hpp @@ -0,0 +1,55 @@ +//***************************************************************************** +// Copyright (c) 2024, Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +//***************************************************************************** + +#pragma once + +#include + +namespace dpnp::kernels::degrees +{ +template +struct DegreesFunctor +{ + // is function constant for given argT + using is_constant = typename std::false_type; + // constant value, if constant + // constexpr resT constant_value = resT{}; + // is function defined for sycl::vec + using supports_vec = typename std::true_type; + // do both argT and resT support subgroup store/load operation + using supports_sg_loadstore = typename std::true_type; + + resT operator()(const argT &x) const + { + return sycl::degrees(x); + } + + template + sycl::vec operator()(const sycl::vec &x) const + { + return sycl::degrees(x); + } +}; +} // namespace dpnp::kernels::degrees diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index 39487e6cb9e4..8a93d3c6fbc1 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -36,7 +36,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_ALLCLOSE_EXT DPNP_FN_CHOOSE_EXT DPNP_FN_CORRELATE_EXT - DPNP_FN_DEGREES_EXT DPNP_FN_EDIFF1D_EXT DPNP_FN_ERF_EXT DPNP_FN_FFT_FFT_EXT @@ -165,9 +164,3 @@ Logic functions """ cpdef dpnp_descriptor dpnp_isclose(dpnp_descriptor input1, dpnp_descriptor input2, double rtol=*, double atol=*, cpp_bool equal_nan=*) - - -""" -Trigonometric functions -""" -cpdef dpnp_descriptor dpnp_degrees(dpnp_descriptor array1) diff --git a/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi b/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi index 69586644937b..0dad17c154b7 100644 --- a/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi @@ -36,15 +36,10 @@ and the rest of the library # NO IMPORTs here. All imports must be placed into main "dpnp_algo.pyx" file __all__ += [ - 'dpnp_degrees', 'dpnp_unwrap' ] -cpdef utils.dpnp_descriptor dpnp_degrees(utils.dpnp_descriptor x1): - return call_fptr_1in_1out_strides(DPNP_FN_DEGREES_EXT, x1) - - cpdef utils.dpnp_descriptor dpnp_unwrap(utils.dpnp_descriptor array1): result_type = dpnp.float64 diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index b9c147707464..fdceca572bca 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -53,7 +53,6 @@ import dpnp.backend.extensions.vm._vm_impl as vmi from .dpnp_algo import ( - dpnp_degrees, dpnp_unwrap, ) from .dpnp_algo.dpnp_elementwise_common import DPNPBinaryFunc, DPNPUnaryFunc @@ -803,7 +802,7 @@ def cumlogsumexp( Notes ----- -:obj:`dpnp.deg2rad(x)` is ``x * pi / 180``. +dpnp.deg2rad(x) is ``x * pi / 180``. Examples -------- @@ -821,38 +820,62 @@ def cumlogsumexp( ) -def degrees(x1, **kwargs): - """ - Convert angles from radians to degrees. +_DEGREES_DOCSTRING = """ +Convert angles from radians to degrees. - For full documentation refer to :obj:`numpy.degrees`. +For full documentation refer to :obj:`numpy.degrees`. - Limitations - ----------- - Input array is supported as :obj:`dpnp.ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. +Parameters +---------- +x : {dpnp.ndarray, usm_ndarray} + Input array in radians. +out : {None, dpnp.ndarray, usm_ndarray}, optional + Output array to populate. + Array must have the correct shape and the expected data type. + Default: ``None``. +order : {"C", "F", "A", "K"}, optional + Memory layout of the newly output array, if parameter `out` is ``None``. + Default: ``"K"``. - .. seealso:: :obj:`dpnp.rad2deg` convert angles from radians to degrees. +Returns +------- +out : dpnp.ndarray + The corresponding degree values. The data type of the returned array is + determined by the Type Promotion Rules. - Examples - -------- - >>> import dpnp as np - >>> rad = np.arange(6.) * np.pi/6 - >>> out = np.degrees(rad) - >>> [i for i in out] - [0.0, 30.0, 60.0, 90.0, 120.0, 150.0] +Limitations +----------- +Parameters `where` and `subok` are supported with their default values. +Keyword argument `kwargs` is currently unsupported. +Otherwise ``NotImplementedError`` exception will be raised. - """ +See Also +-------- +:obj:`dpnp.rad2deg` : Equivalent function. - x1_desc = dpnp.get_dpnp_descriptor( - x1, copy_when_strides=False, copy_when_nondefault_queue=False - ) - if kwargs: - pass - elif x1_desc: - return dpnp_degrees(x1_desc).get_pyobj() +Examples +-------- +>>> import dpnp as np +>>> rad = np.arange(12.) * np.pi/6 - return call_origin(numpy.degrees, x1, **kwargs) +Convert a radian array to degrees: + +>>> np.degrees(rad) +array([ 0., 30., 60., 90., 120., 150., 180., 210., 240., 270., 300., + 330.]) + +>>> out = np.zeros_like(rad) +>>> r = np.degrees(rad, out) +>>> np.all(r == out) +array(True) +""" + +degrees = DPNPUnaryFunc( + "degrees", + ufi._degrees_result_type, + ufi._degrees, + _DEGREES_DOCSTRING, +) _EXP_DOCSTRING = """ @@ -1474,6 +1497,120 @@ def logsumexp(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ) +_RAD2DEG_DOCSTRING = """ +Convert angles from radians to degrees. + +For full documentation refer to :obj:`numpy.rad2deg`. + +Parameters +---------- +x : {dpnp.ndarray, usm_ndarray} + Angle in radians. +out : {None, dpnp.ndarray, usm_ndarray}, optional + Output array to populate. + Array must have the correct shape and the expected data type. + Default: ``None``. +order : {"C", "F", "A", "K"}, optional + Memory layout of the newly output array, if parameter `out` is ``None``. + Default: ``"K"``. + +Returns +------- +out : dpnp.ndarray + The corresponding angle in degrees. The data type of the returned array is + determined by the Type Promotion Rules. + +Limitations +----------- +Parameters `where` and `subok` are supported with their default values. +Keyword argument `kwargs` is currently unsupported. +Otherwise ``NotImplementedError`` exception will be raised. + +See Also +-------- +:obj:`dpnp.deg2rad` : Convert angles from degrees to radians. +:obj:`dpnp.unwrap` : Remove large jumps in angle by wrapping. +:obj:`dpnp.degrees` : Equivalent function. + +Notes +----- +dpnp.rad2deg(x) is ``180 * x / pi``. + +Examples +-------- +>>> import dpnp as np +>>> x = np.array(np.pi / 2) +>>> np.rad2deg(x) +array(90.) +""" + +rad2deg = DPNPUnaryFunc( + "rad2deg", + ufi._degrees_result_type, + ufi._degrees, + _RAD2DEG_DOCSTRING, +) + + +_RADIANS_DOCSTRING = """ +Convert angles from degrees to radians. + +For full documentation refer to :obj:`numpy.radians`. + +Parameters +---------- +x : {dpnp.ndarray, usm_ndarray} + Input array in degrees. +out : {None, dpnp.ndarray, usm_ndarray}, optional + Output array to populate. + Array must have the correct shape and the expected data type. + Default: ``None``. +order : {"C", "F", "A", "K"}, optional + Memory layout of the newly output array, if parameter `out` is ``None``. + Default: ``"K"``. + +Returns +------- +out : dpnp.ndarray + The corresponding radian values. The data type of the returned array is + determined by the Type Promotion Rules. + +Limitations +----------- +Parameters `where` and `subok` are supported with their default values. +Keyword argument `kwargs` is currently unsupported. +Otherwise ``NotImplementedError`` exception will be raised. + +See Also +-------- +:obj:`dpnp.deg2rad` : Equivalent function. + +Examples +-------- +>>> import dpnp as np +>>> deg = np.arange(12.) * 30. + +Convert a degree array to radians: + +>>> np.radians(deg) +array([0. , 0.52359878, 1.04719755, 1.57079633, 2.0943951 , + 2.61799388, 3.14159265, 3.66519143, 4.1887902 , 4.71238898, + 5.23598776, 5.75958653]) + +>>> out = np.zeros_like(deg) +>>> ret = np.radians(deg, out) +>>> ret is out +True +""" + +radians = DPNPUnaryFunc( + "radians", + ufi._radians_result_type, + ufi._radians, + _RADIANS_DOCSTRING, +) + + _RECIPROCAL_DOCSTRING = """ Computes the reciprocal square-root for each element `x_i` for input array `x`. @@ -1656,85 +1793,6 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ) -def rad2deg(x1): - """ - Convert angles from radians to degrees. - - For full documentation refer to :obj:`numpy.rad2deg`. - - See Also - -------- - :obj:`dpnp.deg2rad` : Convert angles from degrees to radians. - :obj:`dpnp.unwrap` : Remove large jumps in angle by wrapping. - - Notes - ----- - This function works exactly the same as :obj:`dpnp.degrees`. - - """ - - return degrees(x1) - - -_RADIANS_DOCSTRING = """ -Convert angles from degrees to radians. - -For full documentation refer to :obj:`numpy.radians`. - -Parameters ----------- -x : {dpnp.ndarray, usm_ndarray} - Input array in degrees. -out : {None, dpnp.ndarray, usm_ndarray}, optional - Output array to populate. - Array must have the correct shape and the expected data type. - Default: ``None``. -order : {"C", "F", "A", "K"}, optional - Memory layout of the newly output array, if parameter `out` is ``None``. - Default: ``"K"``. - -Returns -------- -out : dpnp.ndarray - The corresponding radian values. The data type of the returned array is - determined by the Type Promotion Rules. - -Limitations ------------ -Parameters `where` and `subok` are supported with their default values. -Keyword argument `kwargs` is currently unsupported. -Otherwise ``NotImplementedError`` exception will be raised. - -See Also --------- -:obj:`dpnp.deg2rad` : Equivalent function. - -Examples --------- ->>> import dpnp as np ->>> deg = np.arange(12.) * 30. - -Convert a degree array to radians: - ->>> np.radians(deg) -array([0. , 0.52359878, 1.04719755, 1.57079633, 2.0943951 , - 2.61799388, 3.14159265, 3.66519143, 4.1887902 , 4.71238898, - 5.23598776, 5.75958653]) - ->>> out = np.zeros_like(deg) ->>> ret = np.radians(deg, out) ->>> ret is out -True -""" - -radians = DPNPUnaryFunc( - "radians", - ufi._radians_result_type, - ufi._radians, - _RADIANS_DOCSTRING, -) - - _SIN_DOCSTRING = """ Computes sine for each element `x_i` of input array `x`. diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 976a1f34c748..b5ed7f8369de 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -35,8 +35,6 @@ tests/third_party/cupy/fft_tests/test_fft.py::TestFftn_param_23_{axes=None, norm tests/third_party/intel/test_zero_copy_test1.py::test_dpnp_interaction_with_dpctl_memory -tests/test_strides.py::test_strides_1arg[(10,)-None-degrees] - tests/test_umath.py::test_umaths[('divmod', 'ii')] tests/test_umath.py::test_umaths[('divmod', 'll')] tests/test_umath.py::test_umaths[('divmod', 'ff')] diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 418b51bacc8d..52cdeeb129e8 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -414,6 +414,7 @@ def test_meshgrid(device): pytest.param("count_nonzero", [3, 0, 2, -1.2]), pytest.param("cumprod", [[1, 2, 3], [4, 5, 6]]), pytest.param("cumsum", [[1, 2, 3], [4, 5, 6]]), + pytest.param("degrees", [numpy.pi, numpy.pi / 2, 0]), pytest.param("diagonal", [[[1, 2], [3, 4]]]), pytest.param("diff", [1.0, 2.0, 4.0, 7.0, 0.0]), pytest.param("ediff1d", [1.0, 2.0, 4.0, 7.0, 0.0]), diff --git a/tests/test_umath.py b/tests/test_umath.py index d396fc9ae54e..e130cb9c7a45 100644 --- a/tests/test_umath.py +++ b/tests/test_umath.py @@ -11,6 +11,7 @@ assert_dtype_allclose, get_all_dtypes, get_float_complex_dtypes, + get_float_dtypes, has_support_aspect16, has_support_aspect64, ) @@ -279,6 +280,37 @@ def test_invalid_shape(self, shape): dpnp.copysign(dp_array, dp_array, out=dp_out) +class TestDegrees: + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_none=True, no_complex=True) + ) + def test_basic(self, dtype): + a = numpy.array([numpy.pi, -0.5 * numpy.pi], dtype=dtype) + ia = dpnp.array(a) + + result = dpnp.degrees(ia) + expected = numpy.degrees(a) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_nan_infs(self, dtype): + a = numpy.array([numpy.nan, -numpy.inf, numpy.inf], dtype=dtype) + ia = dpnp.array(a) + + result = dpnp.degrees(ia) + expected = numpy.degrees(a) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_large_values(self, dtype): + a = numpy.arange(0, 10**5, 70, dtype=dtype) * numpy.pi + ia = dpnp.array(a) + + result = dpnp.degrees(ia) + expected = numpy.degrees(a) + assert_dtype_allclose(result, expected) + + class TestLogaddexp: @pytest.mark.parametrize("dtype", get_all_dtypes(no_complex=True)) def test_logaddexp(self, dtype): @@ -319,7 +351,7 @@ class TestRadians: @pytest.mark.parametrize( "dtype", get_all_dtypes(no_none=True, no_complex=True) ) - def test_radians(self, dtype): + def test_basic(self, dtype): a = numpy.array([180.0, -90.0], dtype=dtype) ia = dpnp.array(a) @@ -327,6 +359,24 @@ def test_radians(self, dtype): expected = numpy.radians(a) assert_dtype_allclose(result, expected) + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_nan_infs(self, dtype): + a = numpy.array([numpy.nan, -numpy.inf, numpy.inf], dtype=dtype) + ia = dpnp.array(a) + + result = dpnp.radians(ia) + expected = numpy.radians(a) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_large_values(self, dtype): + a = numpy.arange(0, 10**5, 70, dtype=dtype) + ia = dpnp.array(a) + + result = dpnp.radians(ia) + expected = numpy.radians(a) + assert_dtype_allclose(result, expected) + class TestReciprocal: @pytest.mark.usefixtures("suppress_divide_numpy_warnings") diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index d53377b307f2..8d66d1df7005 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -547,6 +547,7 @@ def test_norm(usm_type, ord, axis): pytest.param("cumlogsumexp", [1.0, 2.0, 4.0, 7.0]), pytest.param("cumprod", [[1, 2, 3], [4, 5, 6]]), pytest.param("cumsum", [[1, 2, 3], [4, 5, 6]]), + pytest.param("degrees", [numpy.pi, numpy.pi / 2, 0]), pytest.param("diagonal", [[[1, 2], [3, 4]]]), pytest.param("diff", [1.0, 2.0, 4.0, 7.0, 0.0]), pytest.param("exp", [1.0, 2.0, 4.0, 7.0]),