Skip to content

BUG: stats/fft/differentiate/optimize: test suite failures with CuPy 13.2.0 #21227

@mdhaber

Description

@mdhaber

Describe your issue.

There are some test suite failures with CuPy 13.2.0 due to adoption of NEP 50 rules. I guess some functions have become (at least temporarily) less array API standard compliant in some functions because this is failing with the same error:

import cupy as cp
cp.full((1,), cp.nan)
# TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the value.
This change was part of adopting NEP 50, we may explicitly allow them again in the future.

Update: It looks like CuPy will change this - cupy/cupy#8391. There are also differentiate and optimize failures related to cupy/cupy#8391, and some fft failures related cupy/cupy#8393.

According to the standard, Python scalars should be accepted for the fill_value (and the dtype will be some default).

The full message is too long to include here (GitHub won't accept it), so I'm only including the first and last full messages. Most (if not all) of it has to do with call of xp.full or xp.full_like not accepting Python scalars, and a lot of those uses are in the definition of xp_sign or test_morestate.py.

Reproducing Code Example

pytest scipy/stats

Error message

====================================================== FAILURES =======================================================
___________________________ TestCircFuncs.test_nan_propagate_array[circmean-expected0-cupy] ___________________________

self = <scipy.stats.tests.test_morestats.TestCircFuncs object at 0x000001BCEEFAB920>
test_func = <function circmean at 0x000001BCEAB834C0>, expected = {None: nan, 0: 355.66582264, 1: 0.28725053}
xp = <module 'cupy' from 'C:\\Users\\matth\\miniforge3\\envs\\scipy-dev\\Lib\\site-packages\\cupy\\__init__.py'>

    @pytest.mark.parametrize("test_func,expected",
                             [(stats.circmean,
                               {None: np.nan, 0: 355.66582264, 1: 0.28725053}),
                              (stats.circvar,
                               {None: np.nan,
                                0: 0.002570671054089924,
                                1: 0.005545914017677123}),
                              (stats.circstd,
                               {None: np.nan, 0: 4.11093193, 1: 6.04265394})])
    def test_nan_propagate_array(self, test_func, expected, xp):
        x = xp.asarray([[355, 5, 2, 359, 10, 350, 1],
                        [351, 7, 4, 352, 9, 349, np.nan],
                        [1, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]])
        for axis in expected.keys():
            out = test_func(x, high=360, axis=axis)
            if axis is None:
                xp_assert_equal(out, xp.asarray(xp.nan))
            else:
                xp_assert_close(out[0], xp.asarray(expected[axis]))
>               xp_assert_equal(out[1:], xp.full_like(out[1:], xp.nan))

axis       = 0
expected   = {None: nan, 0: 355.66582264, 1: 0.28725053}
out        = array([355.66582264,          nan,          nan,          nan,
                nan,          nan,          nan])
self       = <scipy.stats.tests.test_morestats.TestCircFuncs object at 0x000001BCEEFAB920>
test_func  = <function circmean at 0x000001BCEAB834C0>
x          = array([[355.,   5.,   2., 359.,  10., 350.,   1.],
       [351.,   7.,   4., 352.,   9., 349.,  nan],
       [  1.,  nan,  nan,  nan,  nan,  nan,  nan]])
xp         = <module 'cupy' from 'C:\\Users\\matth\\miniforge3\\envs\\scipy-dev\\Lib\\site-packages\\cupy\\__init__.py'>

scipy\stats\tests\test_morestats.py:2703:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\miniforge3\envs\scipy-dev\Lib\site-packages\cupy\_creation\basic.py:370: in full_like
    cupy.copyto(a, fill_value, casting='unsafe')
        a          = array([-0.08715574,  0.08715574,  0.0348995 , -0.01745241,  0.17364818,
       -0.17364818])
        dtype      = dtype('float64')
        fill_value = nan
        memptr     = None
        order      = 'C'
        shape      = (6,)
        strides    = None
        subok      = None
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dst = array([-0.08715574,  0.08715574,  0.0348995 , -0.01745241,  0.17364818,
       -0.17364818]), src = nan
casting = 'unsafe', where = None

    def copyto(dst, src, casting='same_kind', where=None):
        """Copies values from one array to another with broadcasting.

        This function can be called for arrays on different devices. In this case,
        casting, ``where``, and broadcasting is not supported, and an exception is
        raised if these are used.

        Args:
            dst (cupy.ndarray): Target array.
            src (cupy.ndarray): Source array.
            casting (str): Casting rule. See :func:`numpy.can_cast` for detail.
            where (cupy.ndarray of bool): If specified, this array acts as a mask,
                and an element is copied only if the corresponding element of
                ``where`` is True.

        .. seealso:: :func:`numpy.copyto`

        """
        src_is_numpy_scalar = False

        src_type = type(src)
        src_is_python_scalar = src_type in (
            int, bool, float, complex,
            fusion._FusionVarScalar, _fusion_interface._ScalarProxy)
        if src_is_python_scalar:
            src_dtype = numpy.dtype(type(src))
>           can_cast = numpy.can_cast(src, dst.dtype, casting)
E           TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the value.
E           This change was part of adopting NEP 50, we may explicitly allow them again in the future.

casting    = 'unsafe'
dst        = array([-0.08715574,  0.08715574,  0.0348995 , -0.01745241,  0.17364818,
       -0.17364818])
src        = nan
src_dtype  = dtype('float64')
src_is_numpy_scalar = False
src_is_python_scalar = True
src_type   = <class 'float'>
where      = None

..\..\miniforge3\envs\scipy-dev\Lib\site-packages\cupy\_manipulation\basic.py:38: TypeError

...
____________________________________________ TestNormalTest.test_nan[cupy] ____________________________________________

self = <scipy.stats.tests.test_stats.TestNormalTest object at 0x000001BCEFC12ED0>
xp = <module 'cupy' from 'C:\\Users\\matth\\miniforge3\\envs\\scipy-dev\\Lib\\site-packages\\cupy\\__init__.py'>

    def test_nan(self, xp):
        # nan in input -> nan output (default nan_policy='propagate')
        test_fun = getattr(stats, self.test_name)
        x = xp.arange(30.)
        NaN = xp.asarray(xp.nan, dtype=x.dtype)
        x = xp.where(x == 29, NaN, x)
        with np.errstate(invalid="ignore"):
>           res = test_fun(x)

NaN        = array(nan)
self       = <scipy.stats.tests.test_stats.TestNormalTest object at 0x000001BCEFC12ED0>
test_fun   = <function normaltest at 0x000001BCEABCC7C0>
x          = array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., nan])
xp         = <module 'cupy' from 'C:\\Users\\matth\\miniforge3\\envs\\scipy-dev\\Lib\\site-packages\\cupy\\__init__.py'>

