Repository: scipy/scipy
Pull request: TST: stats.ttest_1samp: fix xslow test
#### Reference issue
Closes gh-20641

#### What does this implement/fix?
Fixes the one test failure that occurs twice with each backend tested.

#### Additional information
```
[gh20641 aa257e0deb] TST: stats.ttest_1samp: fix xslow test
 1 file changed, 3 insertions(+), 3 deletions(-)
(scipy-dev) matthaberland@Matts-MacBook-Air scipy % git status
On branch gh20641
nothing to commit, working tree clean
(scipy-dev) matthaberland@Matts-MacBook-Air scipy % pytest scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci -v
========================================= test session starts =========================================
platform darwin -- Python 3.11.6, pytest-7.4.3, pluggy-1.5.0 -- /Users/matthaberland/miniforge3/envs/scipy-dev/bin/python3.11
cachedir: .pytest_cache
hypothesis profile 'deterministic' -> database=None, deadline=None, print_blob=True, derandomize=True, suppress_health_check=[HealthCheck.data_too_large, HealthCheck.filter_too_much, HealthCheck.too_slow, HealthCheck.large_base_example, HealthCheck.function_scoped_fixture, HealthCheck.differing_executors]
rootdir: /Users/matthaberland/Desktop/scipy
configfile: pytest.ini
plugins: fail-slow-0.5.0, hypothesis-6.88.1, anyio-4.3.0, cov-4.1.0, skip-slow-0.0.5, xdist-3.3.1
collected 6 items                                                                                     

scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[less-numpy] PASSED             [ 16%]
scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[less-array_api_strict] PASSED  [ 33%]
scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[less-torch] PASSED             [ 50%]
scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[greater-numpy] PASSED          [ 66%]
scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[greater-array_api_strict] PASSED [ 83%]
scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[greater-torch] PASSED          [100%]

========================================== 6 passed in 8.73s ==========================================
```

Problem statement:
BUG: stats: Two new XSLOW test failures
There are two new XSLOW test failures occurring in `stats`:

