ronantakizawa/codereview-bench huggingface dataset:
Repository: scipy/scipy
File: scipy/stats/tests/test_discrete_basic.py (Python)

Code before:
    # gh-18919 reported incorrect results for ppf and isf of discrete distributions when
    # arguments were arrays and first argument (`q`) had elements at the boundaries of
    # the support.
    q = [[0.5, 1.0, 0.5],
         [1.0, 0.5, 1.0],
         [0.5, 1.0, 0.5]]

    n = [[45, 46, 47],
         [48, 49, 50],
         [51, 52, 53]]

    p = 0.5

    ref = _ufuncs._binom_ppf(q, n, p)
    res = stats.binom.ppf(q, n, p)
    np.testing.assert_allclose(res, ref)

def test_gh18919_ppf_isf_array_args2():
    # a more general version of the test above. Requires that arguments are broadcasted
    # by the infrastructure.
    rng = np.random.default_rng(34873457824358729823)
    q = rng.random(size=(30, 1, 1, 1))
    n = rng.integers(10, 30, size=(10, 1, 1))
    p = rng.random(size=(4, 1))
    loc = rng.integers(5, size=(3,))

    q[rng.random(size=30) > 0.7] = 0
    q[rng.random(size=30) > 0.7] = 1

    res = stats.binom.ppf(q, n, p, loc=loc)
    ref = _ufuncs._binom_ppf(q, n, p) + loc
    ref[np.broadcast_to(q, ref.shape) == 0] -= 1
    np.testing.assert_allclose(res, ref)

    res = stats.binom.isf(q, n, p, loc=loc)
    ref = _ufuncs._binom_isf(q, n, p) + loc
    ref[np.broadcast_to(q, ref.shape) == 1] -= 1
    np.testing.assert_allclose(res, ref)


Review comment (bug):
Rather than broadcasting all the arrays from the outset using `np.broadcast`, the old infrastructure broadcasts every once in a while with idioms like `*(cond == cond)` - multiplication with an all-true array of the right shape. This is another source of potential bugs, so check that the right thing is happening when all the arrays are of different (but compatible) shapes.

Code after:
    # gh-18919 reported incorrect results for ppf and isf of discrete distributions when
    # arguments were arrays and first argument (`q`) had elements at the boundaries of
    # the support.
    q = [[0.5, 1.0, 0.5],
         [1.0, 0.5, 1.0],
         [0.5, 1.0, 0.5]]

    n = [[45, 46, 47],
         [48, 49, 50],
         [51, 52, 53]]

    p = 0.5

    ref = _ufuncs._binom_ppf(q, n, p)
    res = stats.binom.ppf(q, n, p)
    np.testing.assert_allclose(res, ref)

@pytest.mark.parametrize("dist", [stats.binom, stats.boltzmann])
def test_gh18919_ppf_isf_array_args2(dist):
    # a more general version of the test above. Requires that arguments are broadcasted
    # by the infrastructure.
    rng = np.random.default_rng(34873457824358729823)
    q = rng.random(size=(30, 1, 1, 1))
    n = rng.integers(10, 30, size=(10, 1, 1))
    p = rng.random(size=(4, 1))
    loc = rng.integers(5, size=(3,))

    q[rng.random(size=30) > 0.7] = 0
    q[rng.random(size=30) > 0.7] = 1

    args = (q, n, p) if dist == stats.binom else (q, p, n)

    res = dist.ppf(*args, loc=loc)
    ref = np.vectorize(dist.ppf)(*args) + loc
    np.testing.assert_allclose(res, ref)

    res = dist.isf(*args, loc=loc)
    ref = np.vectorize(dist.isf)(*args) + loc
    np.testing.assert_allclose(res, ref)
Repository: scipy/scipy
File: scipy/special/tests/test_cdflib.py (Python)

Code before:
def test_chdtriv_p_equals_1_returns_0(x):
    assert sp.chdtriv(1, x) == 0


