Repository: scipy/scipy
File: scipy/stats/_hypotests.py (Python)

Code before:
    statistic which follows a `chi2` distribution. If the sample size of both
    `x` and `y` is below 25, the small sample correction proposed in [1]_ is
    applied to the test statistic.

    The default values of `t` are determined in [1]_ by considering
    various distributions and finding good values that lead to a high power
    of the test in general. Table III in [1]_ gives the optimal values for
    the distributions tested in that study. The values of `t` are scaled by
    the semi-interquartile range in the implementation, see [1]_.

    References
    ----------
    .. [1] T. W. Epps and K. J. Singleton, "An omnibus test for the two-sample
       problem using the empirical characteristic function", Journal of
       Statistical Computation and Simulation 26, p. 177--203, 1986.

    .. [2] S. J. Goerg and J. Kaiser, "Nonparametric testing of distributions
       - the Epps-Singleton two-sample test using the empirical characteristic
       function", The Stata Journal 9(3), p. 454--465, 2009.

    """
    np = array_namespace(x, y)
    # x and y are converted to arrays by the decorator
    # and `axis` is guaranteed to be -1.
    t = np.asarray(t)
    # check if x and y are valid inputs
    nx, ny = x.shape[-1], y.shape[-1]
    if (nx < 5) or (ny < 5):  # only used by test_axis_nan_policy
        raise ValueError('x and y should have at least 5 elements, but len(x) '
                         f'= {nx} and len(y) = {ny}.')
    # should replace this behavior by returning NaN
    if not np.isfinite(x).all():
        raise ValueError('x must not contain nonfinite values.')
    if not np.isfinite(y).all():
        raise ValueError('y must not contain nonfinite values.')
    n = nx + ny

    # check if t is valid
    if t.ndim > 1:
        raise ValueError(f't must be 1d, but t.ndim equals {t.ndim}.')
    if np.any(t <= 0):
        raise ValueError('t must contain positive elements only.')

    # rescale t with semi-iqr as proposed in [1]; import iqr here to avoid
    # circular import
    from scipy.stats import iqr
    sigma = iqr(np.concat((x, y), axis=-1), axis=-1, keepdims=True) / 2
    ts = np.reshape(t, (-1,) + (1,)*x.ndim) / sigma

    # covariance estimation of ES test
    gx = np.concat((np.cos(ts*x), np.sin(ts*x)), axis=0)

Review comment (suggestion):
Not worth rerunning CI for but if we are coming back here in the near future then
```suggestion
    x, y, t = xp_promote(x, y, t, force_floating=True, xp=np)
```

Code after:
    statistic which follows a `chi2` distribution. If the sample size of both
    `x` and `y` is below 25, the small sample correction proposed in [1]_ is
    applied to the test statistic.

    The default values of `t` are determined in [1]_ by considering
    various distributions and finding good values that lead to a high power
    of the test in general. Table III in [1]_ gives the optimal values for
    the distributions tested in that study. The values of `t` are scaled by
    the semi-interquartile range in the implementation, see [1]_.

    References
    ----------
    .. [1] T. W. Epps and K. J. Singleton, "An omnibus test for the two-sample
       problem using the empirical characteristic function", Journal of
       Statistical Computation and Simulation 26, p. 177--203, 1986.

    .. [2] S. J. Goerg and J. Kaiser, "Nonparametric testing of distributions
       - the Epps-Singleton two-sample test using the empirical characteristic
       function", The Stata Journal 9(3), p. 454--465, 2009.

    """
    np = array_namespace(x, y)
    # x and y are converted to arrays by the decorator
    # and `axis` is guaranteed to be -1.
    x, y = xp_promote(x, y, force_floating=True, xp=np)
    t = np.asarray(t, dtype=x.dtype)
    # check if x and y are valid inputs
    nx, ny = x.shape[-1], y.shape[-1]
    if (nx < 5) or (ny < 5):  # only used by test_axis_nan_policy
        raise ValueError('x and y should have at least 5 elements, but len(x) '
                         f'= {nx} and len(y) = {ny}.')
    n = nx + ny

    # check if t is valid
    if t.ndim > 1:
        raise ValueError(f't must be 1d, but t.ndim equals {t.ndim}.')
    if np.any(t <= 0):
        raise ValueError('t must contain positive elements only.')

    # Previously, non-finite input caused an error in linalg functions.
    # To prevent an issue in one slice from halting the calculation, replace non-finite
    # values with a harmless one, and replace results with NaN at the end.
    i_x = ~np.isfinite(x)
    i_y = ~np.isfinite(y)
    x = xpx.at(x)[i_x].set(1)
    y = xpx.at(y)[i_y].set(1)
    invalid_result = np.any(i_x, axis=-1) | np.any(i_y, axis=-1)

    # rescale t with semi-iqr as proposed in [1]; import iqr here to avoid
    # circular import
    from scipy.stats import iqr