Repository: scipy/scipy
File: scipy/stats/tests/test_distributions.py (Python)

Code before:
        # be represented on the unlogged scale. See: gh-13616
        logcdf = stats.invgauss.logcdf(0.0001, mu=1.05)
        assert_allclose(logcdf, -5003.87872590367)
        logcdf = stats.invgauss.logcdf(110, 1.05)
        assert_allclose(logcdf, -4.12851625944087e-25)
        logsf = stats.invgauss.logsf(0.001, mu=1.05)
        assert_allclose(logsf, -4.65246506892676e-219)
        logsf = stats.invgauss.logsf(110, 1.05)
        assert_allclose(logsf, -56.1467092416426)

    # from mpmath import mp
    # mp.dps = 100
    # mu = mp.mpf(1e-2)
    # ref = (1/2 * mp.log(2 * mp.pi * mp.e * mu**3)
    #        - 3/2* mp.exp(2/mu) * mp.e1(2/mu))
    @pytest.mark.parametrize("mu, ref", [(2e-8, -25.172361826883957),
                                         (1e-3, -8.943444010642972),
                                         (1e-2, -5.4962796152622335),
                                         (1e8, 3.3244822568873476),
                                         (1e100, 3.32448280139689)])
    def test_entropy(self, mu, ref):
        assert_allclose(stats.invgauss.entropy(mu), ref, rtol=5e-14)


class TestLandau:
    @pytest.mark.fail_slow(60)
    def test_precision_pdf(self):
        # Compare the Landau distribution against the more general
        # Levy stable distribution, which should be exactly the same.

        for loc in [-99, -5, 0, 5, 99]:
            for scale in [1]:
                # Only testing scale=1 because of BUG #19140.

                err_msg = f'landau parameters: loc={loc}, scale={scale}'

                # In the range where most of the weight is located, we find up
                # to 8 digits of agreement between the two distributions.
                # Between 188 and 190, the levy_stable PDF has a discrete jump
                # and this breaks the agreement between the two distributions.
                x_values = np.linspace(loc-5*scale, loc+180*scale, 999)
                landau = stats.landau.pdf(x_values, loc=loc, scale=scale)
                expected = stats.levy_stable(alpha=1, beta=1, loc=loc,
                                             scale=scale).pdf(x_values)
                assert_almost_equal(landau, expected, decimal=8, err_msg=err_msg)

                # After the discrete jump, the precision is worse but still good
                # enough with 5 digits.
                x_values = np.linspace(loc+180*scale, loc+9999*scale, 99)
                landau = stats.landau.pdf(x_values, loc=loc, scale=scale)
                expected = stats.levy_stable(alpha=1, beta=1, loc=loc,

Review comment (performance):
These tests are quite slow. I don't think we need to test at multiple location parameters, and we don't need to test at 999 points. One thought is to leave them as they are, mark them `xslow`, and then just add a much faster test for a few points at `loc=0`. ~~Does something like that sound good?~~ On second thought, I think we should trim them down considerably. I run `xslow` tests some time, and I don't think it's worth the time to compare at so many points. We just need to check enough points to convince us that this is indeed the Landau distribution, IMO.

Code after:
        # be represented on the unlogged scale. See: gh-13616
        logcdf = stats.invgauss.logcdf(0.0001, mu=1.05)
        assert_allclose(logcdf, -5003.87872590367)
        logcdf = stats.invgauss.logcdf(110, 1.05)
        assert_allclose(logcdf, -4.12851625944087e-25)
        logsf = stats.invgauss.logsf(0.001, mu=1.05)
        assert_allclose(logsf, -4.65246506892676e-219)
        logsf = stats.invgauss.logsf(110, 1.05)
        assert_allclose(logsf, -56.1467092416426)

    # from mpmath import mp
    # mp.dps = 100
    # mu = mp.mpf(1e-2)
    # ref = (1/2 * mp.log(2 * mp.pi * mp.e * mu**3)
    #        - 3/2* mp.exp(2/mu) * mp.e1(2/mu))
    @pytest.mark.parametrize("mu, ref", [(2e-8, -25.172361826883957),
                                         (1e-3, -8.943444010642972),
                                         (1e-2, -5.4962796152622335),
                                         (1e8, 3.3244822568873476),
                                         (1e100, 3.32448280139689)])
    def test_entropy(self, mu, ref):
        assert_allclose(stats.invgauss.entropy(mu), ref, rtol=5e-14)


class TestLandau:
    @pytest.mark.parametrize('name', ['pdf', 'cdf', 'sf', 'ppf', 'isf'])
    def test_landau_levy_agreement(self, name):
        # Test PDF to confirm that this is the Landau distribution
        # Test other methods with tighter tolerance than generic tests
        # Levy entropy is slow and inaccurate, and RVS is tested generically
        if name in {'ppf', 'isf'}:
            x = np.linspace(0.1, 0.9, 5),
        else:
            x = np.linspace(-2, 5, 10),

        landau_method = getattr(stats.landau, name)
        levy_method = getattr(stats.levy_stable, name)
        res = landau_method(*x)
        ref = levy_method(*x, 1, 1)
        assert_allclose(res, ref, rtol=1e-14)

    def test_moments(self):
        # I would test these against Levy above, but Levy says variance is infinite.
        assert_equal(stats.landau.stats(moments='mvsk'), (np.nan,)*4)
        assert_equal(stats.landau.moment(5), np.nan)


class TestLaplace:
    @pytest.mark.parametrize("rvs_loc", [-5, 0, 1, 2])
    @pytest.mark.parametrize("rvs_scale", [1, 2, 3, 10])
    def test_fit(self, rvs_loc, rvs_scale):