class TestPdtrik:
    @pytest.mark.parametrize("p, m, expected",
                             [(0, 0.5, 0),
                              (0.5, 0, 0),
                              (0, 0, 0)])
    def test_edge_cases(self, p, m, expected):
        assert sp.pdtrik(p, m) == expected

    @pytest.mark.parametrize("m", (0.1, 1, 10))
    def test_p_equals_1_returns_nan(self, m):
        assert np.isnan(sp.pdtrik(1, m))

    def test_small_probabilities(self):
        # Edge case: m = 0 or very small.
        k = sp.pdtrik([[0], [0.25], [0.95]], [0, 1e-20, 1e-6])
        assert_array_equal(k, np.zeros((3, 3)))

    def test_roundtrip_against_pdtr(self):
        m = [10, 50, 500]
        k = 5
        p = sp.pdtr(k, m)
        assert_allclose(sp.pdtrik(p, m), k, atol=1.5e-7, rtol=0)

    @pytest.mark.parametrize("p, m, k",
                             [(1.8976107553682285e-40, 100, 2),
                              (0.48670120172085135, 100, 99),
                              (8.30383406699052e-69, 1000, 500),
                              (2.252837804125894e-227, 100_000, 90_000)]
                            )
    def test_accuracy(self, p, m, k):
        # Reference values for p were computed with mpmath using
        # mp.gammainc(k+1, a=m, regularized=True)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)


Review comment (suggestion):
The computed results are much more precise than suggested by `atol=1.5e-7`, and indeed we should expect (and test for) better precision than that.  `rtol=1e-15` works on my computer.
```suggestion
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)
```

Code after:
def test_chdtriv_p_equals_1_returns_0(x):
    assert sp.chdtriv(1, x) == 0


class TestPdtrik:
    @pytest.mark.parametrize("p, m, expected",
                             [(0, 0.5, 0),
                              (0.5, 0, 0)])
    def test_edge_cases(self, p, m, expected):
        assert sp.pdtrik(p, m) == expected

    @pytest.mark.parametrize("m", (0.1, 1, 10))
    def test_p_equals_1_returns_nan(self, m):
        assert np.isnan(sp.pdtrik(1, m))

    def test_small_probabilities(self):
        # Edge case: m = 0 or very small.
        k = sp.pdtrik([[0], [0.25], [0.95]], [0, 1e-20, 1e-6])
        assert_array_equal(k, np.zeros((3, 3)))

    def test_roundtrip_against_pdtr(self):
        m = [10, 50, 500]
        k = 5
        p = sp.pdtr(k, m)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)

    @pytest.mark.parametrize("p, m, k",
                             [(1.8976107553682285e-40, 100, 2),
                              (0.48670120172085135, 100, 99),
                              (8.30383406699052e-69, 1000, 500),
                              (2.252837804125894e-227, 100_000, 90_000)])
    def test_accuracy(self, p, m, k):
        # Reference values for p were computed with mpmath using
        # mp.gammainc(k+1, a=m, regularized=True)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)
Repository: scipy/scipy
File: scipy/special/tests/test_cdflib.py (Python)

Code before:
                              (0.5, 0, 0),
                              (0, 0, 0)])
    def test_edge_cases(self, p, m, expected):
        assert sp.pdtrik(p, m) == expected

    @pytest.mark.parametrize("m", (0.1, 1, 10))
    def test_p_equals_1_returns_nan(self, m):
        assert np.isnan(sp.pdtrik(1, m))

    def test_small_probabilities(self):
        # Edge case: m = 0 or very small.
        k = sp.pdtrik([[0], [0.25], [0.95]], [0, 1e-20, 1e-6])
        assert_array_equal(k, np.zeros((3, 3)))

    def test_roundtrip_against_pdtr(self):
        m = [10, 50, 500]
        k = 5
        p = sp.pdtr(k, m)
        assert_allclose(sp.pdtrik(p, m), k, atol=1.5e-7, rtol=0)

    @pytest.mark.parametrize("p, m, k",
                             [(1.8976107553682285e-40, 100, 2),
                              (0.48670120172085135, 100, 99),
                              (8.30383406699052e-69, 1000, 500),
                              (2.252837804125894e-227, 100_000, 90_000)]
                            )
    def test_accuracy(self, p, m, k):
        # Reference values for p were computed with mpmath using
        # mp.gammainc(k+1, a=m, regularized=True)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)


Review comment (suggestion):
Style nit: this exact formatting case is covered in PEP 8:
```suggestion
                              (2.252837804125894e-227, 100_000, 90_000)])
```