scipy\stats\tests\test_stats.py:6461:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
scipy\stats\_axis_nan_policy.py:433: in axis_nan_policy_wrapper
    return hypotest_fun_in(*args, **kwds)
        _no_deco   = False
        args       = (array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., nan]),)
        default_axis = 0
        hypotest_fun_in = <function normaltest at 0x000001BCEABCC720>
        is_too_small = <function _axis_nan_policy_factory.<locals>.is_too_small at 0x000001BCEABCC5E0>
        kwd_samples = []
        kwds       = {}
        msg        = 'Use of `nan_policy` and `keepdims` is incompatible with non-NumPy arrays.'
        n_outputs  = 2
        n_samples  = 1
        override   = {'nan_propagation': True, 'vectorization': False}
        paired     = False
        result_to_tuple = <function _axis_nan_policy_factory.<locals>.result_to_tuple at 0x000001BCEABCC540>
        temp       = array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., nan])
        tuple_to_result = <class 'scipy.stats._stats_py.NormaltestResult'>
scipy\stats\_stats_py.py:1824: in normaltest
    k, _ = kurtosistest(a, axis, _no_deco=True)
        _          = array(nan)
        a          = array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., nan])
        axis       = 0
        nan_policy = 'propagate'
        s          = array(nan)
        xp         = <module 'scipy._lib.array_api_compat.cupy' from 'C:\\Users\\matth\\Desktop\\scipy\\scipy\\_lib\\array_api_compat/array_api_compat/cupy/__init__.py'>
scipy\stats\_axis_nan_policy.py:418: in axis_nan_policy_wrapper
    return hypotest_fun_in(*args, **kwds)
        _no_deco   = True
        args       = (array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., nan]), 0)
        default_axis = 0
        hypotest_fun_in = <function kurtosistest at 0x000001BCEABCC0E0>
        is_too_small = <function _axis_nan_policy_factory.<locals>.is_too_small at 0x000001BCEABD7F60>
        kwd_samples = []
        kwds       = {}
        n_outputs  = 2
        n_samples  = 1
        override   = {'nan_propagation': True, 'vectorization': False}
        paired     = False
        result_to_tuple = <function _axis_nan_policy_factory.<locals>.result_to_tuple at 0x000001BCEABD7EC0>
        tuple_to_result = <class 'scipy.stats._stats_py.KurtosistestResult'>