```
$ SCIPY_XSLOW=1 python3 dev.py test -t scipy.stats.tests.test_stats -m full -j 9
💻  ninja -C /home/warren/repos/git/forks/scipy/build -j12
ninja: Entering directory `/home/warren/repos/git/forks/scipy/build'
[2/2] Generating scipy/generate-version with a custom command
Build OK
💻  meson install -C build --only-changed
Installing, see meson-install.log...
Installation OK
SciPy from development installed path at: /home/warren/repos/git/forks/scipy/build-install/lib/python3.12/site-packages
Running tests for scipy version:1.14.0.dev0+1096.9c75b1f, installed at:/home/warren/repos/git/forks/scipy/build-install/lib/python3.12/site-packages/scipy
=============================== test session starts ================================
platform linux -- Python 3.12.3, pytest-8.1.1, pluggy-1.5.0
rootdir: /home/warren/repos/git/forks/scipy
configfile: pytest.ini
plugins: timeout-2.3.1, xdist-3.5.0, hypothesis-6.100.1, cov-5.0.0
9 workers [1019 items]  
............................................................................ [  7%]
............................................................................ [ 14%]
............................................................................ [ 22%]
............................................................................ [ 29%]
............................................................................ [ 37%]
............................................................................ [ 44%]
............................................................................ [ 52%]
........................................x................................... [ 59%]
...........................................x.......................x........ [ 67%]
............................................................................ [ 74%]
............................................................................ [ 82%]
............................................................................ [ 89%]
...............................................s............................ [ 96%]
.FF............................                                              [100%]
===================================== FAILURES =====================================
____________________ TestStudentTest.test_pvalue_ci[less-numpy] ____________________
[gw0] linux -- Python 3.12.3 /home/warren/py3.12.3/bin/python3
scipy/stats/tests/test_stats.py:3708: in test_pvalue_ci
    @hypothesis.given(alpha=hypothesis.strategies.floats(1e-15, 1-1e-15),
        alternative = 'less'
        f          = <function given.<locals>.run_test_as_given.<locals>.wrapped_test at 0x710e04b10360>
        self       = <scipy.stats.tests.test_stats.TestStudentTest object at 0x710dfc1869c0>
        xp         = <module 'numpy' from '/home/warren/py3.12.3/lib/python3.12/site-packages/numpy/__init__.py'>
scipy/stats/tests/test_stats.py:3714: in test_pvalue_ci
    data = data.astype(copy=True)  # ensure byte order
E   TypeError: astype() missing required argument 'dtype' (pos 0)
E   Falsifying example: test_pvalue_ci(
E       # The test always failed when commented parts were varied together.
E       self=<scipy.stats.tests.test_stats.TestStudentTest object at 0x710dfc1869c0>,
E       alternative='less',
E       xp=<module 'numpy' from '/home/warren/py3.12.3/lib/python3.12/site-packages/numpy/__init__.py'>,
E       alpha=0.5,  # or any other generated value
E       data_axis=(array([0., 1.], dtype=float16),
E        0),  # or any other generated value
E   )
E   
E   You can reproduce this example by temporarily adding @reproduce_failure('6.100.1', b'AXicY2BgOMAAA4xghBUwAgAc3wDE') as a decorator on your test case
        alpha      = 0.5
        alternative = 'less'
        axis       = 0
        data       = array([0., 1.], dtype=float16)
        data_axis  = (array([0., 1.], dtype=float16), 0)
        self       = <scipy.stats.tests.test_stats.TestStudentTest object at 0x710dfc1869c0>
        xp         = <module 'numpy' from '/home/warren/py3.12.3/lib/python3.12/site-packages/numpy/__init__.py'>
__________________ TestStudentTest.test_pvalue_ci[greater-numpy] ___________________
[gw0] linux -- Python 3.12.3 /home/warren/py3.12.3/bin/python3
scipy/stats/tests/test_stats.py:3708: in test_pvalue_ci
    @hypothesis.given(alpha=hypothesis.strategies.floats(1e-15, 1-1e-15),
        alternative = 'greater'
        f          = <function given.<locals>.run_test_as_given.<locals>.wrapped_test at 0x710e04b10360>
        self       = <scipy.stats.tests.test_stats.TestStudentTest object at 0x710dfc186960>
        xp         = <module 'numpy' from '/home/warren/py3.12.3/lib/python3.12/site-packages/numpy/__init__.py'>
scipy/stats/tests/test_stats.py:3714: in test_pvalue_ci
    data = data.astype(copy=True)  # ensure byte order
E   TypeError: astype() missing required argument 'dtype' (pos 0)
E   Falsifying example: test_pvalue_ci(
E       self=<scipy.stats.tests.test_stats.TestStudentTest object at 0x710dfc186960>,
E       alternative='greater',
E       xp=<module 'numpy' from '/home/warren/py3.12.3/lib/python3.12/site-packages/numpy/__init__.py'>,
E       alpha=0.5,  # or any other generated value
E       data_axis=(array([0., 1.], dtype=float16), 0),
E   )
E   
E   You can reproduce this example by temporarily adding @reproduce_failure('6.100.1', b'AXicY2BgOMAAA4xghBUwAgAc3wDE') as a decorator on your test case
        alpha      = 0.5
        alternative = 'greater'
        axis       = 0
        data       = array([0., 1.], dtype=float16)
        data_axis  = (array([0., 1.], dtype=float16), 0)
        self       = <scipy.stats.tests.test_stats.TestStudentTest object at 0x710dfc186960>
        xp         = <module 'numpy' from '/home/warren/py3.12.3/lib/python3.12/site-packages/numpy/__init__.py'>
============================= short test summary info ==============================
FAILED scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[less-numpy] - TypeError: astype() missing required argument 'dtype' (pos 0)
FAILED scipy/stats/tests/test_stats.py::TestStudentTest::test_pvalue_ci[greater-numpy] - TypeError: astype() missing required argument 'dtype' (pos 0)
========= 2 failed, 1013 passed, 1 skipped, 3 xfailed in 78.32s (0:01:18) ==========

```


### SciPy/NumPy/Python version and system information

```shell
1.14.0.dev0+1096.9c75b1f 1.26.4 sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)
Build Dependencies:
  blas:
    detection method: pkgconfig
    found: true
    include directory: /usr/include/x86_64-linux-gnu/openblas-pthread/
    lib directory: /usr/lib/x86_64-linux-gnu/openblas-pthread/
    name: openblas
    openblas configuration: USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER=1 NO_CBLAS=
      NO_LAPACK= NO_LAPACKE=1 NO_AFFINITY=1 USE_OPENMP=0 generic MAX_THREADS=64
    pc file directory: /usr/lib/x86_64-linux-gnu/pkgconfig
    version: 0.3.20
  lapack:
    detection method: pkgconfig
    found: true
    include directory: /usr/include/x86_64-linux-gnu/openblas-pthread/
    lib directory: /usr/lib/x86_64-linux-gnu/openblas-pthread/
    name: openblas
    openblas configuration: USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER=1 NO_CBLAS=
      NO_LAPACK= NO_LAPACKE=1 NO_AFFINITY=1 USE_OPENMP=0 generic MAX_THREADS=64
    pc file directory: /usr/lib/x86_64-linux-gnu/pkgconfig
    version: 0.3.20
  pybind11:
    detection method: config-tool
    include directory: unknown
    name: pybind11
    version: 2.12.0
Compilers:
  c:
    commands: cc
    linker: ld.bfd
    name: gcc
    version: 11.4.0
  c++:
    commands: c++
    linker: ld.bfd
    name: gcc
    version: 11.4.0
  cython:
    commands: cython
    linker: cython
    name: cython
    version: 3.0.10
  fortran:
    commands: gfortran
    linker: ld.bfd
    name: gcc
    version: 11.4.0
  pythran:
    include directory: ../../../../../py3.12.3/lib/python3.12/site-packages/pythran
    version: 0.15.0
Machine Information:
  build:
    cpu: x86_64
    endian: little
    family: x86_64
    system: linux
  cross-compiled: false
  host:
    cpu: x86_64
    endian: little
    family: x86_64
    system: linux
Python Information:
  path: /home/warren/py3.12.3/bin/python3.12
  version: '3.12'

```

Hints from issue discussion:
cc @mdhaber

Commit message: TST: stats.ttest_1samp: fix xslow test

[skip ci]

Patch to review:
diff --git a/scipy/stats/tests/test_stats.py b/scipy/stats/tests/test_stats.py
index b0b3bc4c574d..483c0a40124b 100644
--- a/scipy/stats/tests/test_stats.py
+++ b/scipy/stats/tests/test_stats.py
@@ -3711,8 +3711,8 @@ def test_1samp_ci_iv(self, xp):
     def test_pvalue_ci(self, alpha, data_axis, alternative, xp):
         # test relationship between one-sided p-values and confidence intervals
         data, axis = data_axis
-        data = data.astype(copy=True)  # ensure byte order
-        data = xp.asarray(data)
+        data = data.astype(np.float64, copy=True)  # ensure byte order
+        data = xp.asarray(data, dtype=xp.float64)
         res = stats.ttest_1samp(data, 0.,
                                 alternative=alternative, axis=axis)
         l, u = res.confidence_interval(confidence_level=alpha)
@@ -3722,7 +3722,7 @@ def test_pvalue_ci(self, alpha, data_axis, alternative, xp):
         res = stats.ttest_1samp(data, popmean, alternative=alternative, axis=axis)
         shape = list(data.shape)
         shape.pop(axis)
-        ref = xp.broadcast_to(xp.asarray(1-alpha), shape)
+        ref = xp.broadcast_to(xp.asarray(1-alpha, dtype=xp.float64), shape)
         xp_assert_close(res.pvalue, ref)
 
 


Code review comments:
diff_hunk: @@ -3711,8 +3711,8 @@ def test_1samp_ci_iv(self, xp):
     def test_pvalue_ci(self, alpha, data_axis, alternative, xp):
         # test relationship between one-sided p-values and confidence intervals
         data, axis = data_axis
-        data = data.astype(copy=True)  # ensure byte order
-        data = xp.asarray(data)
+        data = data.astype(np.float64, copy=True)  # ensure byte order
+        data = xp.asarray(data, dtype=xp.float64)
path: scipy/stats/tests/test_stats.py
text: @user1:
Am I missing something with the "ensure byte order" comment? Can we not just include the `copy` in `asarray`?

```suggestion
	# `float64` is needed here because of the range of `alpha`
        data = xp.asarray(data, dtype=xp.float64, copy=True)
```

@author:
`hypothesis` generates them in some nonstandard format that `torch.asarray` won't accept. Might be possible to make it generate more standard `float64`s.

@user1:
okay, if that isn't possible then I think this looks okay. Maybe worth adding a comment as to why.

@author:
I adjusted the test strategy to generate normal `float64`s. I think that the old strategy must have been left over from before the test took its final form.

diff_hunk: @@ -3711,8 +3711,8 @@ def test_1samp_ci_iv(self, xp):
     def test_pvalue_ci(self, alpha, data_axis, alternative, xp):
         # test relationship between one-sided p-values and confidence intervals
         data, axis = data_axis
-        data = data.astype(copy=True)  # ensure byte order
-        data = xp.asarray(data)
+        data = data.astype(np.float64, copy=True)  # ensure byte order
+        data = xp.asarray(data, dtype=xp.float64)
path: scipy/stats/tests/test_stats.py
text: @author:
```suggestion
        data = data.astype(np.float64, copy=True)  # ensure byte order
        # `float64` is needed here because of the range of `alpha`
        data = xp.asarray(data, dtype=xp.float64)
```

@user1:
I did check that all these incantations pass locally on x86_64 Linux, while they fail on `main`:

```
SCIPY_XSLOW=1 SCIPY_DEVICE=cuda python dev.py test -j 32 -b all -- -k "test_pvalue_ci"
SCIPY_XSLOW=1 python dev.py test -j 32 -b all -- -k "test_pvalue_ci"
SCIPY_XSLOW=1 python dev.py test -j 32 -- -k "test_pvalue_ci"
```

I tried to play picky reviewer and force `float32` instead of `float64` locally, and saw overflow/invalid value warnings, so that seems like a plausible justification for non-`stats` expert at least.

@user1:
(obivously the first one has limited value, since it is cpu only)