Code after:
                              (0.5, 0, 0)])
    def test_edge_cases(self, p, m, expected):
        assert sp.pdtrik(p, m) == expected

    @pytest.mark.parametrize("m", (0.1, 1, 10))
    def test_p_equals_1_returns_nan(self, m):
        assert np.isnan(sp.pdtrik(1, m))

    def test_small_probabilities(self):
        # Edge case: m = 0 or very small.
        k = sp.pdtrik([[0], [0.25], [0.95]], [0, 1e-20, 1e-6])
        assert_array_equal(k, np.zeros((3, 3)))

    def test_roundtrip_against_pdtr(self):
        m = [10, 50, 500]
        k = 5
        p = sp.pdtr(k, m)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)

    @pytest.mark.parametrize("p, m, k",
                             [(1.8976107553682285e-40, 100, 2),
                              (0.48670120172085135, 100, 99),
                              (8.30383406699052e-69, 1000, 500),
                              (2.252837804125894e-227, 100_000, 90_000)])
    def test_accuracy(self, p, m, k):
        # Reference values for p were computed with mpmath using
        # mp.gammainc(k+1, a=m, regularized=True)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)
Repository: scipy/scipy
File: scipy/special/tests/test_cdflib.py (Python)

Code before:

@pytest.mark.parametrize("a, b, p, ref", [
    (0, 0, 0, np.nan),
    (0, 0, 1, np.nan),
    (0, np.inf, 0, np.nan),
    (0, np.inf, 1, np.nan),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, 1, np.nan),
    (np.inf, np.inf, 0, np.nan),
    (np.inf, np.inf, 1, np.nan)
])
def test_gdtrix_edge_cases(a, b, p, ref):
    assert_allclose(sp.gdtrix(a, b, p), ref, rtol=0)

@pytest.mark.parametrize("p, b, x, ref", [
    (0, 0, 0, np.nan),
    (0, 0, np.inf, np.nan),
    (0, 1, 0, np.nan),
    (0, 1, np.inf, 0),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, np.inf, np.nan),
    (np.inf, 1, 0, np.nan),
    (np.inf, 1, np.inf, np.nan)
])
def test_gdtria_edge_cases(p, b, x, ref):
    assert_allclose(sp.gdtria(p, b, x), ref, rtol=0)


Review comment (suggestion):
```suggestion
    assert_equal(sp.gdtria(p, b, x), ref)
```


Code after:

@pytest.mark.parametrize("a, b, p, ref", [
    (0, 0, 0, np.nan),
    (0, 0, 1, np.nan),
    (0, np.inf, 0, np.nan),
    (0, np.inf, 1, np.nan),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, 1, np.nan),
    (np.inf, np.inf, 0, np.nan),
    (np.inf, np.inf, 1, np.nan)
])
def test_gdtrix_edge_cases(a, b, p, ref):
    assert_equal(sp.gdtrix(a, b, p), ref)

@pytest.mark.parametrize("p, b, x, ref", [
    (0, 0, 0, np.nan),
    (0, 0, np.inf, np.nan),
    (0, 1, 0, np.nan),
    (0, 1, np.inf, 0),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, np.inf, np.nan),
    (np.inf, 1, 0, np.nan),
    (np.inf, 1, np.inf, np.nan)
])
def test_gdtria_edge_cases(p, b, x, ref):
    assert_equal(sp.gdtria(p, b, x), ref)
Repository: scipy/scipy
File: scipy/special/tests/test_cdflib.py (Python)

Code before:
                              (0.48670120172085135, 100, 99),
                              (8.30383406699052e-69, 1000, 500),
                              (2.252837804125894e-227, 100_000, 90_000)])
    def test_accuracy(self, p, m, k):
        # Reference values for p were computed with mpmath using
        # mp.gammainc(k+1, a=m, regularized=True)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)

@pytest.mark.parametrize("a, b, p, ref", [
    (0, 0, 0, np.nan),
    (0, 0, 1, np.nan),
    (0, np.inf, 0, np.nan),
    (0, np.inf, 1, np.nan),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, 1, np.nan),
    (np.inf, np.inf, 0, np.nan),
    (np.inf, np.inf, 1, np.nan)
])
def test_gdtrix_edge_cases(a, b, p, ref):
    assert_allclose(sp.gdtrix(a, b, p), ref, rtol=0)

@pytest.mark.parametrize("p, b, x, ref", [
    (0, 0, 0, np.nan),
    (0, 0, np.inf, np.nan),
    (0, 1, 0, np.nan),
    (0, 1, np.inf, 0),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, np.inf, np.nan),
    (np.inf, 1, 0, np.nan),
    (np.inf, 1, np.inf, np.nan)
])
def test_gdtria_edge_cases(p, b, x, ref):
    assert_allclose(sp.gdtria(p, b, x), ref, rtol=0)