scipy\stats\_stats_py.py:1740: in kurtosistest
    term2 = xp_sign(denom) * xp.where(denom == 0.0, NaN,
        A          = 18.434484048524254
        E          = 2.806451612903226
        NaN        = array(nan)
        a          = array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., nan])
        alternative = 'two-sided'
        axis       = 0
        b2         = array(nan)
        denom      = array(nan)
        n          = 30
        nan_policy = 'propagate'
        sqrtbeta1  = 1.728414305160957
        term1      = 0.9879452974307674
        varb2      = 0.49039825938889414
        x          = array(nan)
        xp         = <module 'scipy._lib.array_api_compat.cupy' from 'C:\\Users\\matth\\Desktop\\scipy\\scipy\\_lib\\array_api_compat/array_api_compat/cupy/__init__.py'>
scipy\_lib\_array_api.py:542: in xp_sign
    sign = xp.full_like(x, xp.nan)
        x          = array(nan)
        xp         = <module 'scipy._lib.array_api_compat.cupy' from 'C:\\Users\\matth\\Desktop\\scipy\\scipy\\_lib\\array_api_compat/array_api_compat/cupy/__init__.py'>
scipy\_lib\array_api_compat\array_api_compat\_internal.py:28: in wrapped_f
    return f(*args, xp=xp, **kwargs)
        args       = (array(nan), nan)
        f          = <function full_like at 0x000001BC6F7882C0>
        kwargs     = {}
        xp         = <module 'cupy' from 'C:\\Users\\matth\\miniforge3\\envs\\scipy-dev\\Lib\\site-packages\\cupy\\__init__.py'>
scipy\_lib\array_api_compat\array_api_compat\common\_aliases.py:90: in full_like
    return xp.full_like(x, fill_value, dtype=dtype, **kwargs)
        device     = None
        dtype      = None
        fill_value = nan
        kwargs     = {}
        x          = array(nan)
        xp         = <module 'cupy' from 'C:\\Users\\matth\\miniforge3\\envs\\scipy-dev\\Lib\\site-packages\\cupy\\__init__.py'>
..\..\miniforge3\envs\scipy-dev\Lib\site-packages\cupy\_creation\basic.py:370: in full_like
    cupy.copyto(a, fill_value, casting='unsafe')
        a          = array(nan)
        dtype      = dtype('float64')
        fill_value = nan
        memptr     = None
        order      = 'C'
        shape      = ()
        strides    = None
        subok      = None
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

dst = array(nan), src = nan, casting = 'unsafe', where = None

    def copyto(dst, src, casting='same_kind', where=None):
        """Copies values from one array to another with broadcasting.

        This function can be called for arrays on different devices. In this case,
        casting, ``where``, and broadcasting is not supported, and an exception is
        raised if these are used.

        Args:
            dst (cupy.ndarray): Target array.
            src (cupy.ndarray): Source array.
            casting (str): Casting rule. See :func:`numpy.can_cast` for detail.
            where (cupy.ndarray of bool): If specified, this array acts as a mask,
                and an element is copied only if the corresponding element of
                ``where`` is True.

        .. seealso:: :func:`numpy.copyto`

        """
        src_is_numpy_scalar = False

        src_type = type(src)
        src_is_python_scalar = src_type in (
            int, bool, float, complex,
            fusion._FusionVarScalar, _fusion_interface._ScalarProxy)
        if src_is_python_scalar:
            src_dtype = numpy.dtype(type(src))
>           can_cast = numpy.can_cast(src, dst.dtype, casting)
E           TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the value.
E           This change was part of adopting NEP 50, we may explicitly allow them again in the future.

casting    = 'unsafe'
dst        = array(nan)
src        = nan
src_dtype  = dtype('float64')
src_is_numpy_scalar = False
src_is_python_scalar = True
src_type   = <class 'float'>
where      = None

