From a4095e813e95f33a49eb04e3e0a912485cd32059 Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 16:00:04 +0000 Subject: [PATCH 1/7] Exponential --- pymc/distributions/continuous.py | 6 ++++++ pymc/tests/test_distributions_moments.py | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index 88cdfc8690..9c3b60973e 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -1399,6 +1399,12 @@ def dist(cls, lam, *args, **kwargs): # Aesara exponential op is parametrized in terms of mu (1/lam) return super().dist([at.inv(lam)], **kwargs) + def get_moment(rv, size, lam): + mean = 1 / lam + if not rv_size_is_none(size): + mean = at.full(size, mean) + return mean + def logcdf(value, mu): r""" Compute the log of cumulative distribution function for the Exponential distribution diff --git a/pymc/tests/test_distributions_moments.py b/pymc/tests/test_distributions_moments.py index 26a76640ef..2a9472aecf 100644 --- a/pymc/tests/test_distributions_moments.py +++ b/pymc/tests/test_distributions_moments.py @@ -2,7 +2,7 @@ import pytest from pymc import Bernoulli, Flat, HalfFlat, Normal, TruncatedNormal, Uniform -from pymc.distributions import Beta, HalfNormal +from pymc.distributions import Beta, Exponential, HalfNormal from pymc.distributions.shape_utils import rv_size_is_none from pymc.initial_point import make_initial_point_fn from pymc.model import Model @@ -157,3 +157,18 @@ def test_beta_moment(alpha, beta, size, expected): with Model() as model: Beta("x", alpha=alpha, beta=beta, size=size) assert_moment_is_expected(model, expected) + + +@pytest.mark.parametrize( + "lam, size, expected", + [ + (2, None, 0.5), + (2, 5, np.full(5, 0.5)), + (np.arange(1, 5), None, 1 / np.arange(1, 5)), + (np.arange(1, 5), (2, 4), np.full((2, 4), 1 / np.arange(1, 5))), + ], +) +def test_exponential_moment(lam, size, expected): + with Model() as model: + Exponential("x", lam=lam, size=size) + assert_moment_is_expected(model, expected) From 3a3e8c7940b7e3f0f06319cbc1e3135ce4a00635 Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 16:21:37 +0000 Subject: [PATCH 2/7] Laplace --- pymc/distributions/continuous.py | 6 ++++++ pymc/tests/test_distributions_moments.py | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index 9c3b60973e..cd8d190ed1 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -1481,6 +1481,12 @@ def dist(cls, mu, b, *args, **kwargs): assert_negative_support(b, "b", "Laplace") return super().dist([mu, b], *args, **kwargs) + def get_moment(rv, size, mu, b): + mu, _ = at.broadcast_arrays(mu, b) + if not rv_size_is_none(size): + mu = at.full(size, mu) + return mu + def logcdf(value, mu, b): """ Compute the log of the cumulative distribution function for Laplace distribution diff --git a/pymc/tests/test_distributions_moments.py b/pymc/tests/test_distributions_moments.py index 2a9472aecf..bdcb7a4c39 100644 --- a/pymc/tests/test_distributions_moments.py +++ b/pymc/tests/test_distributions_moments.py @@ -2,7 +2,7 @@ import pytest from pymc import Bernoulli, Flat, HalfFlat, Normal, TruncatedNormal, Uniform -from pymc.distributions import Beta, Exponential, HalfNormal +from pymc.distributions import Beta, Exponential, HalfNormal, Laplace from pymc.distributions.shape_utils import rv_size_is_none from pymc.initial_point import make_initial_point_fn from pymc.model import Model @@ -172,3 +172,18 @@ def test_exponential_moment(lam, size, expected): with Model() as model: Exponential("x", lam=lam, size=size) assert_moment_is_expected(model, expected) + + +@pytest.mark.parametrize( + "mu, b, size, expected", + [ + (0, 1, None, 0), + (0, np.ones(5), None, np.zeros(5)), + (np.arange(5), 1, None, np.arange(5)), + (np.arange(5), np.arange(1, 6), (2, 5), np.full((2, 5), np.arange(5))), + ], +) +def test_laplace_moment(mu, b, size, expected): + with Model() as model: + Laplace("x", mu=mu, b=b, size=size) + assert_moment_is_expected(model, expected) From 62d7315396463ff451089b72ccc7c7d7c141ed3f Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 16:33:14 +0000 Subject: [PATCH 3/7] StudentT --- pymc/distributions/continuous.py | 6 ++++++ pymc/tests/test_distributions_moments.py | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index cd8d190ed1..94c0b98b23 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -1812,6 +1812,12 @@ def dist(cls, nu, mu=0, lam=None, sigma=None, sd=None, *args, **kwargs): return super().dist([nu, mu, sigma], **kwargs) + def get_moment(rv, size, nu, mu, sigma): + mu, _, _ = at.broadcast_arrays(mu, nu, sigma) + if not rv_size_is_none(size): + mu = at.full(size, mu) + return mu + def logp(value, nu, mu, sigma): """ Calculate log-probability of StudentT distribution at specified value. diff --git a/pymc/tests/test_distributions_moments.py b/pymc/tests/test_distributions_moments.py index bdcb7a4c39..76f75047b9 100644 --- a/pymc/tests/test_distributions_moments.py +++ b/pymc/tests/test_distributions_moments.py @@ -2,7 +2,7 @@ import pytest from pymc import Bernoulli, Flat, HalfFlat, Normal, TruncatedNormal, Uniform -from pymc.distributions import Beta, Exponential, HalfNormal, Laplace +from pymc.distributions import Beta, Exponential, HalfNormal, Laplace, StudentT from pymc.distributions.shape_utils import rv_size_is_none from pymc.initial_point import make_initial_point_fn from pymc.model import Model @@ -187,3 +187,18 @@ def test_laplace_moment(mu, b, size, expected): with Model() as model: Laplace("x", mu=mu, b=b, size=size) assert_moment_is_expected(model, expected) + + +@pytest.mark.parametrize( + "mu, nu, sigma, size, expected", + [ + (0, 1, 1, None, 0), + (0, np.ones(5), 1, None, np.zeros(5)), + (np.arange(5), 10, np.arange(1, 6), None, np.arange(5)), + (np.arange(5), 10, np.arange(1, 6), (2, 5), np.full((2, 5), np.arange(5))), + ], +) +def test_studentt_moment(mu, nu, sigma, size, expected): + with Model() as model: + StudentT("x", mu=mu, nu=nu, sigma=sigma, size=size) + assert_moment_is_expected(model, expected) From 4ca4bf59c873f97a4ca4aa50ff2cae1962eac068 Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 16:42:16 +0000 Subject: [PATCH 4/7] Cauchy --- pymc/distributions/continuous.py | 15 +++++++++------ pymc/tests/test_distributions_moments.py | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index 94c0b98b23..193c10380d 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -1400,10 +1400,10 @@ def dist(cls, lam, *args, **kwargs): return super().dist([at.inv(lam)], **kwargs) def get_moment(rv, size, lam): - mean = 1 / lam + mu = 1 / lam if not rv_size_is_none(size): - mean = at.full(size, mean) - return mean + mu = at.full(size, mu) + return mu def logcdf(value, mu): r""" @@ -2019,12 +2019,15 @@ def dist(cls, alpha, beta, *args, **kwargs): alpha = at.as_tensor_variable(floatX(alpha)) beta = at.as_tensor_variable(floatX(beta)) - # median = alpha - # mode = alpha - assert_negative_support(beta, "beta", "Cauchy") return super().dist([alpha, beta], **kwargs) + def get_moment(rv, size, alpha, beta): + alpha, _ = at.broadcast_arrays(alpha, beta) + if not rv_size_is_none(size): + alpha = at.full(size, median) + return alpha + def logcdf(value, alpha, beta): """ Compute the log of the cumulative distribution function for Cauchy distribution diff --git a/pymc/tests/test_distributions_moments.py b/pymc/tests/test_distributions_moments.py index 76f75047b9..3b257576c5 100644 --- a/pymc/tests/test_distributions_moments.py +++ b/pymc/tests/test_distributions_moments.py @@ -2,7 +2,7 @@ import pytest from pymc import Bernoulli, Flat, HalfFlat, Normal, TruncatedNormal, Uniform -from pymc.distributions import Beta, Exponential, HalfNormal, Laplace, StudentT +from pymc.distributions import Beta, Cauchy, Exponential, HalfNormal, Laplace, StudentT from pymc.distributions.shape_utils import rv_size_is_none from pymc.initial_point import make_initial_point_fn from pymc.model import Model @@ -202,3 +202,18 @@ def test_studentt_moment(mu, nu, sigma, size, expected): with Model() as model: StudentT("x", mu=mu, nu=nu, sigma=sigma, size=size) assert_moment_is_expected(model, expected) + + +@pytest.mark.parametrize( + "alpha, beta, size, expected", + [ + (0, 1, None, 0), + (0, np.ones(5), None, np.zeros(5)), + (np.arange(5), 1, None, np.arange(5)), + (np.arange(5), np.arange(1, 6), (2, 5), np.full((2, 5), np.arange(5))), + ], +) +def test_cauchy_moment(alpha, beta, size, expected): + with Model() as model: + Cauchy("x", alpha=alpha, beta=beta, size=size) + assert_moment_is_expected(model, expected) From 3a08b9a38c4eaabdb9f721677f5097c23058cdc1 Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 17:03:46 +0000 Subject: [PATCH 5/7] Kumaraswamy --- pymc/distributions/continuous.py | 6 ++++++ pymc/tests/test_distributions_moments.py | 26 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index 193c10380d..a1c29854e3 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -1313,6 +1313,12 @@ def dist(cls, a, b, *args, **kwargs): return super().dist([a, b], *args, **kwargs) + def get_moment(rv, size, a, b): + mean = at.exp(at.log(b) + at.gammaln(1 + 1 / a) + at.gammaln(b) - at.gammaln(1 + 1 / a + b)) + if not rv_size_is_none(size): + mean = at.full(size, mean) + return mean + def logp(value, a, b): """ Calculate log-probability of Kumaraswamy distribution at specified value. diff --git a/pymc/tests/test_distributions_moments.py b/pymc/tests/test_distributions_moments.py index 3b257576c5..d0c2d63324 100644 --- a/pymc/tests/test_distributions_moments.py +++ b/pymc/tests/test_distributions_moments.py @@ -2,7 +2,15 @@ import pytest from pymc import Bernoulli, Flat, HalfFlat, Normal, TruncatedNormal, Uniform -from pymc.distributions import Beta, Cauchy, Exponential, HalfNormal, Laplace, StudentT +from pymc.distributions import ( + Beta, + Cauchy, + Exponential, + HalfNormal, + Kumaraswamy, + Laplace, + StudentT, +) from pymc.distributions.shape_utils import rv_size_is_none from pymc.initial_point import make_initial_point_fn from pymc.model import Model @@ -217,3 +225,19 @@ def test_cauchy_moment(alpha, beta, size, expected): with Model() as model: Cauchy("x", alpha=alpha, beta=beta, size=size) assert_moment_is_expected(model, expected) + + +@pytest.mark.parametrize( + "a, b, size, expected", + [ + (1, 1, None, 0.5), + (1, 1, 5, np.full(5, 0.5)), + (1, np.arange(1, 6), None, 1 / np.arange(2, 7)), + (np.arange(1, 6), 1, None, np.arange(1, 6) / np.arange(2, 7)), + (1, np.arange(1, 6), (2, 5), np.full((2, 5), 1 / np.arange(2, 7))), + ], +) +def test_kumaraswamy_moment(a, b, size, expected): + with Model() as model: + Kumaraswamy("x", a=a, b=b, size=size) + assert_moment_is_expected(model, expected) From e383022a6a78fb5b36fa17c1235226758db50b06 Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 17:39:43 +0000 Subject: [PATCH 6/7] Fix typo --- pymc/distributions/continuous.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index a1c29854e3..5db13e9dec 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -2031,7 +2031,7 @@ def dist(cls, alpha, beta, *args, **kwargs): def get_moment(rv, size, alpha, beta): alpha, _ = at.broadcast_arrays(alpha, beta) if not rv_size_is_none(size): - alpha = at.full(size, median) + alpha = at.full(size, alpha) return alpha def logcdf(value, alpha, beta): From bab2a1e51efbae4cc718897a3a1ba1bdaf5fbe0f Mon Sep 17 00:00:00 2001 From: michaeloriordan Date: Sat, 6 Nov 2021 18:05:31 +0000 Subject: [PATCH 7/7] Lam already converted to mu in dist --- pymc/distributions/continuous.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pymc/distributions/continuous.py b/pymc/distributions/continuous.py index 5db13e9dec..f43ea7b0da 100644 --- a/pymc/distributions/continuous.py +++ b/pymc/distributions/continuous.py @@ -1405,8 +1405,7 @@ def dist(cls, lam, *args, **kwargs): # Aesara exponential op is parametrized in terms of mu (1/lam) return super().dist([at.inv(lam)], **kwargs) - def get_moment(rv, size, lam): - mu = 1 / lam + def get_moment(rv, size, mu): if not rv_size_is_none(size): mu = at.full(size, mu) return mu