From 45fb34f3b4b437bb09a8af3ecbf3ef348efea456 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Fri, 26 Jul 2024 19:15:23 +0200 Subject: [PATCH 1/7] Align doc page of Mathematical functions with numpy --- doc/reference/math.rst | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/doc/reference/math.rst b/doc/reference/math.rst index 48142b10fd45..e093a7a29b34 100644 --- a/doc/reference/math.rst +++ b/doc/reference/math.rst @@ -1,4 +1,4 @@ -Mathematical Functions +Mathematical functions ====================== .. https://docs.scipy.org/doc/numpy/reference/routines.math.html @@ -14,10 +14,14 @@ Trigonometric functions dpnp.cos dpnp.tan dpnp.arcsin + dpnp.asin dpnp.arccos + dpnp.acos dpnp.arctan + dpnp.atan dpnp.hypot dpnp.arctan2 + dpnp.atan2 dpnp.degrees dpnp.radians dpnp.unwrap @@ -37,8 +41,11 @@ Hyperbolic functions dpnp.cosh dpnp.tanh dpnp.arcsinh + dpnp.asinh dpnp.arccosh + dpnp.acosh dpnp.arctanh + dpnp.atanh Rounding @@ -48,8 +55,8 @@ Rounding :toctree: generated/ :nosignatures: - dpnp.around dpnp.round + dpnp.around dpnp.rint dpnp.fix dpnp.floor @@ -68,6 +75,8 @@ Sums, products, differences dpnp.sum dpnp.nanprod dpnp.nansum + dpnp.cumulative_sum + dpnp.cumulative_prod dpnp.cumprod dpnp.cumsum dpnp.nancumprod @@ -75,8 +84,8 @@ Sums, products, differences dpnp.diff dpnp.ediff1d dpnp.gradient - dpnp.trapz dpnp.cross + dpnp.trapezoid Exponents and logarithms @@ -127,6 +136,7 @@ Floating point routines Rational routines ----------------- + .. autosummary:: :toctree: generated/ :nosignatures: @@ -144,15 +154,17 @@ Arithmetic operations dpnp.add dpnp.reciprocal - dpnp.negative dpnp.positive + dpnp.negative dpnp.multiply dpnp.divide dpnp.power + dpnp.pow dpnp.subtract dpnp.true_divide dpnp.floor_divide - dpnp.floor_power + dpnp.float_power + dpnp.fmod dpnp.mod dpnp.modf @@ -175,7 +187,7 @@ Handling complex numbers dpnp.proj -Extrema Finding +Extrema finding --------------- .. autosummary:: @@ -187,6 +199,7 @@ Extrema Finding dpnp.amax dpnp.fmax dpnp.nanmax + dpnp.minimum dpnp.min dpnp.amin @@ -203,17 +216,21 @@ Miscellaneous dpnp.convolve dpnp.clip + dpnp.sqrt dpnp.cbrt dpnp.square dpnp.rsqrt + dpnp.abs dpnp.absolute dpnp.fabs dpnp.sign + dpnp.heaviside + dpnp.nan_to_num - dpnp.bartlett - dpnp.blackman - dpnp.hamming - dpnp.hanning - dpnp.kaiser + dpnp.real_if_close + + dpnp.interp + + dpnp.bitwise_count From f9a0594cef5b779f552622f206b441e6462e761c Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Fri, 26 Jul 2024 20:03:37 +0200 Subject: [PATCH 2/7] Implement dpnp.unwrap() function --- doc/reference/math.rst | 4 +- dpnp/dpnp_algo/CMakeLists.txt | 1 - dpnp/dpnp_algo/dpnp_algo.pyx | 1 - dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi | 63 ----------- dpnp/dpnp_iface_trigonometric.py | 126 ++++++++++++++++----- 5 files changed, 102 insertions(+), 93 deletions(-) delete mode 100644 dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi diff --git a/doc/reference/math.rst b/doc/reference/math.rst index e093a7a29b34..522d046299e7 100644 --- a/doc/reference/math.rst +++ b/doc/reference/math.rst @@ -199,7 +199,7 @@ Extrema finding dpnp.amax dpnp.fmax dpnp.nanmax - + dpnp.minimum dpnp.min dpnp.amin @@ -227,7 +227,7 @@ Miscellaneous dpnp.fabs dpnp.sign dpnp.heaviside - + dpnp.nan_to_num dpnp.real_if_close diff --git a/dpnp/dpnp_algo/CMakeLists.txt b/dpnp/dpnp_algo/CMakeLists.txt index 3711cc744c01..17163836ea8f 100644 --- a/dpnp/dpnp_algo/CMakeLists.txt +++ b/dpnp/dpnp_algo/CMakeLists.txt @@ -1,7 +1,6 @@ set(dpnp_algo_pyx_deps ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_statistics.pxi - ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_trigonometric.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_sorting.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_mathematical.pxi ${CMAKE_CURRENT_SOURCE_DIR}/dpnp_algo_indexing.pxi diff --git a/dpnp/dpnp_algo/dpnp_algo.pyx b/dpnp/dpnp_algo/dpnp_algo.pyx index ac2ed08e1364..f19dcc952230 100644 --- a/dpnp/dpnp_algo/dpnp_algo.pyx +++ b/dpnp/dpnp_algo/dpnp_algo.pyx @@ -63,7 +63,6 @@ include "dpnp_algo_mathematical.pxi" include "dpnp_algo_sorting.pxi" include "dpnp_algo_special.pxi" include "dpnp_algo_statistics.pxi" -include "dpnp_algo_trigonometric.pxi" ctypedef c_dpctl.DPCTLSyclEventRef(*fptr_dpnp_flatten_t)(c_dpctl.DPCTLSyclQueueRef, diff --git a/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi b/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi deleted file mode 100644 index 0dad17c154b7..000000000000 --- a/dpnp/dpnp_algo/dpnp_algo_trigonometric.pxi +++ /dev/null @@ -1,63 +0,0 @@ -# cython: language_level=3 -# cython: linetrace=True -# -*- coding: utf-8 -*- -# ***************************************************************************** -# Copyright (c) 2016-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. -# ***************************************************************************** - -"""Module Backend (Trigonometric part) - -This module contains interface functions between C backend layer -and the rest of the library - -""" - -# NO IMPORTs here. All imports must be placed into main "dpnp_algo.pyx" file - -__all__ += [ - 'dpnp_unwrap' -] - - -cpdef utils.dpnp_descriptor dpnp_unwrap(utils.dpnp_descriptor array1): - - result_type = dpnp.float64 - - if array1.dtype == dpnp.float32: - result_type = dpnp.float32 - - array1_obj = array1.get_array() - - cdef utils.dpnp_descriptor result = utils_py.create_output_descriptor_py(array1.shape, - result_type, - None, - device=array1_obj.sycl_device, - usm_type=array1_obj.usm_type, - sycl_queue=array1_obj.sycl_queue) - - for i in range(result.size): - val, = numpy.unwrap([array1.get_pyobj()[i]]) - result.get_pyobj()[i] = val - - return result diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index fdceca572bca..8a5acc5b00e3 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -38,25 +38,17 @@ """ # pylint: disable=protected-access -# pylint: disable=c-extension-no-member -# pylint: disable=duplicate-code -# pylint: disable=no-name-in-module import dpctl.tensor as dpt import dpctl.tensor._tensor_elementwise_impl as ti import dpctl.tensor._type_utils as dtu -import numpy import dpnp import dpnp.backend.extensions.ufunc._ufunc_impl as ufi import dpnp.backend.extensions.vm._vm_impl as vmi -from .dpnp_algo import ( - dpnp_unwrap, -) from .dpnp_algo.dpnp_elementwise_common import DPNPBinaryFunc, DPNPUnaryFunc -from .dpnp_utils import call_origin from .dpnp_utils.dpnp_utils_reduction import dpnp_wrap_reduction_call __all__ = [ @@ -2119,38 +2111,120 @@ def reduce_hypot(x, /, *, axis=None, dtype=None, keepdims=False, out=None): ) -def unwrap(x1, **kwargs): - """ - Unwrap by changing deltas between values to 2*pi complement. +def unwrap(p, discont=None, axis=-1, *, period=2 * dpnp.pi): + r""" + Unwrap by taking the complement of large deltas with respect to the period. + + This unwraps a signal `p` by changing elements which have an absolute + difference from their predecessor of more than ``max(discont, period / 2)`` + to their `period`-complementary values. + + For the default case where `period` is :math:`2\pi` and `discont` is + :math:`\pi`, this unwraps a radian phase `p` such that adjacent differences + are never greater than :math:`\pi` by adding :math:`2k\pi` for some integer + :math:`k`. For full documentation refer to :obj:`numpy.unwrap`. - Limitations - ----------- - Input array is supported as :class:`dpnp.ndarray`. - Input array data types are limited by supported DPNP :ref:`Data types`. + Parameters + ---------- + p : {dpnp.ndarray, usm_ndarray} + Input array. + discont : {float, None}, optional + Maximum discontinuity between values, default is ``period / 2``. Values + below ``period / 2`` are treated as if they were ``period / 2``. To + have an effect different from the default, `discont` should be larger + than ``period / 2``. + Default: ``None``. + axis : int, optional + Axis along which unwrap will operate, default is the last axis. + Default: ``-1``. + period : float, optional + Size of the range over which the input wraps. + Default: ``2 * pi``. + + Returns + ------- + out : dpnp.ndarray + Output array. See Also -------- :obj:`dpnp.rad2deg` : Convert angles from radians to degrees. :obj:`dpnp.deg2rad` : Convert angles from degrees to radians. + Notes + ----- + If the discontinuity in `p` is smaller than ``period / 2``, but larger than + `discont`, no unwrapping is done because taking the complement would only + make the discontinuity larger. + Examples -------- >>> import dpnp as np >>> phase = np.linspace(0, np.pi, num=5) - >>> for i in range(3, 5): - >>> phase[i] += np.pi - >>> out = np.unwrap(phase) - >>> [i for i in out] - [0.0, 0.78539816, 1.57079633, 5.49778714, 6.28318531] + >>> phase[3:] += np.pi + >>> phase + array([0. , 0.78539816, 1.57079633, 5.49778714, 6.28318531]) + >>> np.unwrap(phase) + array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) + + >>> phase = np.array([0, 1, 2, -1, 0]) + >>> np.unwrap(phase, period=4) + array([0, 1, 2, 3, 4]) + + >>> phase = np.array([1, 2, 3, 4, 5, 6, 1, 2, 3]) + >>> np.unwrap(phase, period=6) + array([1, 2, 3, 4, 5, 6, 7, 8, 9]) + + >>> phase = np.array([2, 3, 4, 5, 2, 3, 4, 5]) + >>> np.unwrap(phase, period=4) + array([2, 3, 4, 5, 6, 7, 8, 9]) + + >>> phase_deg = np.mod(np.linspace(0 ,720, 19), 360) - 180 + >>> np.unwrap(phase_deg, period=360) + array([-180., -140., -100., -60., -20., 20., 60., 100., 140., + 180., 220., 260., 300., 340., 380., 420., 460., 500., + 540.]) """ - x1_desc = dpnp.get_dpnp_descriptor(x1, copy_when_nondefault_queue=False) - if kwargs: - pass - elif x1_desc: - return dpnp_unwrap(x1_desc).get_pyobj() + dpnp.check_supported_arrays_type(p) - return call_origin(numpy.unwrap, x1, **kwargs) + p_nd = p.ndim + p_diff = dpnp.diff(p, axis=axis) + + if discont is None: + discont = period / 2 + + # full slices + slice1 = [slice(None, None)] * p_nd + slice1[axis] = slice(1, None) + slice1 = tuple(slice1) + + dt = dpnp.result_type(p_diff, period) + if dpnp.issubdtype(dt, dpnp.integer): + interval_high, rem = divmod(period, 2) + boundary_ambiguous = rem == 0 + else: + interval_high = period / 2 + boundary_ambiguous = True + interval_low = -interval_high + + ddmod = p_diff - interval_low + ddmod = dpnp.remainder(ddmod, period, out=ddmod) + ddmod += interval_low + + if boundary_ambiguous: + mask = ddmod == interval_low + mask &= p_diff > 0 + dpnp.copyto(ddmod, interval_high, where=mask) + + ph_correct = dpnp.subtract(ddmod, p_diff, out=ddmod) + abs_p_diff = dpnp.abs(p_diff, out=p_diff) + dpnp.copyto(ph_correct, 0, where=abs_p_diff < discont) + + up = dpnp.astype(p, dtype=dt, copy=True) + up[slice1] = p[slice1] + up[slice1] += ph_correct.cumsum(axis=axis) + return up From bb2632dba147d92bde64791ffad0ce028479afc1 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Fri, 26 Jul 2024 20:23:46 +0200 Subject: [PATCH 3/7] Enable muted tests --- tests/skipped_tests.tbl | 9 -------- tests/skipped_tests_gpu.tbl | 9 -------- tests/skipped_tests_gpu_no_fp64.tbl | 2 -- .../cupy/math_tests/test_trigonometric.py | 22 +++++++++++-------- 4 files changed, 13 insertions(+), 29 deletions(-) diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index b5ed7f8369de..0fe1eacefce0 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -252,15 +252,6 @@ tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_heaviside_nan_inf tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_fix -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_period -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont_and_period -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_axis -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_discont -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_without_axis -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_period -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_discont_and_period - tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_0_{a_shape=(), b_shape=(), shape=(4, 3, 2)}::test_beta tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_1_{a_shape=(), b_shape=(), shape=(3, 2)}::test_beta tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_2_{a_shape=(), b_shape=(3, 2), shape=(4, 3, 2)}::test_beta diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 24eabe21055e..a42a2326e2a5 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -306,15 +306,6 @@ tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_heaviside_nan_inf tests/third_party/cupy/math_tests/test_rounding.py::TestRounding::test_fix -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_period -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim_with_discont_and_period -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_axis -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_discont -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_without_axis -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_period -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_2dim_with_discont_and_period - tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_0_{a_shape=(), b_shape=(), shape=(4, 3, 2)}::test_beta tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_1_{a_shape=(), b_shape=(), shape=(3, 2)}::test_beta tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_2_{a_shape=(), b_shape=(3, 2), shape=(4, 3, 2)}::test_beta diff --git a/tests/skipped_tests_gpu_no_fp64.tbl b/tests/skipped_tests_gpu_no_fp64.tbl index 44e4c856b773..7cd2d8a1c152 100644 --- a/tests/skipped_tests_gpu_no_fp64.tbl +++ b/tests/skipped_tests_gpu_no_fp64.tbl @@ -1,7 +1,5 @@ tests/test_umath.py::test_umaths[('floor_divide', 'ff')] -tests/third_party/cupy/math_tests/test_trigonometric.py::TestUnwrap::test_unwrap_1dim - tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_6_{a_shape=(3, 2), b_shape=(3, 2), shape=(4, 3, 2)}::test_beta tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsBeta_param_7_{a_shape=(3, 2), b_shape=(3, 2), shape=(3, 2)}::test_beta tests/third_party/cupy/random_tests/test_distributions.py::TestDistributionsChisquare_param_0_{df_shape=(), shape=(4, 3, 2)}::test_chisquare diff --git a/tests/third_party/cupy/math_tests/test_trigonometric.py b/tests/third_party/cupy/math_tests/test_trigonometric.py index 778dc461454d..ea1881662efc 100644 --- a/tests/third_party/cupy/math_tests/test_trigonometric.py +++ b/tests/third_party/cupy/math_tests/test_trigonometric.py @@ -58,55 +58,59 @@ def test_rad2deg(self): @testing.with_requires("numpy>=1.21.0") class TestUnwrap(unittest.TestCase): @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_unwrap_1dim(self, xp, dtype): a = testing.shaped_random((5,), xp, dtype) return xp.unwrap(a) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_unwrap_1dim_with_discont(self, xp, dtype): a = testing.shaped_random((5,), xp, dtype) return xp.unwrap(a, discont=1.0) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_unwrap_1dim_with_period(self, xp, dtype): a = testing.shaped_random((5,), xp, dtype) return xp.unwrap(a, period=1.2) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_unwrap_1dim_with_discont_and_period(self, xp, dtype): a = testing.shaped_random((5,), xp, dtype) return xp.unwrap(a, discont=1.0, period=1.2) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose( + rtol=1e-06, atol=1e-06, type_check=has_support_aspect64() + ) def test_unwrap_2dim_without_axis(self, xp, dtype): a = testing.shaped_random((4, 5), xp, dtype) return xp.unwrap(a) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose( + rtol=1e-06, atol=1e-06, type_check=has_support_aspect64() + ) def test_unwrap_2dim_with_axis(self, xp, dtype): a = testing.shaped_random((4, 5), xp, dtype) return xp.unwrap(a, axis=1) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(rtol=1e-06, type_check=has_support_aspect64()) def test_unwrap_2dim_with_discont(self, xp, dtype): a = testing.shaped_random((4, 5), xp, dtype) return xp.unwrap(a, discont=5.0, axis=1) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_unwrap_2dim_with_period(self, xp, dtype): a = testing.shaped_random((4, 5), xp, dtype) return xp.unwrap(a, axis=1, period=4.5) @testing.for_all_dtypes(no_complex=True) - @testing.numpy_cupy_allclose() + @testing.numpy_cupy_allclose(type_check=has_support_aspect64()) def test_unwrap_2dim_with_discont_and_period(self, xp, dtype): a = testing.shaped_random((4, 5), xp, dtype) return xp.unwrap(a, discont=5.0, axis=1, period=4.5) From f67c3b70710d26a0a031debd3474118215971a64 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Fri, 26 Jul 2024 21:00:06 +0200 Subject: [PATCH 4/7] Add more tests --- dpnp/dpnp_iface_trigonometric.py | 4 +- tests/test_mathematical.py | 75 ++++++++++++++++++++++++++++++++ tests/test_strides.py | 1 + tests/test_sycl_queue.py | 1 + tests/test_usm_type.py | 1 + 5 files changed, 81 insertions(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index 8a5acc5b00e3..c3f17ea5b2a6 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -2226,5 +2226,7 @@ def unwrap(p, discont=None, axis=-1, *, period=2 * dpnp.pi): up = dpnp.astype(p, dtype=dt, copy=True) up[slice1] = p[slice1] - up[slice1] += ph_correct.cumsum(axis=axis) + # TODO: replace, once dpctl-1757 resolved + # up[slice1] += ph_correct.cumsum(axis=axis) + up[slice1] += ph_correct.cumsum(axis=axis, dtype=dt) return up diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 7d2a2fd907e7..2f5558a14fc8 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -1250,6 +1250,81 @@ def test_f16_corner_values_with_scalar(self, val, scalar): assert_equal(result, expected) +class TestUnwrap: + @pytest.mark.parametrize("dt", get_float_dtypes()) + def test_basic(self, dt): + a = numpy.array([1, 1 + 2 * numpy.pi], dtype=dt) + ia = dpnp.array(a) + + # unwrap removes jumps greater that 2*pi + result = dpnp.unwrap(ia) + expected = numpy.unwrap(a) + assert_array_equal(result, expected) + + @pytest.mark.parametrize( + "dt", get_all_dtypes(no_none=True, no_complex=True) + ) + def test_rand(self, dt): + a = numpy.random.rand(10) * 100 + a = a.astype(dtype=dt) + ia = dpnp.array(a) + + result = dpnp.unwrap(ia) + expected = numpy.unwrap(a) + assert_dtype_allclose(result, expected) + + @pytest.mark.parametrize( + "dt", get_all_dtypes(no_none=True, no_bool=True, no_complex=True) + ) + def test_period(self, dt): + a = numpy.array([1, 1 + 256], dtype=dt) + ia = dpnp.array(a) + + # unwrap removes jumps greater that 255 + result = dpnp.unwrap(ia, period=255) + expected = numpy.unwrap(a, period=255) + assert_array_equal(result, expected) + + @pytest.mark.parametrize( + "dt", get_all_dtypes(no_none=True, no_bool=True, no_complex=True) + ) + def test_rand_period(self, dt): + a = numpy.random.rand(10) * 1000 + a = a.astype(dtype=dt) + ia = dpnp.array(a) + + result = dpnp.unwrap(ia, period=255) + expected = numpy.unwrap(a, period=255) + assert_dtype_allclose(result, expected) + + def test_simple_seq(self): + simple_seq = numpy.array([0, 75, 150, 225, 300]) + wrap_seq = numpy.mod(simple_seq, 255) + isimple_seq, iwrap_seq = dpnp.array(simple_seq), dpnp.array(wrap_seq) + + result = dpnp.unwrap(iwrap_seq, period=255) + expected = numpy.unwrap(wrap_seq, period=255) + assert_array_equal(result, expected) + assert_array_equal(result, isimple_seq) + + @pytest.mark.parametrize( + "dt", get_all_dtypes(no_none=True, no_complex=True) + ) + def test_discont(self, dt): + a = numpy.array([0, 75, 150, 225, 300, 430], dtype=dt) + a = numpy.mod(a, 250) + ia = dpnp.array(a) + + result = dpnp.unwrap(ia, period=250) + expected = numpy.unwrap(a, period=250) + assert_array_equal(result, expected) + + result = dpnp.unwrap(ia, period=250, discont=140) + expected = numpy.unwrap(a, period=250, discont=140) + assert_array_equal(result, expected) + assert result.dtype == ia.dtype == a.dtype + + @pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings") @pytest.mark.parametrize( "val_type", [bool, int, float], ids=["bool", "int", "float"] diff --git a/tests/test_strides.py b/tests/test_strides.py index 780c069e9ca0..5e06bd3dabf9 100644 --- a/tests/test_strides.py +++ b/tests/test_strides.py @@ -85,6 +85,7 @@ def test_strides(func_name, dtype): "tan", "tanh", "trunc", + "unwrap", ], ) @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True, no_complex=True)) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index ecc940dec43b..0df494eafce1 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -479,6 +479,7 @@ def test_meshgrid(device): pytest.param("trapz", [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0]]), pytest.param("trim_zeros", [0, 0, 0, 1, 2, 3, 0, 2, 1, 0]), pytest.param("trunc", [-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]), + pytest.param("unwrap", [[0, 1, 2, -1, 0]]), pytest.param("var", [1.0, 2.0, 4.0, 7.0]), ], ) diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 7d4788762ef6..bf635d8dc439 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -613,6 +613,7 @@ def test_norm(usm_type, ord, axis): ), pytest.param("trim_zeros", [0, 0, 0, 1, 2, 3, 0, 2, 1, 0]), pytest.param("trunc", [-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]), + pytest.param("unwrap", [[0, 1, 2, -1, 0]]), pytest.param("var", [1.0, 2.0, 4.0, 7.0]), ], ) From 08c8b9522ee82e867e1f7f0c4cb659be4344cf4d Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Fri, 26 Jul 2024 21:06:27 +0200 Subject: [PATCH 5/7] Resolve pre-commit issue --- dpnp/dpnp_iface_trigonometric.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index c3f17ea5b2a6..53f6340af46b 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -38,6 +38,7 @@ """ # pylint: disable=protected-access +# pylint: disable=no-name-in-module import dpctl.tensor as dpt From d7a2772c27c1e81ab6490039c57a460002c97785 Mon Sep 17 00:00:00 2001 From: Anton <100830759+antonwolfy@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:20:24 +0200 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: vtavana <120411540+vtavana@users.noreply.github.com> --- tests/test_mathematical.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 2f5558a14fc8..8b91e1876d39 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -1256,7 +1256,7 @@ def test_basic(self, dt): a = numpy.array([1, 1 + 2 * numpy.pi], dtype=dt) ia = dpnp.array(a) - # unwrap removes jumps greater that 2*pi + # unwrap removes jumps greater than 2*pi result = dpnp.unwrap(ia) expected = numpy.unwrap(a) assert_array_equal(result, expected) @@ -1280,7 +1280,7 @@ def test_period(self, dt): a = numpy.array([1, 1 + 256], dtype=dt) ia = dpnp.array(a) - # unwrap removes jumps greater that 255 + # unwrap removes jumps greater than 255 result = dpnp.unwrap(ia, period=255) expected = numpy.unwrap(a, period=255) assert_array_equal(result, expected) From 4f22fd2e40fb15bf15da49682557ec2fc9db3689 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 1 Aug 2024 17:07:23 +0200 Subject: [PATCH 7/7] Replace dpnp.copyto with dpnp.where --- dpnp/dpnp_iface_trigonometric.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dpnp/dpnp_iface_trigonometric.py b/dpnp/dpnp_iface_trigonometric.py index 53f6340af46b..b67bc3da8f27 100644 --- a/dpnp/dpnp_iface_trigonometric.py +++ b/dpnp/dpnp_iface_trigonometric.py @@ -2219,11 +2219,11 @@ def unwrap(p, discont=None, axis=-1, *, period=2 * dpnp.pi): if boundary_ambiguous: mask = ddmod == interval_low mask &= p_diff > 0 - dpnp.copyto(ddmod, interval_high, where=mask) + ddmod = dpnp.where(mask, interval_high, ddmod, out=ddmod) ph_correct = dpnp.subtract(ddmod, p_diff, out=ddmod) abs_p_diff = dpnp.abs(p_diff, out=p_diff) - dpnp.copyto(ph_correct, 0, where=abs_p_diff < discont) + ph_correct = dpnp.where(abs_p_diff < discont, 0, ph_correct, out=ph_correct) up = dpnp.astype(p, dtype=dt, copy=True) up[slice1] = p[slice1]