..\..\miniforge3\envs\scipy-dev\Lib\site-packages\cupy\_manipulation\basic.py:38: TypeError
=============================================== short test summary info ===============================================
FAILED scipy/stats/tests/test_morestats.py::TestCircFuncs::test_nan_propagate_array[circmean-expected0-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_morestats.py::TestCircFuncs::test_nan_propagate_array[circvar-expected1-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_morestats.py::TestCircFuncs::test_nan_propagate_array[circstd-expected2-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestTrimmedStats::test_tvar[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestZmapZscore::test_zscore_nan_propagate[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestZmapZscore::test_zscore_constant_input_1d[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestZmapZscore::test_zscore_2d_all_nan[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestMoments::test_constant_moments[0-1-float32-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestMoments::test_constant_moments[0-1-float64-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestMoments::test_constant_moments[0-1-complex128-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestMoments::test_constant_moments[1-0-float32-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestMoments::test_constant_moments[1-0-float64-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestMoments::test_constant_moments[1-0-complex128-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[greater-numpy] - hypothesis.errors.FailedHealthCheck: It looks like your strategy is filtering out a lot of data. Health check found...
FAILED scipy/stats/tests/test_stats.py::test_ttest_ind_axis_size_zero[b0-expected_shape0-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::test_ttest_ind_axis_size_zero[b1-expected_shape1-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestDescribe::test_describe_numbers[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestDescribe::test_describe_ddof[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestDescribe::test_describe_axis_none[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_against_R[two-sided-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_against_R[less-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_against_R[greater-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_nan[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_intuitive[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_gh9033_regression[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestKurtosisTest::test_kurtosistest_too_few_observations[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestNormalTest::test_against_R[two-sided-cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
FAILED scipy/stats/tests/test_stats.py::TestNormalTest::test_nan[cupy] - TypeError: can_cast() does not support Python ints, floats, and complex because the result used to depend on the va...
======================= 28 failed, 14004 passed, 1264 skipped, 70 xfailed in 3006.10s (0:50:06) =======================

(scipy-dev) C:\Users\matth\Desktop\scipy>

SciPy/NumPy/Python version and system information

1.15.0.dev0+1217.afeab37 2.0.0 sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)
Build Dependencies:
  blas:
    detection method: pkgconfig
    found: true
    include directory: C:/Users/matth/miniforge3/envs/scipy-dev/Library/include/openblas
    lib directory: C:/Users/matth/miniforge3/envs/scipy-dev/Library/lib
    name: openblas
    openblas configuration: USE_64BITINT= NO_CBLAS= NO_LAPACK= NO_LAPACKE= DYNAMIC_ARCH=ON
      DYNAMIC_OLDER=OFF NO_AFFINITY=1 USE_OPENMP= HASWELL MAX_THREADS=128
    pc file directory: C:\Users\matth\miniforge3\envs\scipy-dev\Library\lib\pkgconfig
    version: 0.3.27
  lapack:
    detection method: pkgconfig
    found: true
    include directory: C:/Users/matth/miniforge3/envs/scipy-dev/Library/include/openblas
    lib directory: C:/Users/matth/miniforge3/envs/scipy-dev/Library/lib
    name: openblas
    openblas configuration: USE_64BITINT= NO_CBLAS= NO_LAPACK= NO_LAPACKE= DYNAMIC_ARCH=ON
      DYNAMIC_OLDER=OFF NO_AFFINITY=1 USE_OPENMP= HASWELL MAX_THREADS=128
    pc file directory: C:\Users\matth\miniforge3\envs\scipy-dev\Library\lib\pkgconfig
    version: 0.3.27
  pybind11:
    detection method: pkgconfig
    include directory: C:/Users/matth/miniforge3/envs/scipy-dev/Library/include
    name: pybind11
    version: 2.12.0
Compilers:
  c:
    commands: cc
    linker: ld.bfd
    name: gcc
    version: 10.3.0
  c++:
    commands: c++
    linker: ld.bfd
    name: gcc
    version: 10.3.0
  cython:
    commands: cython
    linker: cython
    name: cython
    version: 3.0.10
  fortran:
    commands: gfortran
    linker: ld.bfd
    name: gcc
    version: 10.3.0
  pythran:
    include directory: ..\..\..\miniforge3\envs\scipy-dev\Lib\site-packages\pythran
    version: 0.16.1
Machine Information:
  build:
    cpu: x86_64
    endian: little
    family: x86_64
    system: windows
  cross-compiled: false
  host:
    cpu: x86_64
    endian: little
    family: x86_64
    system: windows
Python Information:
  path: C:\Users\matth\miniforge3\envs\scipy-dev\python.exe
  version: '3.12'

Metadata

Metadata

Assignees

No one assigned

    Labels

    array typesItems related to array API support and input array validation (see gh-18286)defectA clear bug or issue that prevents SciPy from being installed or used as expectedscipy.differentiatescipy.fftscipy.stats

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions