diff --git a/dpnp/backend/extensions/ufunc/CMakeLists.txt b/dpnp/backend/extensions/ufunc/CMakeLists.txt index 7f9a240271b1..1d140b066584 100644 --- a/dpnp/backend/extensions/ufunc/CMakeLists.txt +++ b/dpnp/backend/extensions/ufunc/CMakeLists.txt @@ -26,6 +26,7 @@ set(_elementwise_sources ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/common.cpp ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/fabs.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/elementwise_functions/fmod.cpp ) set(python_module_name _ufunc_impl) diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp b/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp index 44173fc764fe..b915f9a299a8 100644 --- a/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/common.cpp @@ -26,6 +26,7 @@ #include #include "fabs.hpp" +#include "fmod.hpp" namespace py = pybind11; @@ -37,5 +38,6 @@ namespace dpnp::extensions::ufunc void init_elementwise_functions(py::module_ m) { init_fabs(m); + init_fmod(m); } } // namespace dpnp::extensions::ufunc diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/fmod.cpp b/dpnp/backend/extensions/ufunc/elementwise_functions/fmod.cpp new file mode 100644 index 000000000000..dbc215ec1f40 --- /dev/null +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/fmod.cpp @@ -0,0 +1,193 @@ +//***************************************************************************** +// 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 "fmod.hpp" +#include "kernels/elementwise_functions/fmod.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 py = pybind11; + +namespace dpnp::extensions::ufunc +{ +namespace ew_cmn_ns = dpctl::tensor::kernels::elementwise_common; +namespace py_int = dpnp::extensions::py_internal; +namespace td_ns = dpctl::tensor::type_dispatch; + +using ew_cmn_ns::unary_contig_impl_fn_ptr_t; +using ew_cmn_ns::unary_strided_impl_fn_ptr_t; + +namespace impl +{ +/** + * @brief A factory to define pairs of supported types for which + * sycl::fmod function is available. + * + * @tparam T1 Type of input vectors `a` + * @tparam T2 Type of input vectors `b` + */ +template +struct OutputType +{ + using value_type = typename std::disjunction< + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::DefaultResultEntry>::result_type; +}; + +using dpnp::kernels::fmod::FmodFunctor; + +template +using ContigFunctor = + ew_cmn_ns::BinaryContigFunctor, + vec_sz, + n_vecs, + enable_sg_loadstore>; + +template +using StridedFunctor = + ew_cmn_ns::BinaryStridedFunctor>; + +using ew_cmn_ns::binary_contig_impl_fn_ptr_t; +using ew_cmn_ns::binary_contig_matrix_contig_row_broadcast_impl_fn_ptr_t; +using ew_cmn_ns::binary_contig_row_contig_matrix_broadcast_impl_fn_ptr_t; +using ew_cmn_ns::binary_strided_impl_fn_ptr_t; + +static binary_contig_impl_fn_ptr_t fmod_contig_dispatch_table[td_ns::num_types] + [td_ns::num_types]; +static int fmod_output_typeid_table[td_ns::num_types][td_ns::num_types]; +static binary_strided_impl_fn_ptr_t + fmod_strided_dispatch_table[td_ns::num_types][td_ns::num_types]; + +MACRO_POPULATE_DISPATCH_TABLES(fmod); +} // namespace impl + +void init_fmod(py::module_ m) +{ + using arrayT = dpctl::tensor::usm_ndarray; + using event_vecT = std::vector; + { + impl::populate_fmod_dispatch_tables(); + using impl::fmod_contig_dispatch_table; + using impl::fmod_output_typeid_table; + using impl::fmod_strided_dispatch_table; + + auto fmod_pyapi = [&](const arrayT &src1, const arrayT &src2, + const arrayT &dst, sycl::queue &exec_q, + const event_vecT &depends = {}) { + return py_int::py_binary_ufunc( + src1, src2, dst, exec_q, depends, fmod_output_typeid_table, + fmod_contig_dispatch_table, fmod_strided_dispatch_table, + // no support of C-contig row with broadcasting in OneMKL + td_ns::NullPtrTable< + impl:: + binary_contig_matrix_contig_row_broadcast_impl_fn_ptr_t>{}, + td_ns::NullPtrTable< + impl:: + binary_contig_row_contig_matrix_broadcast_impl_fn_ptr_t>{}); + }; + m.def("_fmod", fmod_pyapi, "", py::arg("src1"), py::arg("src2"), + py::arg("dst"), py::arg("sycl_queue"), + py::arg("depends") = py::list()); + + auto fmod_result_type_pyapi = [&](const py::dtype &dtype1, + const py::dtype &dtype2) { + return py_int::py_binary_ufunc_result_type( + dtype1, dtype2, fmod_output_typeid_table); + }; + m.def("_fmod_result_type", fmod_result_type_pyapi); + } +} +} // namespace dpnp::extensions::ufunc diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/fmod.hpp b/dpnp/backend/extensions/ufunc/elementwise_functions/fmod.hpp new file mode 100644 index 000000000000..cfc61ba218f8 --- /dev/null +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/fmod.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_fmod(py::module_ m); +} // namespace dpnp::extensions::ufunc diff --git a/dpnp/backend/extensions/ufunc/elementwise_functions/populate.hpp b/dpnp/backend/extensions/ufunc/elementwise_functions/populate.hpp index 6261fcc08eb6..0b3cc8dac152 100644 --- a/dpnp/backend/extensions/ufunc/elementwise_functions/populate.hpp +++ b/dpnp/backend/extensions/ufunc/elementwise_functions/populate.hpp @@ -26,7 +26,8 @@ #pragma once /** - * @brief A macro used to define factories and a populating universal functions. + * @brief A macro used to define factories and a populating unary universal + * functions. */ #define MACRO_POPULATE_DISPATCH_VECTORS(__name__) \ template \ + class __name__##_contig_kernel; \ + \ + template \ + sycl::event __name__##_contig_impl( \ + sycl::queue &exec_q, size_t nelems, const char *arg1_p, \ + py::ssize_t arg1_offset, const char *arg2_p, py::ssize_t arg2_offset, \ + char *res_p, py::ssize_t res_offset, \ + const std::vector &depends = {}) \ + { \ + return ew_cmn_ns::binary_contig_impl( \ + exec_q, nelems, arg1_p, arg1_offset, arg2_p, arg2_offset, res_p, \ + res_offset, depends); \ + } \ + \ + template \ + struct ContigFactory \ + { \ + fnT get() \ + { \ + if constexpr (std::is_same_v< \ + typename OutputType::value_type, void>) \ + { \ + \ + fnT fn = nullptr; \ + return fn; \ + } \ + else { \ + fnT fn = __name__##_contig_impl; \ + return fn; \ + } \ + } \ + }; \ + \ + template \ + struct TypeMapFactory \ + { \ + std::enable_if_t::value, int> get() \ + { \ + using rT = typename OutputType::value_type; \ + return td_ns::GetTypeid{}.get(); \ + } \ + }; \ + \ + template \ + class __name__##_strided_kernel; \ + \ + template \ + sycl::event __name__##_strided_impl( \ + sycl::queue &exec_q, size_t nelems, int nd, \ + const py::ssize_t *shape_and_strides, const char *arg1_p, \ + py::ssize_t arg1_offset, const char *arg2_p, py::ssize_t arg2_offset, \ + char *res_p, py::ssize_t res_offset, \ + const std::vector &depends, \ + const std::vector &additional_depends) \ + { \ + return ew_cmn_ns::binary_strided_impl( \ + exec_q, nelems, nd, shape_and_strides, arg1_p, arg1_offset, \ + arg2_p, arg2_offset, res_p, res_offset, depends, \ + additional_depends); \ + } \ + \ + template \ + struct StridedFactory \ + { \ + fnT get() \ + { \ + if constexpr (std::is_same_v< \ + typename OutputType::value_type, void>) \ + { \ + fnT fn = nullptr; \ + return fn; \ + } \ + else { \ + fnT fn = __name__##_strided_impl; \ + return fn; \ + } \ + } \ + }; \ + \ + void populate_##__name__##_dispatch_tables(void) \ + { \ + td_ns::DispatchTableBuilder \ + dvb1; \ + dvb1.populate_dispatch_table(__name__##_contig_dispatch_table); \ + \ + td_ns::DispatchTableBuilder \ + dvb2; \ + dvb2.populate_dispatch_table(__name__##_strided_dispatch_table); \ + \ + td_ns::DispatchTableBuilder \ + dvb3; \ + dvb3.populate_dispatch_table(__name__##_output_typeid_table); \ + }; diff --git a/dpnp/backend/extensions/vm/CMakeLists.txt b/dpnp/backend/extensions/vm/CMakeLists.txt index ba1e46ea0ed8..de6262581f59 100644 --- a/dpnp/backend/extensions/vm/CMakeLists.txt +++ b/dpnp/backend/extensions/vm/CMakeLists.txt @@ -43,6 +43,7 @@ set(_elementwise_sources ${CMAKE_CURRENT_SOURCE_DIR}/exp2.cpp ${CMAKE_CURRENT_SOURCE_DIR}/expm1.cpp ${CMAKE_CURRENT_SOURCE_DIR}/floor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fmod.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hypot.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ln.cpp ${CMAKE_CURRENT_SOURCE_DIR}/log10.cpp diff --git a/dpnp/backend/extensions/vm/fmod.cpp b/dpnp/backend/extensions/vm/fmod.cpp new file mode 100644 index 000000000000..e985492de047 --- /dev/null +++ b/dpnp/backend/extensions/vm/fmod.cpp @@ -0,0 +1,161 @@ +//***************************************************************************** +// 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 + +#include "dpctl4pybind11.hpp" + +#include "common.hpp" +#include "fmod.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" +#include "utils/type_utils.hpp" + +namespace dpnp::extensions::vm +{ +namespace ew_cmn_ns = dpctl::tensor::kernels::elementwise_common; +namespace py = pybind11; +namespace py_int = dpnp::extensions::py_internal; +namespace td_ns = dpctl::tensor::type_dispatch; +namespace tu_ns = dpctl::tensor::type_utils; + +namespace impl +{ +// OneMKL namespace with VM functions +namespace mkl_vm = oneapi::mkl::vm; + +/** + * @brief A factory to define pairs of supported types for which + * MKL VM library provides support in oneapi::mkl::vm::fmod function. + * + * @tparam T Type of input vectors `a` and `b` and of result vector `y`. + */ +template +struct OutputType +{ + using value_type = typename std::disjunction< + td_ns::BinaryTypeMapResultEntry, + td_ns::BinaryTypeMapResultEntry, + td_ns::DefaultResultEntry>::result_type; +}; + +template +static sycl::event fmod_contig_impl(sycl::queue &exec_q, + std::size_t in_n, + const char *in_a, + py::ssize_t a_offset, + const char *in_b, + py::ssize_t b_offset, + char *out_y, + py::ssize_t out_offset, + const std::vector &depends) +{ + tu_ns::validate_type_for_device(exec_q); + tu_ns::validate_type_for_device(exec_q); + + if ((a_offset != 0) || (b_offset != 0) || (out_offset != 0)) { + throw std::runtime_error("Arrays offsets have to be equals to 0"); + } + + std::int64_t n = static_cast(in_n); + const T1 *a = reinterpret_cast(in_a); + const T2 *b = reinterpret_cast(in_b); + + using resTy = typename OutputType::value_type; + resTy *y = reinterpret_cast(out_y); + + return mkl_vm::fmod(exec_q, + n, // number of elements to be calculated + a, // pointer `a` containing 1st input vector of size n + b, // pointer `b` containing 2nd input vector of size n + y, // pointer `y` to the output vector of size n + depends); +} + +using ew_cmn_ns::binary_contig_impl_fn_ptr_t; +using ew_cmn_ns::binary_contig_matrix_contig_row_broadcast_impl_fn_ptr_t; +using ew_cmn_ns::binary_contig_row_contig_matrix_broadcast_impl_fn_ptr_t; +using ew_cmn_ns::binary_strided_impl_fn_ptr_t; + +static int output_typeid_vector[td_ns::num_types][td_ns::num_types]; +static binary_contig_impl_fn_ptr_t contig_dispatch_vector[td_ns::num_types] + [td_ns::num_types]; + +MACRO_POPULATE_DISPATCH_TABLES(fmod); +} // namespace impl + +void init_fmod(py::module_ m) +{ + using arrayT = dpctl::tensor::usm_ndarray; + using event_vecT = std::vector; + + impl::populate_dispatch_tables(); + using impl::contig_dispatch_vector; + using impl::output_typeid_vector; + + auto fmod_pyapi = [&](sycl::queue &exec_q, const arrayT &src1, + const arrayT &src2, const arrayT &dst, + const event_vecT &depends = {}) { + return py_int::py_binary_ufunc( + src1, src2, dst, exec_q, depends, output_typeid_vector, + contig_dispatch_vector, + // no support of strided implementation in OneMKL + td_ns::NullPtrTable{}, + // no support of C-contig row with broadcasting in OneMKL + td_ns::NullPtrTable< + impl:: + binary_contig_matrix_contig_row_broadcast_impl_fn_ptr_t>{}, + td_ns::NullPtrTable< + impl:: + binary_contig_row_contig_matrix_broadcast_impl_fn_ptr_t>{}); + }; + m.def("_fmod", fmod_pyapi, + "Call `fmod` function from OneMKL VM library to performs element " + "by element computation of the modulus function of vector `src1` " + "with respect to vector `src2` to resulting vector `dst`", + py::arg("sycl_queue"), py::arg("src1"), py::arg("src2"), + py::arg("dst"), py::arg("depends") = py::list()); + + auto fmod_need_to_call_pyapi = [&](sycl::queue &exec_q, const arrayT &src1, + const arrayT &src2, const arrayT &dst) { + return py_internal::need_to_call_binary_ufunc(exec_q, src1, src2, dst, + output_typeid_vector, + contig_dispatch_vector); + }; + m.def("_mkl_fmod_to_call", fmod_need_to_call_pyapi, + "Check input arguments to answer if `fmod` function from " + "OneMKL VM library can be used", + py::arg("sycl_queue"), py::arg("src1"), py::arg("src2"), + py::arg("dst")); +} +} // namespace dpnp::extensions::vm diff --git a/dpnp/backend/extensions/vm/fmod.hpp b/dpnp/backend/extensions/vm/fmod.hpp new file mode 100644 index 000000000000..492ac8f98899 --- /dev/null +++ b/dpnp/backend/extensions/vm/fmod.hpp @@ -0,0 +1,35 @@ +//***************************************************************************** +// Copyright (c) 2023-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::vm +{ +void init_fmod(py::module_ m); +} // namespace dpnp::extensions::vm diff --git a/dpnp/backend/extensions/vm/vm_py.cpp b/dpnp/backend/extensions/vm/vm_py.cpp index 791a8f6d6561..b78ae51ddc30 100644 --- a/dpnp/backend/extensions/vm/vm_py.cpp +++ b/dpnp/backend/extensions/vm/vm_py.cpp @@ -46,6 +46,7 @@ #include "exp2.hpp" #include "expm1.hpp" #include "floor.hpp" +#include "fmod.hpp" #include "hypot.hpp" #include "ln.hpp" #include "log10.hpp" @@ -86,6 +87,7 @@ PYBIND11_MODULE(_vm_impl, m) vm_ns::init_exp2(m); vm_ns::init_expm1(m); vm_ns::init_floor(m); + vm_ns::init_fmod(m); vm_ns::init_hypot(m); vm_ns::init_ln(m); vm_ns::init_log10(m); diff --git a/dpnp/backend/include/dpnp_iface_fptr.hpp b/dpnp/backend/include/dpnp_iface_fptr.hpp index 0f6ef51bc7ce..1172bcbe4f5f 100644 --- a/dpnp/backend/include/dpnp_iface_fptr.hpp +++ b/dpnp/backend/include/dpnp_iface_fptr.hpp @@ -140,12 +140,10 @@ enum class DPNPFuncName : size_t DPNP_FN_FLOOR, /**< Used in numpy.floor() impl */ DPNP_FN_FLOOR_DIVIDE, /**< Used in numpy.floor_divide() impl */ DPNP_FN_FMOD, /**< Used in numpy.fmod() impl */ - DPNP_FN_FMOD_EXT, /**< Used in numpy.fmod() impl, requires extra parameters - */ - DPNP_FN_FULL, /**< Used in numpy.full() impl */ - DPNP_FN_FULL_LIKE, /**< Used in numpy.full_like() impl */ - DPNP_FN_HYPOT, /**< Used in numpy.hypot() impl */ - DPNP_FN_IDENTITY, /**< Used in numpy.identity() impl */ + DPNP_FN_FULL, /**< Used in numpy.full() impl */ + DPNP_FN_FULL_LIKE, /**< Used in numpy.full_like() impl */ + DPNP_FN_HYPOT, /**< Used in numpy.hypot() impl */ + DPNP_FN_IDENTITY, /**< Used in numpy.identity() impl */ DPNP_FN_INITVAL, /**< Used in numpy ones, ones_like, zeros, zeros_like impls */ DPNP_FN_INITVAL_EXT, /**< Used in numpy ones, ones_like, zeros, zeros_like diff --git a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp index 122a3ccdedd3..486851516dcf 100644 --- a/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp +++ b/dpnp/backend/kernels/dpnp_krnl_elemwise.cpp @@ -1401,20 +1401,6 @@ static void func_map_elemwise_2arg_3type_core(func_map_t &fmap) template static void func_map_elemwise_2arg_3type_short_core(func_map_t &fmap) { - ((fmap[DPNPFuncName::DPNP_FN_FMOD_EXT][FT1][FTs] = - {get_floating_res_type(), - (void *) - dpnp_fmod_c_ext()>, - func_type_map_t::find_type, - func_type_map_t::find_type>, - get_floating_res_type(), - (void *)dpnp_fmod_c_ext< - func_type_map_t::find_type()>, - func_type_map_t::find_type, - func_type_map_t::find_type>}), - ...); ((fmap[DPNPFuncName::DPNP_FN_MAXIMUM_EXT][FT1][FTs] = {get_floating_res_type(), (void *)dpnp_maximum_c_ext< diff --git a/dpnp/backend/kernels/elementwise_functions/fmod.hpp b/dpnp/backend/kernels/elementwise_functions/fmod.hpp new file mode 100644 index 000000000000..e97b257cb066 --- /dev/null +++ b/dpnp/backend/kernels/elementwise_functions/fmod.hpp @@ -0,0 +1,61 @@ +//***************************************************************************** +// 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::fmod +{ +template +struct FmodFunctor +{ + using supports_sg_loadstore = typename std::true_type; + using supports_vec = std::negation< + std::conjunction, std::is_integral>>; + + resT operator()(const argT1 &in1, const argT2 &in2) const + { + if constexpr (std::is_integral::value && + std::is_integral::value) { + if (in2 == argT2(0)) { + return resT(0); + } + return in1 % in2; + } + else { + return sycl::fmod(in1, in2); + } + } + + template + sycl::vec + operator()(const sycl::vec &in1, + const sycl::vec &in2) const + { + return sycl::fmod(in1, in2); + } +}; +} // namespace dpnp::kernels::fmod diff --git a/dpnp/dpnp_algo/dpnp_algo.pxd b/dpnp/dpnp_algo/dpnp_algo.pxd index f6df42981a9f..4e91151697c0 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pxd +++ b/dpnp/dpnp_algo/dpnp_algo.pxd @@ -42,7 +42,6 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na DPNP_FN_ERF_EXT DPNP_FN_FFT_FFT_EXT DPNP_FN_FFT_RFFT_EXT - DPNP_FN_FMOD_EXT DPNP_FN_MAXIMUM_EXT DPNP_FN_MEDIAN_EXT DPNP_FN_MINIMUM_EXT diff --git a/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi b/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi index 405037da7829..fca1e6dc3036 100644 --- a/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi +++ b/dpnp/dpnp_algo/dpnp_algo_mathematical.pxi @@ -37,7 +37,6 @@ and the rest of the library __all__ += [ "dpnp_ediff1d", - "dpnp_fmod", "dpnp_fmax", "dpnp_fmin", "dpnp_modf", @@ -109,14 +108,6 @@ cpdef utils.dpnp_descriptor dpnp_ediff1d(utils.dpnp_descriptor x1): return result -cpdef utils.dpnp_descriptor dpnp_fmod(utils.dpnp_descriptor x1_obj, - utils.dpnp_descriptor x2_obj, - object dtype=None, - utils.dpnp_descriptor out=None, - object where=True): - return call_fptr_2in_1out_strides(DPNP_FN_FMOD_EXT, x1_obj, x2_obj, dtype, out, where) - - cpdef utils.dpnp_descriptor dpnp_fmax(utils.dpnp_descriptor x1_obj, utils.dpnp_descriptor x2_obj, object dtype=None, diff --git a/dpnp/dpnp_iface_bitwise.py b/dpnp/dpnp_iface_bitwise.py index 21ee7cc3d827..6a9c44b813e8 100644 --- a/dpnp/dpnp_iface_bitwise.py +++ b/dpnp/dpnp_iface_bitwise.py @@ -65,14 +65,16 @@ Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have integer or boolean data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have integer or boolean data - type. + type. Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -132,14 +134,16 @@ Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have integer or boolean data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have integer or boolean data - type. + type. Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -194,14 +198,16 @@ Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have integer or boolean data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have integer or boolean data - type. + type. Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -264,6 +270,7 @@ 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"``. @@ -326,14 +333,17 @@ Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have integer data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have integer data type. - Each element must be greater than or equal to 0. + Each element must be greater than or equal to ``0``. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -384,14 +394,17 @@ Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have integer data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have integer data type. - Each element must be greater than or equal to 0. + Each element must be greater than or equal to ``0``. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. diff --git a/dpnp/dpnp_iface_logic.py b/dpnp/dpnp_iface_logic.py index 6dfa1a15dccb..70f928306376 100644 --- a/dpnp/dpnp_iface_logic.py +++ b/dpnp/dpnp_iface_logic.py @@ -369,10 +369,12 @@ def any(a, /, axis=None, out=None, keepdims=False, *, where=True): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. out : {None, dpnp.ndarray, usm_ndarray}, optional Output array to populate. Array have the correct shape and the expected data type. @@ -438,13 +440,16 @@ def any(a, /, axis=None, out=None, keepdims=False, *, where=True): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -501,13 +506,16 @@ def any(a, /, axis=None, out=None, keepdims=False, *, where=True): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -612,6 +620,7 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): 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"``. @@ -671,6 +680,7 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): 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"``. @@ -724,6 +734,7 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): 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"``. @@ -774,13 +785,16 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -837,13 +851,16 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -900,13 +917,16 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -969,6 +989,7 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): 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"``. @@ -1017,13 +1038,16 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1082,13 +1106,16 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1145,13 +1172,16 @@ def isclose(x1, x2, rtol=1e-05, atol=1e-08, equal_nan=False): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 2f34be46312b..1fe7839f5967 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -63,7 +63,6 @@ dpnp_ediff1d, dpnp_fmax, dpnp_fmin, - dpnp_fmod, dpnp_modf, dpnp_trapz, ) @@ -343,6 +342,7 @@ def _gradient_num_diff_edges( 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"``. @@ -404,13 +404,16 @@ def _gradient_num_diff_edges( Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -480,6 +483,7 @@ def _gradient_num_diff_edges( 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"``. @@ -537,6 +541,7 @@ def around(x, /, decimals=0, out=None): out : {None, dpnp.ndarray, usm_ndarray}, optional Output array to populate. Array must have the correct shape and the expected data type. + Default: ``None``. Returns ------- @@ -573,6 +578,7 @@ def around(x, /, decimals=0, out=None): 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"``. @@ -699,6 +705,7 @@ def clip(a, a_min, a_max, *, out=None, order="K", **kwargs): 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"``. @@ -762,14 +769,17 @@ def convolve(a, v, mode="full"): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have a real floating-point data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real floating-point data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1236,13 +1246,16 @@ def diff(a, n=1, axis=-1, prepend=None, append=None): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1363,6 +1376,7 @@ def ediff1d(x1, to_end=None, to_begin=None): 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"``. @@ -1411,6 +1425,7 @@ def ediff1d(x1, to_end=None, to_begin=None): 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"``. @@ -1463,13 +1478,16 @@ def ediff1d(x1, to_end=None, to_begin=None): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1748,116 +1766,78 @@ def fmin(x1, x2, /, out=None, *, where=True, dtype=None, subok=True, **kwargs): ) -def fmod(x1, x2, /, out=None, *, where=True, dtype=None, subok=True, **kwargs): - """ - Returns the element-wise remainder of division. +_FMOD_DOCSTRING = """ +Calculates the remainder of division for each element `x1_i` of the input array +`x1` with the respective element `x2_i` of the input array `x2`. - For full documentation refer to :obj:`numpy.fmod`. +This function is equivalent to the Matlab(TM) ``rem`` function and should not +be confused with the Python modulus operator ``x1 % x2``. - Returns - ------- - out : dpnp.ndarray - The remainder of the division of `x1` by `x2`. +For full documentation refer to :obj:`numpy.fmod`. - Limitations - ----------- - Parameters `x1` and `x2` are supported as either scalar, - :class:`dpnp.ndarray` or :class:`dpctl.tensor.usm_ndarray`, but both `x1` - and `x2` can not be scalars at the same time. - Parameters `where`, `dtype` and `subok` are supported with their default - values. - Keyword argument `kwargs` is currently unsupported. - Otherwise the function will be executed sequentially on CPU. - Input array data types are limited by supported DPNP :ref:`Data types`. - - See Also - -------- - :obj:`dpnp.remainder` : Remainder complementary to floor_divide. - :obj:`dpnp.divide` : Standard division. - - Examples - -------- - >>> import dpnp as np - >>> a = np.array([-3, -2, -1, 1, 2, 3]) - >>> np.fmod(a, 2) - array([-1, 0, -1, 1, 0, 1]) - >>> np.remainder(a, 2) - array([1, 0, 1, 1, 0, 1]) - - >>> a = np.array([5, 3]) - >>> b = np.array([2, 2.]) - >>> np.fmod(a, b) - array([1., 1.]) - - >>> a = np.arange(-3, 3).reshape(3, 2) - >>> a - array([[-3, -2], - [-1, 0], - [ 1, 2]]) - >>> b = np.array([2, 2]) - >>> np.fmod(a, b) - array([[-1, 0], - [-1, 0], - [ 1, 0]]) +Parameters +---------- +x1 : {dpnp.ndarray, usm_ndarray, scalar} + First input array, expected to have a real-valued data type. + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} + Second input array, also expected to have a real-valued data type. + Both inputs `x1` and `x2` can not be scalars at the same time. +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 + An array containing the element-wise remainders. The data type of the + returned array is determined by the Type Promotion Rules. - if kwargs: - pass - elif where is not True: - pass - elif dtype is not None: - pass - elif subok is not True: - pass - elif dpnp.isscalar(x1) and dpnp.isscalar(x2): - # at least either x1 or x2 has to be an array - pass - else: - # get USM type and queue to copy scalar from the host memory into - # a USM allocation - usm_type, queue = ( - get_usm_allocations([x1, x2]) - if dpnp.isscalar(x1) or dpnp.isscalar(x2) - else (None, None) - ) +Limitations +---------- +Parameters `where` and `subok` are supported with their default values. +Keyword argument `kwargs` is currently unsupported. +Otherwise ``NotImplementedError`` exception will be raised. - x1_desc = dpnp.get_dpnp_descriptor( - x1, - copy_when_strides=False, - copy_when_nondefault_queue=False, - alloc_usm_type=usm_type, - alloc_queue=queue, - ) - x2_desc = dpnp.get_dpnp_descriptor( - x2, - copy_when_strides=False, - copy_when_nondefault_queue=False, - alloc_usm_type=usm_type, - alloc_queue=queue, - ) - if x1_desc and x2_desc: - if out is not None: - if not dpnp.is_supported_array_type(out): - raise TypeError( - "return array must be of supported array type" - ) - out_desc = ( - dpnp.get_dpnp_descriptor( - out, copy_when_nondefault_queue=False - ) - or None - ) - else: - out_desc = None +See Also +-------- +:obj:`dpnp.remainder` : Equivalent to the Python ``%`` operator. +:obj:`dpnp.divide` : Standard division. - return dpnp_fmod( - x1_desc, x2_desc, dtype=dtype, out=out_desc, where=where - ).get_pyobj() +Examples +-------- +>>> import dpnp as np +>>> a = np.array([-3, -2, -1, 1, 2, 3]) +>>> np.fmod(a, 2) +array([-1, 0, -1, 1, 0, 1]) +>>> np.remainder(a, 2) +array([1, 0, 1, 1, 0, 1]) + +>>> np.fmod(np.array([5, 3]), np.array([2, 2.])) +array([1., 1.]) +>>> a = np.arange(-3, 3).reshape(3, 2) +>>> a +array([[-3, -2], + [-1, 0], + [ 1, 2]]) +>>> np.fmod(a, np.array([2, 2])) +array([[-1, 0], + [-1, 0], + [ 1, 0]]) +""" - return call_origin( - numpy.fmod, x1, x2, dtype=dtype, out=out, where=where, **kwargs - ) +fmod = DPNPBinaryFunc( + "fmod", + ufi._fmod_result_type, + ufi._fmod, + _FMOD_DOCSTRING, + mkl_fn_to_call=vmi._mkl_fmod_to_call, + mkl_impl_fn=vmi._fmod, +) def gradient(f, *varargs, axis=None, edge_order=1): @@ -2074,6 +2054,7 @@ def gradient(f, *varargs, axis=None, edge_order=1): 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"``. @@ -2124,13 +2105,16 @@ def gradient(f, *varargs, axis=None, edge_order=1): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -2196,13 +2180,16 @@ def gradient(f, *varargs, axis=None, edge_order=1): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -2298,13 +2285,16 @@ def modf(x1, **kwargs): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -2371,6 +2361,7 @@ def modf(x1, **kwargs): 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"``. @@ -2426,6 +2417,7 @@ def modf(x1, **kwargs): 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"``. @@ -2481,13 +2473,16 @@ def modf(x1, **kwargs): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. out : {None, dpnp.ndarray, usm_ndarray}, optional - Output array to populate. Array must have the correct - shape and the expected data type. + Output array to populate. Array must have the correct shape and + the expected data type. + Default: ``None``. order : {"C", "F", "A", "K"}, optional Output array, if parameter `out` is ``None``. Default: ``"K"``. @@ -2668,6 +2663,7 @@ def prod( 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"``. @@ -2744,13 +2740,16 @@ def prod( Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have a real-valued data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -2826,6 +2825,7 @@ def prod( 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"``. @@ -2885,6 +2885,7 @@ def prod( out : {None, dpnp.ndarray, usm_ndarray}, optional Output array to populate. Array must have the correct shape and the expected data type. + Default: ``None``. Returns ------- @@ -2941,6 +2942,7 @@ def prod( 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"``. @@ -2995,6 +2997,7 @@ def prod( 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"``. @@ -3041,13 +3044,16 @@ def prod( Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have numeric data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have numeric data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -3331,6 +3337,7 @@ def trapz(y1, x1=None, dx=1.0, axis=-1): 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"``. diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index d38af96ea2cf..4d5703cfc6ce 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -121,6 +121,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -175,6 +176,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -229,6 +231,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -282,7 +285,8 @@ def _get_accumulation_res_dt(a, dtype, _out): Input array, expected to have numeric data type. out : {None, dpnp.ndarray, usm_ndarray}, optional Output array to populate. - Array must have the correct shape and the expected data type.. + 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"``. @@ -336,7 +340,8 @@ def _get_accumulation_res_dt(a, dtype, _out): Input array, expected to have numeric data type. out : {None, dpnp.ndarray, usm_ndarray}, optional Output array to populate. - Array must have the correct shape and the expected data type.. + 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"``. @@ -390,15 +395,18 @@ def _get_accumulation_res_dt(a, dtype, _out): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have a real-valued floating-point data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -466,6 +474,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -520,6 +529,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -571,6 +581,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -624,6 +635,7 @@ def _get_accumulation_res_dt(a, dtype, _out): 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"``. @@ -820,6 +832,7 @@ def degrees(x1, **kwargs): 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"``. @@ -872,6 +885,7 @@ def degrees(x1, **kwargs): 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"``. @@ -927,6 +941,7 @@ def degrees(x1, **kwargs): 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"``. @@ -982,13 +997,16 @@ def degrees(x1, **kwargs): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have a real-valued data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1049,6 +1067,7 @@ def degrees(x1, **kwargs): 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"``. @@ -1103,6 +1122,7 @@ def degrees(x1, **kwargs): 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"``. @@ -1162,6 +1182,7 @@ def degrees(x1, **kwargs): 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"``. @@ -1221,6 +1242,7 @@ def degrees(x1, **kwargs): 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"``. @@ -1278,15 +1300,18 @@ def degrees(x1, **kwargs): Parameters ---------- -x1 : {dpnp.ndarray, usm_ndarray} +x1 : {dpnp.ndarray, usm_ndarray, scalar} First input array, expected to have a real-valued floating-point data type. -x2 : {dpnp.ndarray, usm_ndarray} + Both inputs `x1` and `x2` can not be scalars at the same time. +x2 : {dpnp.ndarray, usm_ndarray, scalar} Second input array, also expected to have a real-valued floating-point data type. + Both inputs `x1` and `x2` can not be scalars at the same time. 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"``. @@ -1426,6 +1451,7 @@ def logsumexp(x, /, *, axis=None, dtype=None, keepdims=False, out=None): 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"``. @@ -1556,6 +1582,7 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): 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"`` @@ -1660,6 +1687,7 @@ def radians(x1, **kwargs): 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"``. @@ -1713,6 +1741,7 @@ def radians(x1, **kwargs): 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"``. @@ -1765,6 +1794,7 @@ def radians(x1, **kwargs): 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"``. @@ -1820,6 +1850,7 @@ def radians(x1, **kwargs): 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"``. @@ -1874,6 +1905,7 @@ def radians(x1, **kwargs): 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"``. @@ -1927,6 +1959,7 @@ def radians(x1, **kwargs): 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"``. diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 6cf52e91deb0..ae2c73748b56 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -1040,12 +1040,11 @@ def test_fmax(self, dtype, lhs, rhs): def test_fmin(self, dtype, lhs, rhs): self._test_mathematical("fmin", dtype, lhs, rhs, check_type=False) - @pytest.mark.usefixtures("allow_fall_back_on_numpy") @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_complex=True) ) def test_fmod(self, dtype, lhs, rhs): - if rhs == 0.3: + if rhs == 0.3 and not has_support_aspect64(): """ Due to accuracy reason, the results are different for `float32` and `float64` >>> numpy.fmod(numpy.array([3.9], dtype=numpy.float32), 0.3) @@ -1053,7 +1052,7 @@ def test_fmod(self, dtype, lhs, rhs): >>> numpy.fmod(numpy.array([3.9], dtype=numpy.float64), 0.3) array([9.53674318e-08]) - On a gpu without support for `float64`, dpnp produces results similar to the second one. + On a gpu without fp64 support, dpnp produces results similar to the second one. """ pytest.skip("Due to accuracy reason, the results are different.") self._test_mathematical("fmod", dtype, lhs, rhs, check_type=False) @@ -1300,6 +1299,52 @@ def test_positive_boolean(): dpnp.positive(dpnp_a) +@pytest.mark.parametrize("dtype", get_float_dtypes(no_float16=False)) +def test_float_remainder_magnitude(dtype): + b = numpy.array(1.0, dtype=dtype) + a = numpy.nextafter(numpy.array(0.0, dtype=dtype), -b) + + ia = dpnp.array(a) + ib = dpnp.array(b) + + result = dpnp.remainder(ia, ib) + expected = numpy.remainder(a, b) + assert_equal(result, expected) + + result = dpnp.remainder(-ia, -ib) + expected = numpy.remainder(-a, -b) + assert_equal(result, expected) + + +@pytest.mark.usefixtures("suppress_divide_numpy_warnings") +@pytest.mark.usefixtures("suppress_invalid_numpy_warnings") +@pytest.mark.parametrize("func", ["remainder", "fmod"]) +@pytest.mark.parametrize("dtype", get_float_dtypes(no_float16=False)) +@pytest.mark.parametrize( + "lhs, rhs", + [ + pytest.param(1.0, 0.0, id="one-zero"), + pytest.param(1.0, numpy.inf, id="one-inf"), + pytest.param(numpy.inf, 1.0, id="inf-one"), + pytest.param(numpy.inf, numpy.inf, id="inf-inf"), + pytest.param(numpy.inf, 0.0, id="inf-zero"), + pytest.param(1.0, numpy.nan, id="one-nan"), + pytest.param(numpy.nan, 0.0, id="nan-zero"), + pytest.param(numpy.nan, 1.0, id="nan-one"), + ], +) +def test_float_remainder_fmod_nans_inf(func, dtype, lhs, rhs): + a = numpy.array(lhs, dtype=dtype) + b = numpy.array(rhs, dtype=dtype) + + ia = dpnp.array(a) + ib = dpnp.array(b) + + result = getattr(dpnp, func)(ia, ib) + expected = getattr(numpy, func)(a, b) + assert_equal(result, expected) + + class TestProd: @pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2, (1, 2), (0, -2)]) @pytest.mark.parametrize("keepdims", [False, True]) diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 427151dcc518..5dafcfb7582a 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -627,6 +627,7 @@ def test_1in_1out(func, data, usm_type): pytest.param("dot", [3 + 2j, 4 + 1j, 5], [1, 2 + 3j, 3]), pytest.param("fmax", [[0.0, 1.0, 2.0]], [[3.0, 4.0, 5.0]]), pytest.param("fmin", [[0.0, 1.0, 2.0]], [[3.0, 4.0, 5.0]]), + pytest.param("fmod", [5, 3], [2, 2.0]), pytest.param( "gradient", [1, 2, 4, 7, 11, 16], [0.0, 1.0, 1.5, 3.5, 4.0, 6.0] ), diff --git a/tests/third_party/cupy/core_tests/test_ndarray_math.py b/tests/third_party/cupy/core_tests/test_ndarray_math.py index 81caf2c8ceb0..40ae44174aee 100644 --- a/tests/third_party/cupy/core_tests/test_ndarray_math.py +++ b/tests/third_party/cupy/core_tests/test_ndarray_math.py @@ -3,7 +3,6 @@ import numpy import pytest -import dpnp as cupy from tests.helper import has_support_aspect64 from tests.third_party.cupy import testing @@ -87,7 +86,7 @@ def test_round_halfway_int(self, xp, dtype): a -= a.size + 1 scale = 10 ** abs(self.decimals) if self.decimals < 0: - a *= xp.array(scale, dtype=dtype) + a *= xp.array(scale).astype(dtype) a >>= 1 return a.round(self.decimals) diff --git a/tests/third_party/cupy/math_tests/test_arithmetic.py b/tests/third_party/cupy/math_tests/test_arithmetic.py index 36593a2a99ef..7a7d10143887 100644 --- a/tests/third_party/cupy/math_tests/test_arithmetic.py +++ b/tests/third_party/cupy/math_tests/test_arithmetic.py @@ -1,29 +1,28 @@ import itertools -import unittest import warnings import numpy import pytest import dpnp as cupy -from tests.helper import has_support_aspect64 +from tests.helper import has_support_aspect16, has_support_aspect64 from tests.third_party.cupy import testing -float_types = list(testing._loops._float_dtypes) -complex_types = [] -signed_int_types = [numpy.int32, numpy.int64] -unsigned_int_types = [] +float_types = [numpy.float16, numpy.float32, numpy.float64] +complex_types = [numpy.complex64, numpy.complex128] +signed_int_types = [numpy.int8, numpy.int16, numpy.int32, numpy.int64] +unsigned_int_types = [numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] int_types = signed_int_types + unsigned_int_types -all_types = float_types + int_types + complex_types +all_types = [numpy.bool_] + float_types + int_types + complex_types +negative_types = [numpy.bool_] + float_types + signed_int_types + complex_types negative_types_wo_fp16 = ( [numpy.bool_] - + float_types + + [numpy.float32, numpy.float64] + [numpy.int16, numpy.int32, numpy.int64] + complex_types ) -negative_types = float_types + signed_int_types + complex_types -negative_no_complex_types = float_types + signed_int_types -no_complex_types = float_types + int_types +negative_no_complex_types = [numpy.bool_] + float_types + signed_int_types +no_complex_types = [numpy.bool_] + float_types + int_types @testing.parameterize( @@ -31,12 +30,7 @@ testing.product( { "nargs": [1], - "name": [ - "reciprocal", - "conj", - "conjugate", - "angle", - ], + "name": ["reciprocal", "conj", "conjugate", "angle"], } ) + testing.product( @@ -52,7 +46,6 @@ "floor_divide", "fmod", "remainder", - "mod", ], } ) @@ -128,47 +121,38 @@ class TestArithmeticUnary: @testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64()) def test_unary(self, xp): arg1 = self.arg1 - arg1 = xp.asarray(arg1) + if isinstance(arg1, numpy.ndarray): + arg1 = xp.asarray(arg1) if self.name in ("reciprocal") and xp is numpy: # In NumPy, for integer arguments with absolute value larger than 1 the result is always zero. # We need to convert the input data type to float then compare the output with DPNP. - if isinstance(arg1, numpy.ndarray) and numpy.issubdtype( - arg1.dtype, numpy.integer - ): - np_dtype = ( - numpy.float64 if has_support_aspect64() else numpy.float32 - ) + if numpy.issubdtype(arg1.dtype, numpy.integer): + if arg1.dtype.char in "bB": # int8 + np_dtype = numpy.float16 + elif arg1.dtype.char in "hH": # int16 + np_dtype = numpy.float32 + else: # int32, int64 + if has_support_aspect64(): + np_dtype = numpy.float64 + else: + np_dtype = numpy.float32 arg1 = xp.asarray(arg1, dtype=np_dtype) if self.name in {"angle"}: y = getattr(xp, self.name)(arg1, self.deg) - # In NumPy, for boolean arguments the output data type is always default floating data type. - # while data type of output in DPNP is determined by Type Promotion Rules. - if ( - isinstance(arg1, cupy.ndarray) - and cupy.issubdtype(arg1.dtype, cupy.bool) - and has_support_aspect64() - ): - y = y.astype(cupy.float64) + if isinstance(arg1, cupy.ndarray): + if arg1.dtype == cupy.bool and has_support_aspect64(): + # In NumPy, for boolean input the output data type is always default floating data type. + # while data type of output in DPNP is determined by Type Promotion Rules. + y = y.astype(cupy.float64) + elif arg1.dtype.char in "bBe" and has_support_aspect16(): + # In NumPy, for int8, uint8 and float16 inputs the output data type is always float16. + # while data type of output in DPNP is float32. + y = y.astype(cupy.float16) else: y = getattr(xp, self.name)(arg1) - # if self.name in ("real", "imag"): - # Some NumPy functions return Python scalars for Python scalar - # inputs. - # We need to convert them to arrays to compare with CuPy outputs. - # if xp is numpy and isinstance(arg1, (bool, int, float, complex)): - # y = xp.asarray(y) - - # TODO(niboshi): Fix this - # numpy.real and numpy.imag return Python int if the input is - # Python bool. CuPy should return an array of dtype.int32 or - # dtype.int64 (depending on the platform) in such cases, instead - # of an array of dtype.bool. - # if xp is cupy and isinstance(arg1, bool): - # y = y.astype(int) - return y @@ -210,9 +194,61 @@ def test_imag_nocomplex(self, xp, dtype): imag = xp.imag(x) return imag + @pytest.mark.skip("'dpnp_array' object has no attribute 'base' yet") + @testing.for_complex_dtypes() + @testing.numpy_cupy_array_equal() + def test_real_ndarray_complex(self, xp, dtype): + x = testing.shaped_arange(self.shape, xp, dtype=dtype) + x_ = x.copy() + real = x_.real + # real returns a view + assert real.base is x_ + x_ += 1 + 1j + testing.assert_array_equal(real, x.real + 1) + return real + + @pytest.mark.skip("'dpnp_array' object has no attribute 'base' yet") + @testing.for_complex_dtypes() + @testing.numpy_cupy_array_equal() + def test_real_complex(self, xp, dtype): + x = testing.shaped_arange(self.shape, xp, dtype=dtype) + x_ = x.copy() + real = xp.real(x_) + # real returns a view + assert real.base is x_ + x_ += 1 + 1j + testing.assert_array_equal(real, x.real + 1) + return real + + @pytest.mark.skip("'dpnp_array' object has no attribute 'base' yet") + @testing.for_complex_dtypes() + @testing.numpy_cupy_array_equal() + def test_imag_ndarray_complex(self, xp, dtype): + x = testing.shaped_arange(self.shape, xp, dtype=dtype) + x_ = x.copy() + imag = x_.imag + # imag returns a view + assert imag.base is x_ + x_ += 1 + 1j + testing.assert_array_equal(imag, x.imag + 1) + return imag + + @pytest.mark.skip("'dpnp_array' object has no attribute 'base' yet") + @testing.for_complex_dtypes() + @testing.numpy_cupy_array_equal() + def test_imag_complex(self, xp, dtype): + x = testing.shaped_arange(self.shape, xp, dtype=dtype) + x_ = x.copy() + imag = xp.imag(x_) + # imag returns a view + assert imag.base is x_ + x_ += 1 + 1j + testing.assert_array_equal(imag, x.imag + 1) + return imag + class ArithmeticBinaryBase: - @testing.numpy_cupy_allclose(atol=1e-4, type_check=False) + @testing.numpy_cupy_allclose(rtol=1e-4, type_check=has_support_aspect64()) def check_binary(self, xp): arg1 = self.arg1 arg2 = self.arg2 @@ -221,15 +257,37 @@ def check_binary(self, xp): dtype1 = np1.dtype dtype2 = np2.dtype - # TODO(niboshi): Fix this: xp.add(0j, xp.array([2.], 'f')).dtype - # numpy => complex64 - # # cupy => complex128 - # if isinstance(arg1, complex): - # if dtype2 in (numpy.float16, numpy.float32): - # return xp.array(True) - - arg1 = xp.asarray(arg1) - arg2 = xp.asarray(arg2) + if xp.isscalar(arg1) and xp.isscalar(arg2): + pytest.skip("both scalar inputs is not supported") + + if self.name == "power": + # TODO(niboshi): Fix this: power(0, 1j) + # numpy => 1+0j + # cupy => 0j + if dtype2 in complex_types and (np1 == 0).any(): + return xp.array(True) + # TODO: Fix this: power(0j, 0) + # numpy => 1+0j + # cupy => nan+nanj + elif dtype1 in complex_types and (np2 == 0).any(): + return xp.array(True) + + if self.name in ("true_divide", "floor_divide", "fmod", "remainder"): + if dtype1.kind in "u" and xp.isscalar(arg2) and arg2 < 0: + # TODO: Fix this: array(3, dtype=uint) / -2 + # numpy => -1.5 + # cupy => 0.01181102 + pytest.skip("due to dpctl gh-1711") + if dtype2.kind in "u" and xp.isscalar(arg1) and arg1 < 0: + # TODO: Fix this: 2 / array(3, dtype=uint) + # numpy => -0.666667 + # cupy => 84.666667 + pytest.skip("due to dpctl gh-1711") + + if isinstance(arg1, numpy.ndarray): + arg1 = xp.asarray(arg1) + if isinstance(arg2, numpy.ndarray): + arg2 = xp.asarray(arg2) # Subtraction between booleans is not allowed. if ( @@ -255,15 +313,6 @@ def check_binary(self, xp): if dtype1 in (numpy.float16, numpy.float32): y = y.astype(numpy.complex64) - # NumPy returns an output array of another type than DPNP when input ones have different types. - if xp is numpy and dtype1 != dtype2: - is_array_arg1 = not xp.isscalar(arg1) - is_array_arg2 = not xp.isscalar(arg2) - - is_int_float = lambda _x, _y: numpy.issubdtype( - _x, numpy.integer - ) and numpy.issubdtype(_y, numpy.floating) - return y @@ -271,16 +320,17 @@ def check_binary(self, xp): *( testing.product( { + # TODO(unno): boolean subtract causes DeprecationWarning in numpy>=1.13 "arg1": [ testing.shaped_arange((2, 3), numpy, dtype=d) for d in all_types ] - + [0, 0.0, 2, 2.0], + + [0, 0.0, 0j, 2, 2.0, 2j, True, False], "arg2": [ testing.shaped_reverse_arange((2, 3), numpy, dtype=d) for d in all_types ] - + [0, 0.0, 2, 2.0], + + [0, 0.0, 0j, 2, 2.0, 2j, True, False], "name": ["add", "multiply", "power", "subtract"], } ) @@ -290,19 +340,18 @@ def check_binary(self, xp): numpy.array([-3, -2, -1, 1, 2, 3], dtype=d) for d in negative_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], + + [0, 0.0, 0j, 2, 2.0, 2j, -2, -2.0, -2j, True, False], "arg2": [ numpy.array([-3, -2, -1, 1, 2, 3], dtype=d) for d in negative_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], + + [0, 0.0, 0j, 2, 2.0, 2j, -2, -2.0, -2j, True, False], "name": ["divide", "true_divide", "subtract"], } ) ) ) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -class TestArithmeticBinary(ArithmeticBinaryBase, unittest.TestCase): +class TestArithmeticBinary(ArithmeticBinaryBase): def test_binary(self): self.use_dtype = False self.check_binary() @@ -311,19 +360,36 @@ def test_binary(self): @testing.parameterize( *( testing.product( + { + "arg1": [ + numpy.array([3, 2, 1, 1, 2, 3], dtype=d) + for d in unsigned_int_types + ] + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], + "arg2": [ + numpy.array([3, 2, 1, 1, 2, 3], dtype=d) + for d in unsigned_int_types + ] + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], + "name": ["true_divide"], + "dtype": [cupy.default_float_type()], + "use_dtype": [True, False], + } + ) + + testing.product( { "arg1": [ numpy.array([-3, -2, -1, 1, 2, 3], dtype=d) - for d in int_types + for d in signed_int_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], "arg2": [ numpy.array([-3, -2, -1, 1, 2, 3], dtype=d) - for d in int_types + for d in signed_int_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], "name": ["true_divide"], - "dtype": float_types, + "dtype": [cupy.default_float_type()], "use_dtype": [True, False], } ) @@ -340,7 +406,7 @@ def test_binary(self): ] + [0.0, 2.0, -2.0], "name": ["power", "true_divide", "subtract"], - "dtype": float_types, + "dtype": [cupy.default_float_type()], "use_dtype": [True, False], } ) @@ -350,14 +416,14 @@ def test_binary(self): testing.shaped_arange((2, 3), numpy, dtype=d) for d in no_complex_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], "arg2": [ testing.shaped_reverse_arange((2, 3), numpy, dtype=d) for d in no_complex_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], - "name": ["floor_divide", "fmod", "remainder", "mod"], - "dtype": float_types, + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], + "name": ["floor_divide", "fmod", "remainder"], + "dtype": [cupy.default_float_type()], "use_dtype": [True, False], } ) @@ -367,31 +433,229 @@ def test_binary(self): numpy.array([-3, -2, -1, 1, 2, 3], dtype=d) for d in negative_no_complex_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], "arg2": [ numpy.array([-3, -2, -1, 1, 2, 3], dtype=d) for d in negative_no_complex_types ] - + [0, 0.0, 2, 2.0, -2, -2.0], - "name": ["floor_divide", "fmod", "remainder", "mod"], - "dtype": float_types, + + [0, 0.0, 2, 2.0, -2, -2.0, True, False], + "name": ["floor_divide", "fmod", "remainder"], + "dtype": [cupy.default_float_type()], "use_dtype": [True, False], } ) ) ) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") -class TestArithmeticBinary2(ArithmeticBinaryBase, unittest.TestCase): +class TestArithmeticBinary2(ArithmeticBinaryBase): def test_binary(self): - if ( - self.use_dtype - and numpy.lib.NumpyVersion(numpy.__version__) < "1.10.0" - ): - raise unittest.SkipTest("NumPy>=1.10") self.check_binary() -class TestArithmeticModf(unittest.TestCase): +@pytest.mark.skip("'casting' keyword is not supported yet") +class UfuncTestBase: + @testing.numpy_cupy_allclose(accept_error=TypeError) + def check_casting_out(self, in0_type, in1_type, out_type, casting, xp): + a = testing.shaped_arange((2, 3), xp, in0_type) + b = testing.shaped_arange((2, 3), xp, in1_type) + c = xp.zeros((2, 3), out_type) + if casting != "unsafe": + # may raise TypeError + return xp.add(a, b, out=c, casting=casting) + + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = xp.add(a, b, out=c, casting=casting) + ws = [w.category for w in ws] + assert all([w == numpy.ComplexWarning for w in ws]), str(ws) + return ret, xp.array(len(ws)) + + @testing.numpy_cupy_allclose(accept_error=TypeError) + def check_casting_dtype(self, in0_type, in1_type, dtype, casting, xp): + a = testing.shaped_arange((2, 3), xp, in0_type) + b = testing.shaped_arange((2, 3), xp, in1_type) + if casting != "unsafe": + # may raise TypeError + return xp.add(a, b, dtype=dtype, casting=casting) + + with warnings.catch_warnings(record=True) as ws: + warnings.simplefilter("always") + ret = xp.add(a, b, dtype=dtype, casting="unsafe") + ws = [w.category for w in ws] + assert all([w == numpy.ComplexWarning for w in ws]), str(ws) + return ret, xp.array(len(ws)) + + # delete this, once check_casting_dtype passes + @testing.numpy_cupy_allclose() + def check_casting_dtype_unsafe_ignore_warnings( + self, in0_type, in1_type, dtype, xp + ): + a = testing.shaped_arange((2, 3), xp, in0_type) + b = testing.shaped_arange((2, 3), xp, in1_type) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + return xp.add(a, b, dtype=dtype, casting="unsafe") + + +class TestUfunc(UfuncTestBase): + @pytest.mark.parametrize( + "casting", + [ + "no", + "equiv", + "safe", + "same_kind", + "unsafe", + ], + ) + @testing.for_all_dtypes_combination(names=["in_type", "out_type"]) + def test_casting_out_only(self, in_type, out_type, casting): + self.check_casting_out(in_type, in_type, out_type, casting) + + @pytest.mark.parametrize( + "casting", + [ + pytest.param("no", marks=pytest.mark.skip("flaky xfail")), + pytest.param("equiv", marks=pytest.mark.skip("flaky xfail")), + "safe", + "same_kind", + "unsafe", + ], + ) + @testing.for_all_dtypes_combination( + names=["in0_type", "in1_type", "out_type"], full=False + ) + def test_casting_in_out(self, in0_type, in1_type, out_type, casting): + self.check_casting_out(in0_type, in1_type, out_type, casting) + + @pytest.mark.xfail() + @pytest.mark.parametrize( + "casting", + [ + "no", + "equiv", + ], + ) + @pytest.mark.parametrize( + ("in0_type", "in1_type", "out_type"), + [ + (numpy.int16, numpy.int32, numpy.int32), + ], + ) + def test_casting_in_xfail1(self, in0_type, in1_type, out_type, casting): + self.check_casting_out(in0_type, in1_type, out_type, casting) + + @pytest.mark.skip("flaky xfail") + @pytest.mark.parametrize( + "casting", + [ + "no", + "equiv", + "safe", + "same_kind", + "unsafe", + ], + ) + @testing.for_all_dtypes_combination( + names=["in0_type", "in1_type", "dtype"], full=False + ) + def test_casting_dtype(self, in0_type, in1_type, dtype, casting): + self.check_casting_dtype(in0_type, in1_type, dtype, casting) + + @pytest.mark.xfail() + @pytest.mark.parametrize( + "casting", + [ + "no", + "equiv", + ], + ) + @pytest.mark.parametrize( + ("in0_type", "in1_type", "dtype"), + [ + (numpy.int16, numpy.int32, numpy.int32), + ], + ) + def test_casting_dtype_xfail1(self, in0_type, in1_type, dtype, casting): + self.check_casting_dtype(in0_type, in1_type, dtype, casting) + + @pytest.mark.xfail() + @pytest.mark.parametrize( + "casting", + [ + "no", + "equiv", + "safe", + "same_kind", + ], + ) + @pytest.mark.parametrize( + ("in0_type", "in1_type", "dtype"), + [ + (numpy.int32, numpy.int32, numpy.bool_), + (numpy.float64, numpy.float64, numpy.int32), + ], + ) + def test_casting_dtype_xfail2(self, in0_type, in1_type, dtype, casting): + self.check_casting_dtype(in0_type, in1_type, dtype, casting) + + @testing.for_all_dtypes_combination( + names=["in0_type", "in1_type", "dtype"], full=False + ) + def test_casting_dtype_unsafe_ignore_warnings( + self, in0_type, in1_type, dtype + ): + self.check_casting_dtype_unsafe_ignore_warnings( + in0_type, in1_type, dtype + ) + + +@testing.slow +class TestUfuncSlow(UfuncTestBase): + @pytest.mark.parametrize( + "casting", + [ + pytest.param("no", marks=pytest.mark.xfail()), + pytest.param("equiv", marks=pytest.mark.xfail()), + "safe", + "same_kind", + "unsafe", + ], + ) + @testing.for_all_dtypes_combination( + names=["in0_type", "in1_type", "out_type"], full=True + ) + def test_casting_out(self, in0_type, in1_type, out_type, casting): + self.check_casting_out(in0_type, in1_type, out_type, casting) + + @pytest.mark.xfail() + @pytest.mark.parametrize( + "casting", + [ + "no", + "equiv", + "safe", + "same_kind", + "unsafe", + ], + ) + @testing.for_all_dtypes_combination( + names=["in0_type", "in1_type", "dtype"], full=True + ) + def test_casting_dtype(self, in0_type, in1_type, dtype, casting): + self.check_casting_dtype(in0_type, in1_type, dtype, casting) + + @testing.for_all_dtypes_combination( + names=["in0_type", "in1_type", "dtype"], full=True + ) + def test_casting_dtype_unsafe_ignore_warnings( + self, in0_type, in1_type, dtype + ): + self.check_casting_dtype_unsafe_ignore_warnings( + in0_type, in1_type, dtype + ) + + +class TestArithmeticModf: @testing.for_float_dtypes() @testing.numpy_cupy_allclose() def test_modf(self, xp, dtype): @@ -406,11 +670,9 @@ def test_modf(self, xp, dtype): @testing.parameterize( *testing.product({"xp": [numpy, cupy], "shape": [(3, 2), (), (3, 0, 2)]}) ) -class TestBoolSubtract(unittest.TestCase): +class TestBoolSubtract: def test_bool_subtract(self): xp = self.xp - if xp is numpy and not testing.numpy_satisfies(">=1.14.0"): - raise unittest.SkipTest("NumPy<1.14.0") shape = self.shape x = testing.shaped_random(shape, xp, dtype=numpy.bool_) y = testing.shaped_random(shape, xp, dtype=numpy.bool_)