Repository: scipy/scipy
File: scipy/signal/tests/test_signaltools.py (Python)

Code before:
        with pytest.raises(ValueError, match="^When given as a tuple, N must hold"):
            hilbert2(x, N=(0, 1))

    @pytest.mark.parametrize('dtype', ['float32', 'float64'])
    def test_hilbert2_types(self, dtype, xp):
        dtype = getattr(xp, dtype)
        in_typed = xp.zeros((2, 32), dtype=dtype)
        out = xp.real(signal.hilbert2(in_typed))
        assert out.dtype == dtype

    def test_1d_input(self, xp):
        """Needed for 100% coverage """
        x = xp.asarray([0., 1., 1., 0., -1., -1.])
        x0a = signal.hilbert2(xp.reshape(x, (6, 1)))
        x1a = signal.hilbert2(xp.reshape(x, (1, 6)))
        xp_assert_close(x0a, x1a.T)

    def test_parameter_N(self, xp):
        """Compare passing tuple to single int. """
        x = xp.zeros((5, 5))
        x0_a = hilbert2(x, N=4)
        x1_a = hilbert2(x, N=(4, 4))
        xp_assert_equal(x1_a, x0_a)

    @pytest.mark.parametrize('shape', [(4, 5), (5, 4), (4, 4), (5, 5)])
    @skip_xp_backends("cupy", reason="Bug in cupy implementation")
    def test_quadrant_values(self, shape, xp):
        """Compare desired and calculated values in Fourier space. """
        x_f = xp.ones(shape, dtype=xp.complex128)  # FFT of input signal
        x_f[0 , 0] += 7
        x = xp.real(sp_fft.ifft2(x_f))  # x.imag is zero

        x_as = hilbert2(x)
        x_as_f = sp_fft.fft2(x_as)

        # Create slices for bins with purely positive and purely negative frequencies
        # (can be verified with `sp_fft.fftfreq()`):
        f0_pos, f0_neg = slice(1, (shape[0] + 1) // 2), slice((shape[0] + 1) // 2, None)
        f1_pos, f1_neg = slice(1, (shape[1] + 1) // 2), slice((shape[1] + 1) // 2, None)
        # Verify all values:
        atol = 1e-12  # for x of dtype complex128
        xp_assert_close(x_as_f[f0_pos, f1_pos], x_f[f0_pos, f1_pos] * 4, atol=atol)
        xp_assert_close(x_as_f[0, f1_pos], x_f[0, f1_pos] * 2, atol=atol)
        xp_assert_close(x_as_f[f0_pos, 0], x_f[f0_pos, 0] * 2, atol=atol)
        xp_assert_close(x_as_f[0, 0], x_f[0, 0], atol=atol)
        zz_as_f = x_as_f[f0_neg, f1_neg]  # check for zeroed orthants
        xp_assert_close(zz_as_f, xp.zeros_like(zz_as_f), atol=atol)

    @pytest.mark.parametrize('shape', [(4, 5), (5, 4), (4, 4), (5, 5)])
    def test_zero_analytic_signal(self, shape, xp):
        """Test that a real signal with Z[-p,-q] == np.conj(Z[p,q])

Review comment (bug):
```suggestion
    @skip_xp_backends("cupy", reason="Bug in cupy implementation, see cupy#9396")
```

Code after:
        with pytest.raises(ValueError, match="^When given as a tuple, N must hold"):
            hilbert2(x, N=(0, 1))

    @pytest.mark.parametrize('dtype', ['float32', 'float64'])
    def test_hilbert2_types(self, dtype, xp):
        dtype = getattr(xp, dtype)
        in_typed = xp.zeros((2, 32), dtype=dtype)
        out = xp.real(signal.hilbert2(in_typed))
        assert out.dtype == dtype

    def test_1d_input(self, xp):
        """Needed for 100% coverage """
        x = xp.asarray([0., 1., 1., 0., -1., -1.])
        x0a = signal.hilbert2(xp.reshape(x, (6, 1)))
        x1a = signal.hilbert2(xp.reshape(x, (1, 6)))
        xp_assert_close(x0a, x1a.T)

    def test_parameter_N(self, xp):
        """Compare passing tuple to single int. """
        x = xp.zeros((5, 5))
        x0_a = hilbert2(x, N=4)
        x1_a = hilbert2(x, N=(4, 4))
        xp_assert_equal(x1_a, x0_a)

    @pytest.mark.parametrize('shape', [(4, 5), (5, 4), (4, 4), (5, 5)])
    @skip_xp_backends("cupy", reason="Bug in cupy implementation, see cupy#9396")
    def test_quadrant_values(self, shape, xp):
        """Compare desired and calculated values in Fourier space. """
        x_f = xp.ones(shape, dtype=xp.complex128)  # FFT of input signal
        x_f[0 , 0] += 7
        x = xp.real(sp_fft.ifft2(x_f))  # x.imag is zero

        x_as = hilbert2(x)
        x_as_f = sp_fft.fft2(x_as)

        # Create slices for bins with purely positive and purely negative frequencies
        # (can be verified with `sp_fft.fftfreq()`):
        f0_pos, f0_neg = slice(1, (shape[0] + 1) // 2), slice((shape[0] + 1) // 2, None)
        f1_pos, f1_neg = slice(1, (shape[1] + 1) // 2), slice((shape[1] + 1) // 2, None)
        # Verify all values:
        atol = 1e-12  # for x of dtype complex128
        xp_assert_close(x_as_f[f0_pos, f1_pos], x_f[f0_pos, f1_pos] * 4, atol=atol)
        xp_assert_close(x_as_f[0, f1_pos], x_f[0, f1_pos] * 2, atol=atol)
        xp_assert_close(x_as_f[f0_pos, 0], x_f[f0_pos, 0] * 2, atol=atol)
        xp_assert_close(x_as_f[0, 0], x_f[0, 0], atol=atol)
        zz_as_f = x_as_f[f0_neg, f1_neg]  # check for zeroed orthants
        xp_assert_close(zz_as_f, xp.zeros_like(zz_as_f), atol=atol)

    @pytest.mark.parametrize('shape', [(4, 5), (5, 4), (4, 4), (5, 5)])
    def test_zero_analytic_signal(self, shape, xp):
        """Test that a real signal with Z[-p,-q] == np.conj(Z[p,q])