Review comment (suggestion):
I think `gdtria(0, 1, inf)` should be `nan`; `a = 0` is not a meaningful limit for the gamma distribution. Note that `gdtr(0, 1, inf)` returns `nan`.  But it looks like returning 0 is consistent with SciPy 1.16.3, so it should be OK to put off rationalizing the special cases in a follow-up.

Code after:
                              (0.48670120172085135, 100, 99),
                              (8.30383406699052e-69, 1000, 500),
                              (2.252837804125894e-227, 100_000, 90_000)])
    def test_accuracy(self, p, m, k):
        # Reference values for p were computed with mpmath using
        # mp.gammainc(k+1, a=m, regularized=True)
        assert_allclose(sp.pdtrik(p, m), k, rtol=1e-15)

@pytest.mark.parametrize("a, b, p, ref", [
    (0, 0, 0, np.nan),
    (0, 0, 1, np.nan),
    (0, np.inf, 0, np.nan),
    (0, np.inf, 1, np.nan),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, 1, np.nan),
    (np.inf, np.inf, 0, np.nan),
    (np.inf, np.inf, 1, np.nan)
])
def test_gdtrix_edge_cases(a, b, p, ref):
    assert_equal(sp.gdtrix(a, b, p), ref)

@pytest.mark.parametrize("p, b, x, ref", [
    (0, 0, 0, np.nan),
    (0, 0, np.inf, np.nan),
    (0, 1, 0, np.nan),
    (0, 1, np.inf, 0),
    (np.inf, 0, 0, np.nan),
    (np.inf, 0, np.inf, np.nan),
    (np.inf, 1, 0, np.nan),
    (np.inf, 1, np.inf, np.nan)
])
def test_gdtria_edge_cases(p, b, x, ref):
    assert_equal(sp.gdtria(p, b, x), ref)
Repository: scipy/scipy
File: scipy/interpolate/_fitpack_py.py (Python)

Code before:
        # NB: if c array is 1D, transposes are no-ops
        sh = tuple(range(c.ndim))
        c = c.transpose(sh[1:] + (0,))
        t_, c_, k_ = _impl.insert(x, (t, c, k), m, per)

        # and roll the last axis back
        c_ = np.asarray(c_)
        c_ = c_.transpose((sh[-1],) + sh[:-1])
        return BSpline(t_, c_, k_)
    else:
        return _impl.insert(x, tck, m, per)


@xp_capabilities(out_of_scope=True)
def splder(tck, n=1):
    """
    Compute the spline representation of the derivative of a given spline

    .. legacy:: function

        Specifically, we recommend constructing a `BSpline` object and using its
        ``derivative`` method.

    Parameters
    ----------
    tck : BSpline instance or tuple@xp_capabilities(out_of_scope=True)
        BSpline instance or a tuple (t,c,k) containing the vector of knots,
        the B-spline coefficients, and the degree of the spline whose 
        derivative to compute
    n : int, optional
        Order of derivative to evaluate. Default: 1

    Returns
    -------
    `BSpline` instance or tuple
        Spline of order k2=k-n representing the derivative
        of the input spline.
        A tuple is returned if the input argument `tck` is a tuple, otherwise
        a BSpline object is constructed and returned.

    See Also
    --------
    splantider, splev, spalde
    BSpline

    Notes
    -----

    .. versionadded:: 0.13.0

    Examples

Review comment (suggestion):
```suggestion
    tck : BSpline instance or tuple
```

Code after:
        # NB: if c array is 1D, transposes are no-ops
        sh = tuple(range(c.ndim))
        c = c.transpose(sh[1:] + (0,))
        t_, c_, k_ = _impl.insert(x, (t, c, k), m, per)

        # and roll the last axis back
        c_ = np.asarray(c_)
        c_ = c_.transpose((sh[-1],) + sh[:-1])
        return BSpline(t_, c_, k_)
    else:
        return _impl.insert(x, tck, m, per)


@xp_capabilities(out_of_scope=True)
def splder(tck, n=1):
    """
    Compute the spline representation of the derivative of a given spline

    .. legacy:: function

        Specifically, we recommend constructing a `BSpline` object and using its
        ``derivative`` method.

    Parameters
    ----------
    tck : BSpline instance or tuple
        BSpline instance or a tuple (t,c,k) containing the vector of knots,
        the B-spline coefficients, and the degree of the spline whose 
        derivative to compute
    n : int, optional
        Order of derivative to evaluate. Default: 1

    Returns
    -------
    `BSpline` instance or tuple
        Spline of order k2=k-n representing the derivative
        of the input spline.
        A tuple is returned if the input argument `tck` is a tuple, otherwise
        a BSpline object is constructed and returned.

    See Also
    --------
    splantider, splev, spalde
    BSpline

    Notes
    -----

    .. versionadded:: 0.13.0

    Examples
Repository: scipy/scipy
File: scipy/stats/_stats_py.py (Python)

Code before:
    The proportion to trim is rounded down to the nearest integer. For
    instance, trimming 25% of the values from an array of 10 values will
    return an array of 8 values:

    >>> b = np.arange(10)
    >>> stats.trim1(b, 1/4).shape
    (8,)

    Multidimensional arrays can be trimmed along any axis or across the entire
    array:

    >>> c = [2, 4, 6, 8, 0, 1, 3, 5, 7, 9]
    >>> d = np.array([a, b, c])
    >>> stats.trim1(d, 0.8, axis=0).shape
    (1, 10)
    >>> stats.trim1(d, 0.8, axis=1).shape
    (3, 2)
    >>> stats.trim1(d, 0.8, axis=None).shape
    (6,)

    """
    a = np.asarray(a)
    if axis is None:
        a = a.ravel()
        axis = 0

    nobs = a.shape[axis]

    # avoid possible corner case
    if proportiontocut >= 1:
        return []

    if tail.lower() == 'right':
        lowercut = 0
        uppercut = nobs - int(proportiontocut * nobs)

    elif tail.lower() == 'left':
        lowercut = int(proportiontocut * nobs)
        uppercut = nobs

    atmp = np.partition(a, (lowercut, uppercut - 1), axis)

    sl = [slice(None)] * atmp.ndim
    sl[axis] = slice(lowercut, uppercut)
    return atmp[tuple(sl)]


@xp_capabilities(np_only=True)
@_axis_nan_policy_factory(lambda x: x, result_to_tuple=lambda x, _: (x,), n_outputs=1)
def trim_mean(a, proportiontocut, axis=0):
    """Return mean of array after trimming a specified fraction of extreme values

Review comment (bug):
gh-23840 does this, too, and it adds tests. 

It also makes an adjustment to the special case for empty 1D samples that should fix the `test_axis_nan_policy` failures in CI.

We can let that one merge first.

Code after:
        a = a.ravel()
        axis = 0

    nobs = a.shape[axis]

    # avoid possible corner case
    if proportiontocut >= 1:
        return []

    if tail.lower() == 'right':
        lowercut = 0
        uppercut = nobs - int(proportiontocut * nobs)

    elif tail.lower() == 'left':
        lowercut = int(proportiontocut * nobs)
        uppercut = nobs

    atmp = np.partition(a, (lowercut, uppercut - 1), axis)

    sl = [slice(None)] * atmp.ndim
    sl[axis] = slice(lowercut, uppercut)
    return atmp[tuple(sl)]


@xp_capabilities(np_only=True)
@_axis_nan_policy_factory(lambda x: x, result_to_tuple=lambda x, _: (x,), n_outputs=1)
def trim_mean(a, proportiontocut, axis=0):
    """Return mean of array after trimming a specified fraction of extreme values

    Removes the specified proportion of elements from *each* end of the
    sorted array, then computes the mean of the remaining elements.

    Parameters
    ----------
    a : array_like
        Input array.
    proportiontocut : float
        Fraction of the most positive and most negative elements to remove.
        When the specified proportion does not result in an integer number of
        elements, the number of elements to trim is rounded down.
    axis : int or None, default: 0
        Axis along which the trimmed means are computed.
        If None, compute over the raveled array.

    Returns
    -------
    trim_mean : ndarray
        Mean of trimmed array.

    See Also
    --------
Repository: scipy/scipy
File: scipy/stats/_wilcoxon.py (Python)

Code before:
import numpy as np

from scipy import stats
from ._stats_py import _get_pvalue, _rankdata, _SimpleNormal
from . import _morestats
from ._axis_nan_policy import _broadcast_arrays
from ._hypotests import _get_wilcoxon_distr
from scipy._lib._util import _get_nan
from scipy._lib._array_api import array_namespace, xp_promote, xp_size, xp_copy
import scipy._lib.array_api_extra as xpx


class WilcoxonDistribution:

    def __init__(self, n):
        n = np.asarray(n).astype(int, copy=False)
        self.n = n
        self._dists = {ni: _get_wilcoxon_distr(ni) for ni in np.unique(n)}

    def _cdf1(self, k, n):
        pmfs = self._dists[n]
        return pmfs[:k + 1].sum()

    def _cdf(self, k, n):
        return np.vectorize(self._cdf1, otypes=[float])(k, n)

    def _sf1(self, k, n):
        pmfs = self._dists[n]
        return pmfs[k:].sum()

    def _sf(self, k, n):
        return np.vectorize(self._sf1, otypes=[float])(k, n)

    def mean(self):

Review comment (suggestion):
```suggestion
from scipy._lib._array_api import array_namespace, xp_promote, xp_size
```

Code after:
import numpy as np

from scipy import stats
from ._stats_py import _get_pvalue, _rankdata, _SimpleNormal
from . import _morestats
from ._axis_nan_policy import _broadcast_arrays
from ._hypotests import _get_wilcoxon_distr
from scipy._lib._util import _get_nan
from scipy._lib._array_api import array_namespace, xp_promote, xp_size
import scipy._lib.array_api_extra as xpx


class WilcoxonDistribution:

    def __init__(self, n):
        n = np.asarray(n).astype(int, copy=False)
        self.n = n
        self._dists = {ni: _get_wilcoxon_distr(ni) for ni in np.unique(n)}

    def _cdf1(self, k, n):
        pmfs = self._dists[n]
        return pmfs[:k + 1].sum()

    def _cdf(self, k, n):
        return np.vectorize(self._cdf1, otypes=[float])(k, n)

    def _sf1(self, k, n):
        pmfs = self._dists[n]
        return pmfs[k:].sum()

    def _sf(self, k, n):
        return np.vectorize(self._sf1, otypes=[float])(k, n)

    def mean(self):
Repository: scipy/scipy
File: benchmarks/benchmarks/integrate.py (Python)

Code before:
                "epsabs": self.rtol,
            },
        )


class NquadOscillatory(Benchmark):
    params = (
        # input dimension of integrand (ndim)
        [1, 3, 5],

        # rtol
        [1e-10, 1e-11],
    )

    param_names = ["ndim", "rtol"]

    def setup(self, ndim, rtol):
        self.ndim = ndim

        self.rtol = rtol
        self.atol = 0

        self.ranges = [(0, 1) for _ in range(self.ndim)]

        if ndim == 5 and not is_xslow():
            raise SkipNotImplemented(f"Takes too long to run in CI")

    def f(self, *x):
        x_arr = np.array(x)
        r = 0.5
        alphas = np.repeat(0.1, self.ndim)

        return np.cos(2*np.pi*r + np.sum(alphas * x_arr, axis=-1))

    def time_oscillatory(self, ndim, rtol):
        nquad(
            func=self.f,
            ranges=self.ranges,
            opts={
                "epsabs": self.rtol,
            },
        )


class QuadVecOscillatory(Benchmark):
    params = (
        # output dimension of integrand (fdim)
        [1, 5, 8],

        # rtol
        [1e-10, 1e-11],

Review comment (refactor):
```suggestion
            raise SkipNotImplemented("Takes too long to run in CI")
```

Code after:
                "epsabs": self.rtol,
            },
        )


class NquadOscillatory(Benchmark):
    params = (
        # input dimension of integrand (ndim)
        [1, 3, 5],

        # rtol
        [1e-10, 1e-11],
    )

    param_names = ["ndim", "rtol"]

    def setup(self, ndim, rtol):
        self.ndim = ndim

        self.rtol = rtol
        self.atol = 0

        self.ranges = [(0, 1) for _ in range(self.ndim)]

        if ndim == 5 and not is_xslow():
            raise SkipNotImplemented("Takes too long to run in CI")

    def f(self, *x):
        x_arr = np.array(x)
        r = 0.5
        alphas = np.repeat(0.1, self.ndim)

        return np.cos(2*np.pi*r + np.sum(alphas * x_arr, axis=-1))

    def time_oscillatory(self, ndim, rtol):
        nquad(
            func=self.f,
            ranges=self.ranges,
            opts={
                "epsabs": self.rtol,
            },
        )


class QuadVecOscillatory(Benchmark):
    params = (
        # output dimension of integrand (fdim)
        [1, 5, 8],

        # rtol
        [1e-10, 1e-11],