diff --git a/pymc3/tests/test_distributions.py b/pymc3/tests/test_distributions.py index 2648952bb3..15028abf39 100644 --- a/pymc3/tests/test_distributions.py +++ b/pymc3/tests/test_distributions.py @@ -97,7 +97,7 @@ ) from pymc3.math import kronecker, logsumexp from pymc3.model import Deterministic, Model, Point -from pymc3.tests.helpers import SeededTest, select_by_precision +from pymc3.tests.helpers import select_by_precision from pymc3.theanof import floatX from pymc3.vartypes import continuous_types @@ -545,39 +545,75 @@ def RandomPdMatrix(n): return np.dot(A, A.T) + n * np.identity(n) -class TestMatchesScipy(SeededTest): - def pymc3_matches_scipy( +class TestMatchesScipy: + def check_logp( self, pymc3_dist, domain, paramdomains, - scipy_dist, + scipy_logp, decimal=None, + n_samples=100, extra_args=None, scipy_args=None, ): + """ + Generic test for PyMC3 logp methods + + Test PyMC3 logp and equivalent scipy logpmf/logpdf methods give similar + results for valid values and parameters inside the supported edges. + Edges are excluded by default, but can be artificially included by + creating a domain with repeated values (e.g., `Domain([0, 0, .5, 1, 1]`) + + Parameters + ---------- + pymc3_dist: PyMC3 distribution + domain : Domain + Supported domain of distribution values + paramdomains : Dictionary of Parameter : Domain pairs + Supported domains of distribution parameters + scipy_logp : Scipy logpmf/logpdf method + Scipy logp method of equivalent pymc3_dist distribution + decimal : Int + Level of precision with which pymc3_dist and scipy logp are compared. + Defaults to 6 for float64 and 3 for float32 + n_samples : Int + Upper limit on the number of valid domain and value combinations that + are compared between pymc3 and scipy methods. If n_samples is below the + total number of combinations, a random subset is evaluated. Setting + n_samples = -1, will return all possible combinations. Defaults to 100 + extra_args : Dictionary with extra arguments needed to build pymc3 model + Dictionary is passed to helper function `build_model` from which + the pymc3 distribution logp is calculated + scipy_args : Dictionary with extra arguments needed to call scipy logp method + Usually the same as extra_args + """ + if decimal is None: + decimal = select_by_precision(float64=6, float32=3) + if extra_args is None: extra_args = {} + if scipy_args is None: scipy_args = {} - model = build_model(pymc3_dist, domain, paramdomains, extra_args) - value = model.named_vars["value"] - def logp(args): + def logp_reference(args): args.update(scipy_args) - return scipy_dist(**args) + return scipy_logp(**args) - self.check_logp(model, value, domain, paramdomains, logp, decimal=decimal) + model = build_model(pymc3_dist, domain, paramdomains, extra_args) + logp = model.fastlogp - def check_logp(self, model, value, domain, paramdomains, logp_reference, decimal=None): domains = paramdomains.copy() domains["value"] = domain - logp = model.fastlogp - for pt in product(domains, n_samples=100): + for pt in product(domains, n_samples=n_samples): pt = Point(pt, model=model) - if decimal is None: - decimal = select_by_precision(float64=6, float32=3) - assert_almost_equal(logp(pt), logp_reference(pt), decimal=decimal, err_msg=str(pt)) + assert_almost_equal( + logp(pt), + logp_reference(pt), + decimal=decimal, + err_msg=str(pt), + ) def check_logcdf( self, @@ -621,8 +657,8 @@ def check_logcdf( n_samples : Int Upper limit on the number of valid domain and value combinations that are compared between pymc3 and scipy methods. If n_samples is below the - total number of combinations, a random subset is evaluated. - Defaults to 100 + total number of combinations, a random subset is evaluated. Setting + n_samples = -1, will return all possible combinations. Defaults to 100 skip_paramdomain_inside_edge_test : Bool Whether to run test 1., which checks that pymc3 and scipy distributions match for valid values and parameters inside the respective domain edges @@ -646,11 +682,12 @@ def check_logcdf( scipy_cdf = scipy_logcdf(**params) value = params.pop("value") dist = pymc3_dist.dist(**params) + params["value"] = value # for displaying in err_msg assert_almost_equal( dist.logcdf(value).tag.test_value, scipy_cdf, decimal=decimal, - err_msg=str(pt), + err_msg=str(params), ) valid_value = domain.vals[0] @@ -752,7 +789,7 @@ def checkd(self, distfam, valuedomain, vardomains, checks=None, extra_args=None) check(m, m.named_vars["value"], valuedomain, vardomains) def test_uniform(self): - self.pymc3_matches_scipy( + self.check_logp( Uniform, Runif, {"lower": -Rplusunif, "upper": Rplusunif}, @@ -767,7 +804,7 @@ def test_uniform(self): ) def test_triangular(self): - self.pymc3_matches_scipy( + self.check_logp( Triangular, Runif, {"lower": -Rplusunif, "c": Runif, "upper": Rplusunif}, @@ -783,7 +820,7 @@ def test_triangular(self): def test_bound_normal(self): PositiveNormal = Bound(Normal, lower=0.0) - self.pymc3_matches_scipy( + self.check_logp( PositiveNormal, Rplus, {"mu": Rplus, "sigma": Rplus}, @@ -795,7 +832,7 @@ def test_bound_normal(self): assert np.isinf(x.logp({"x": -1})) def test_discrete_unif(self): - self.pymc3_matches_scipy( + self.check_logp( DiscreteUniform, Rdunif, {"lower": -Rplusdunif, "upper": Rplusdunif}, @@ -815,7 +852,7 @@ def test_discrete_unif(self): ) def test_flat(self): - self.pymc3_matches_scipy(Flat, Runif, {}, lambda value: 0) + self.check_logp(Flat, Runif, {}, lambda value: 0) with Model(): x = Flat("a") assert_allclose(x.tag.test_value, 0) @@ -825,7 +862,7 @@ def test_flat(self): assert -np.inf == Flat.dist().logcdf(-np.inf).tag.test_value def test_half_flat(self): - self.pymc3_matches_scipy(HalfFlat, Rplus, {}, lambda value: 0) + self.check_logp(HalfFlat, Rplus, {}, lambda value: 0) with Model(): x = HalfFlat("a", shape=2) assert_allclose(x.tag.test_value, 1) @@ -836,7 +873,7 @@ def test_half_flat(self): assert -np.inf == HalfFlat.dist().logcdf(-np.inf).tag.test_value def test_normal(self): - self.pymc3_matches_scipy( + self.check_logp( Normal, R, {"mu": R, "sigma": Rplus}, @@ -856,7 +893,7 @@ def scipy_logp(value, mu, sigma, lower, upper): value, (lower - mu) / sigma, (upper - mu) / sigma, loc=mu, scale=sigma ) - self.pymc3_matches_scipy( + self.check_logp( TruncatedNormal, R, {"mu": R, "sigma": Rplusbig, "lower": -Rplusbig, "upper": Rplusbig}, @@ -865,7 +902,7 @@ def scipy_logp(value, mu, sigma, lower, upper): ) def test_half_normal(self): - self.pymc3_matches_scipy( + self.check_logp( HalfNormal, Rplus, {"sigma": Rplus}, @@ -880,7 +917,7 @@ def test_half_normal(self): ) def test_chi_squared(self): - self.pymc3_matches_scipy( + self.check_logp( ChiSquared, Rplus, {"nu": Rplusdunif}, @@ -892,7 +929,7 @@ def test_chi_squared(self): reason="Poor CDF in SciPy. See scipy/scipy#869 for details.", ) def test_wald_scipy(self): - self.pymc3_matches_scipy( + self.check_logp( Wald, Rplus, {"mu": Rplus, "alpha": Rplus}, @@ -936,13 +973,13 @@ def test_wald(self, value, mu, lam, phi, alpha, logp): assert_almost_equal(model.fastlogp(pt), logp, decimal=decimals, err_msg=str(pt)) def test_beta(self): - self.pymc3_matches_scipy( + self.check_logp( Beta, Unit, {"alpha": Rplus, "beta": Rplus}, lambda value, alpha, beta: sp.beta.logpdf(value, alpha, beta), ) - self.pymc3_matches_scipy(Beta, Unit, {"mu": Unit, "sigma": Rplus}, beta_mu_sigma) + self.check_logp(Beta, Unit, {"mu": Unit, "sigma": Rplus}, beta_mu_sigma) self.check_logcdf( Beta, Unit, @@ -958,10 +995,10 @@ def scipy_log_pdf(value, a, b): np.log(a) + np.log(b) + (a - 1) * np.log(value) + (b - 1) * np.log(1 - value ** a) ) - self.pymc3_matches_scipy(Kumaraswamy, Unit, {"a": Rplus, "b": Rplus}, scipy_log_pdf) + self.check_logp(Kumaraswamy, Unit, {"a": Rplus, "b": Rplus}, scipy_log_pdf) def test_exponential(self): - self.pymc3_matches_scipy( + self.check_logp( Exponential, Rplus, {"lam": Rplus}, @@ -975,7 +1012,7 @@ def test_exponential(self): ) def test_geometric(self): - self.pymc3_matches_scipy( + self.check_logp( Geometric, Nat, {"p": Unit}, @@ -1011,7 +1048,7 @@ def modified_scipy_hypergeom_logcdf(value, N, k, n): return original_res if not np.isnan(original_res) else -np.inf - self.pymc3_matches_scipy( + self.check_logp( HyperGeometric, Nat, {"N": NatSmall, "k": NatSmall, "n": NatSmall}, @@ -1036,13 +1073,13 @@ def scipy_mu_alpha_logpmf(value, mu, alpha): def scipy_mu_alpha_logcdf(value, mu, alpha): return sp.nbinom.logcdf(value, alpha, 1 - mu / (mu + alpha)) - self.pymc3_matches_scipy( + self.check_logp( NegativeBinomial, Nat, {"mu": Rplus, "alpha": Rplus}, scipy_mu_alpha_logpmf, ) - self.pymc3_matches_scipy( + self.check_logp( NegativeBinomial, Nat, {"p": Unit, "n": Rplus}, @@ -1090,7 +1127,7 @@ def test_negative_binomial_init_fail(self, mu, p, alpha, n, expected): NegativeBinomial("x", mu=mu, p=p, alpha=alpha, n=n) def test_laplace(self): - self.pymc3_matches_scipy( + self.check_logp( Laplace, R, {"mu": R, "b": Rplus}, @@ -1104,7 +1141,7 @@ def test_laplace(self): ) def test_laplace_asymmetric(self): - self.pymc3_matches_scipy( + self.check_logp( AsymmetricLaplace, R, {"b": Rplus, "kappa": Rplus, "mu": R}, @@ -1112,7 +1149,7 @@ def test_laplace_asymmetric(self): ) def test_lognormal(self): - self.pymc3_matches_scipy( + self.check_logp( Lognormal, Rplus, {"mu": R, "tau": Rplusbig}, @@ -1126,7 +1163,7 @@ def test_lognormal(self): ) def test_t(self): - self.pymc3_matches_scipy( + self.check_logp( StudentT, R, {"nu": Rplus, "mu": R, "lam": Rplus}, @@ -1141,7 +1178,7 @@ def test_t(self): ) def test_cauchy(self): - self.pymc3_matches_scipy( + self.check_logp( Cauchy, R, {"alpha": R, "beta": Rplusbig}, @@ -1155,7 +1192,7 @@ def test_cauchy(self): ) def test_half_cauchy(self): - self.pymc3_matches_scipy( + self.check_logp( HalfCauchy, Rplus, {"beta": Rplusbig}, @@ -1168,8 +1205,8 @@ def test_half_cauchy(self): lambda value, beta: sp.halfcauchy.logcdf(value, scale=beta), ) - def test_gamma(self): - self.pymc3_matches_scipy( + def test_gamma_logp(self): + self.check_logp( Gamma, Rplus, {"alpha": Rplusbig, "beta": Rplusbig}, @@ -1179,11 +1216,21 @@ def test_gamma(self): def test_fun(value, mu, sigma): return sp.gamma.logpdf(value, mu ** 2 / sigma ** 2, scale=1.0 / (mu / sigma ** 2)) - self.pymc3_matches_scipy(Gamma, Rplus, {"mu": Rplusbig, "sigma": Rplusbig}, test_fun) + self.check_logp( + Gamma, + Rplus, + {"mu": Rplusbig, "sigma": Rplusbig}, + test_fun, + ) + @pytest.mark.xfail( + condition=(theano.config.floatX == "float32"), + reason="Fails on float32 due to numerical issues", + ) + def test_gamma_logcdf(self): # pymc-devs/Theano-PyMC#224: skip_paramdomain_outside_edge_test has to be set # True to avoid triggering a C-level assertion in the Theano GammaQ function - # in gamma.c file. Can be set back to False (defalut) once that issue is solved + # in gamma.c file. Can be set back to False (default) once that issue is solved self.check_logcdf( Gamma, Rplus, @@ -1197,7 +1244,7 @@ def test_fun(value, mu, sigma): reason="Fails on float32 due to numerical issues", ) def test_inverse_gamma(self): - self.pymc3_matches_scipy( + self.check_logp( InverseGamma, Rplus, {"alpha": Rplus, "beta": Rplus}, @@ -1205,7 +1252,7 @@ def test_inverse_gamma(self): ) # pymc-devs/Theano-PyMC#224: skip_paramdomain_outside_edge_test has to be set # True to avoid triggering a C-level assertion in the Theano GammaQ function - # in gamma.c file. Can be set back to False (defalut) once that issue is solved + # in gamma.c file. Can be set back to False (default) once that issue is solved self.check_logcdf( InverseGamma, Rplus, @@ -1223,10 +1270,16 @@ def test_fun(value, mu, sigma): alpha, beta = InverseGamma._get_alpha_beta(None, None, mu, sigma) return sp.invgamma.logpdf(value, alpha, scale=beta) - self.pymc3_matches_scipy(InverseGamma, Rplus, {"mu": Rplus, "sigma": Rplus}, test_fun) + self.check_logp( + InverseGamma, + Rplus, + {"mu": Rplus, "sigma": Rplus}, + test_fun, + decimal=select_by_precision(float64=5, float32=3), + ) def test_pareto(self): - self.pymc3_matches_scipy( + self.check_logp( Pareto, Rplus, {"alpha": Rplusbig, "m": Rplusbig}, @@ -1244,7 +1297,7 @@ def test_pareto(self): reason="Fails on float32 due to inf issues", ) def test_weibull(self): - self.pymc3_matches_scipy( + self.check_logp( Weibull, Rplus, {"alpha": Rplusbig, "beta": Rplusbig}, @@ -1259,7 +1312,7 @@ def test_weibull(self): def test_half_studentt(self): # this is only testing for nu=1 (halfcauchy) - self.pymc3_matches_scipy( + self.check_logp( HalfStudentT, Rplus, {"sigma": Rplus}, @@ -1267,15 +1320,16 @@ def test_half_studentt(self): ) def test_skew_normal(self): - self.pymc3_matches_scipy( + self.check_logp( SkewNormal, R, {"mu": R, "sigma": Rplusbig, "alpha": R}, lambda value, alpha, mu, sigma: sp.skewnorm.logpdf(value, alpha, mu, sigma), + decimal=select_by_precision(float64=5, float32=3), ) def test_binomial(self): - self.pymc3_matches_scipy( + self.check_logp( Binomial, Nat, {"n": NatSmall, "p": Unit}, @@ -1306,7 +1360,7 @@ def test_beta_binomial(self): Nat, {"alpha": Rplus, "beta": Rplus, "n": NatSmall}, ) - self.pymc3_matches_scipy( + self.check_logp( BetaBinomial, Nat, {"alpha": Rplus, "beta": Rplus, "n": NatSmall}, @@ -1325,13 +1379,13 @@ def test_beta_binomial(self): ) def test_bernoulli(self): - self.pymc3_matches_scipy( + self.check_logp( Bernoulli, Bool, {"logit_p": R}, lambda value, logit_p: sp.bernoulli.logpmf(value, scipy.special.expit(logit_p)), ) - self.pymc3_matches_scipy( + self.check_logp( Bernoulli, Bool, {"p": Unit}, @@ -1356,7 +1410,7 @@ def test_bernoulli(self): ) def test_discrete_weibull(self): - self.pymc3_matches_scipy( + self.check_logp( DiscreteWeibull, Nat, {"q": Unit, "beta": Rplusdunif}, @@ -1369,7 +1423,7 @@ def test_discrete_weibull(self): ) def test_poisson(self): - self.pymc3_matches_scipy( + self.check_logp( Poisson, Nat, {"mu": Rplus}, @@ -1389,7 +1443,7 @@ def test_poisson(self): def test_bound_poisson(self): NonZeroPoisson = Bound(Poisson, lower=1.0) - self.pymc3_matches_scipy( + self.check_logp( NonZeroPoisson, PosNat, {"mu": Rplus}, @@ -1401,7 +1455,7 @@ def test_bound_poisson(self): assert np.isinf(x.logp({"x": 0})) def test_constantdist(self): - self.pymc3_matches_scipy(Constant, I, {"c": I}, lambda value, c: np.log(c == value)) + self.check_logp(Constant, I, {"c": I}, lambda value, c: np.log(c == value)) # Too lazy to propagate decimal parameter through the whole chain of deps @pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") @@ -1449,38 +1503,38 @@ def test_zeroinflatedbinomial(self): @pytest.mark.parametrize("n", [1, 2, 3]) def test_mvnormal(self, n): - self.pymc3_matches_scipy( + self.check_logp( MvNormal, RealMatrix(5, n), {"mu": Vector(R, n), "tau": PdMatrix(n)}, normal_logpdf_tau, ) - self.pymc3_matches_scipy( + self.check_logp( MvNormal, Vector(R, n), {"mu": Vector(R, n), "tau": PdMatrix(n)}, normal_logpdf_tau, ) - self.pymc3_matches_scipy( + self.check_logp( MvNormal, RealMatrix(5, n), {"mu": Vector(R, n), "cov": PdMatrix(n)}, normal_logpdf_cov, ) - self.pymc3_matches_scipy( + self.check_logp( MvNormal, Vector(R, n), {"mu": Vector(R, n), "cov": PdMatrix(n)}, normal_logpdf_cov, ) - self.pymc3_matches_scipy( + self.check_logp( MvNormal, RealMatrix(5, n), {"mu": Vector(R, n), "chol": PdMatrixChol(n)}, normal_logpdf_chol, decimal=select_by_precision(float64=6, float32=-1), ) - self.pymc3_matches_scipy( + self.check_logp( MvNormal, Vector(R, n), {"mu": Vector(R, n), "chol": PdMatrixChol(n)}, @@ -1491,7 +1545,7 @@ def test_mvnormal(self, n): def MvNormalUpper(*args, **kwargs): return MvNormal(lower=False, *args, **kwargs) - self.pymc3_matches_scipy( + self.check_logp( MvNormalUpper, Vector(R, n), {"mu": Vector(R, n), "chol": PdMatrixCholUpper(n)}, @@ -1535,7 +1589,7 @@ def test_mvnormal_init_fail(self): def test_matrixnormal(self, n): mat_scale = 1e3 # To reduce logp magnitude mean_scale = 0.1 - self.pymc3_matches_scipy( + self.check_logp( MatrixNormal, RealMatrix(n, n), { @@ -1545,7 +1599,7 @@ def test_matrixnormal(self, n): }, matrix_normal_logpdf_cov, ) - self.pymc3_matches_scipy( + self.check_logp( MatrixNormal, RealMatrix(2, n), { @@ -1555,7 +1609,7 @@ def test_matrixnormal(self, n): }, matrix_normal_logpdf_cov, ) - self.pymc3_matches_scipy( + self.check_logp( MatrixNormal, RealMatrix(3, n), { @@ -1566,7 +1620,7 @@ def test_matrixnormal(self, n): matrix_normal_logpdf_chol, decimal=select_by_precision(float64=6, float32=-1), ) - self.pymc3_matches_scipy( + self.check_logp( MatrixNormal, RealMatrix(n, 3), { @@ -1600,7 +1654,7 @@ def test_kroneckernormal(self, n, m, sigma): for args in [cov_args, chol_args, evd_args]: args["sigma"] = sigma - self.pymc3_matches_scipy( + self.check_logp( KroneckerNormal, dom, std_args, @@ -1608,7 +1662,7 @@ def test_kroneckernormal(self, n, m, sigma): extra_args=cov_args, scipy_args=cov_args, ) - self.pymc3_matches_scipy( + self.check_logp( KroneckerNormal, dom, std_args, @@ -1616,7 +1670,7 @@ def test_kroneckernormal(self, n, m, sigma): extra_args=chol_args, scipy_args=chol_args, ) - self.pymc3_matches_scipy( + self.check_logp( KroneckerNormal, dom, std_args, @@ -1627,7 +1681,7 @@ def test_kroneckernormal(self, n, m, sigma): dom = Domain([np.random.randn(2, N) * 0.1], edges=(None, None), shape=(2, N)) - self.pymc3_matches_scipy( + self.check_logp( KroneckerNormal, dom, std_args, @@ -1635,7 +1689,7 @@ def test_kroneckernormal(self, n, m, sigma): extra_args=cov_args, scipy_args=cov_args, ) - self.pymc3_matches_scipy( + self.check_logp( KroneckerNormal, dom, std_args, @@ -1643,7 +1697,7 @@ def test_kroneckernormal(self, n, m, sigma): extra_args=chol_args, scipy_args=chol_args, ) - self.pymc3_matches_scipy( + self.check_logp( KroneckerNormal, dom, std_args, @@ -1654,13 +1708,13 @@ def test_kroneckernormal(self, n, m, sigma): @pytest.mark.parametrize("n", [1, 2]) def test_mvt(self, n): - self.pymc3_matches_scipy( + self.check_logp( MvStudentT, Vector(R, n), {"nu": Rplus, "Sigma": PdMatrix(n), "mu": Vector(R, n)}, mvt_logpdf, ) - self.pymc3_matches_scipy( + self.check_logp( MvStudentT, RealMatrix(2, n), {"nu": Rplus, "Sigma": PdMatrix(n), "mu": Vector(R, n)}, @@ -1669,7 +1723,7 @@ def test_mvt(self, n): @pytest.mark.parametrize("n", [2, 3, 4]) def test_AR1(self, n): - self.pymc3_matches_scipy(AR1, Vector(R, n), {"k": Unit, "tau_e": Rplus}, AR1_logpdf) + self.check_logp(AR1, Vector(R, n), {"k": Unit, "tau_e": Rplus}, AR1_logpdf) @pytest.mark.parametrize("n", [2, 3]) def test_wishart(self, n): @@ -1694,7 +1748,7 @@ def test_lkj(self, x, eta, n, lp): @pytest.mark.parametrize("n", [2, 3]) def test_dirichlet(self, n): - self.pymc3_matches_scipy(Dirichlet, Simplex(n), {"a": Vector(Rplus, n)}, dirichlet_logpdf) + self.check_logp(Dirichlet, Simplex(n), {"a": Vector(Rplus, n)}, dirichlet_logpdf) def test_dirichlet_shape(self): a = tt.as_tensor_variable(np.r_[1, 2]) @@ -1706,7 +1760,7 @@ def test_dirichlet_shape(self): dir_rv = Dirichlet.dist(tt.vector()) def test_dirichlet_2D(self): - self.pymc3_matches_scipy( + self.check_logp( Dirichlet, MultiSimplex(2, 2), {"a": Vector(Vector(Rplus, 2), 2)}, @@ -1715,7 +1769,7 @@ def test_dirichlet_2D(self): @pytest.mark.parametrize("n", [2, 3]) def test_multinomial(self, n): - self.pymc3_matches_scipy( + self.check_logp( Multinomial, Vector(Nat, n), {"p": Simplex(n), "n": Nat}, multinomial_logpdf ) @@ -1865,7 +1919,7 @@ def test_batch_multinomial(self): @pytest.mark.parametrize("n", [2, 3]) def test_dirichlet_multinomial(self, n): - self.pymc3_matches_scipy( + self.check_logp( DirichletMultinomial, Vector(Nat, n), {"a": Vector(Rplus, n), "n": Nat}, @@ -2033,7 +2087,7 @@ def test_categorical_valid_p(self): @pytest.mark.parametrize("n", [2, 3, 4]) def test_categorical(self, n): - self.pymc3_matches_scipy( + self.check_logp( Categorical, Domain(range(n), "int64"), {"p": Simplex(n)}, @@ -2042,7 +2096,7 @@ def test_categorical(self, n): @pytest.mark.parametrize("n", [2, 3, 4]) def test_orderedlogistic(self, n): - self.pymc3_matches_scipy( + self.check_logp( OrderedLogistic, Domain(range(n), "int64"), {"eta": R, "cutpoints": Vector(R, n - 1)}, @@ -2051,7 +2105,7 @@ def test_orderedlogistic(self, n): @pytest.mark.parametrize("n", [2, 3, 4]) def test_orderedprobit(self, n): - self.pymc3_matches_scipy( + self.check_logp( OrderedProbit, Domain(range(n), "int64"), {"eta": Runif, "cutpoints": UnitSortedVector(n - 1)}, @@ -2134,7 +2188,7 @@ def test_ex_gaussian_cdf_outside_edges(self): @pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") def test_vonmises(self): - self.pymc3_matches_scipy( + self.check_logp( VonMises, R, {"mu": Circ, "kappa": Rplus}, @@ -2145,7 +2199,7 @@ def test_gumbel(self): def gumbel(value, mu, beta): return floatX(sp.gumbel_r.logpdf(value, loc=mu, scale=beta)) - self.pymc3_matches_scipy(Gumbel, R, {"mu": R, "beta": Rplusbig}, gumbel) + self.check_logp(Gumbel, R, {"mu": R, "beta": Rplusbig}, gumbel) def gumbellcdf(value, mu, beta): return floatX(sp.gumbel_r.logcdf(value, loc=mu, scale=beta)) @@ -2153,7 +2207,7 @@ def gumbellcdf(value, mu, beta): self.check_logcdf(Gumbel, R, {"mu": R, "beta": Rplusbig}, gumbellcdf) def test_logistic(self): - self.pymc3_matches_scipy( + self.check_logp( Logistic, R, {"mu": R, "s": Rplus}, @@ -2169,7 +2223,7 @@ def test_logistic(self): ) def test_logitnormal(self): - self.pymc3_matches_scipy( + self.check_logp( LogitNormal, Unit, {"mu": R, "sigma": Rplus}, @@ -2184,13 +2238,13 @@ def test_multidimensional_beta_construction(self): Beta("beta", alpha=1.0, beta=1.0, shape=(10, 20)) def test_rice(self): - self.pymc3_matches_scipy( + self.check_logp( Rice, Rplus, {"nu": Rplus, "sigma": Rplusbig}, lambda value, nu, sigma: sp.rice.logpdf(value, b=nu / sigma, loc=0, scale=sigma), ) - self.pymc3_matches_scipy( + self.check_logp( Rice, Rplus, {"b": Rplus, "sigma": Rplusbig}, @@ -2199,7 +2253,7 @@ def test_rice(self): @pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") def test_moyal(self): - self.pymc3_matches_scipy( + self.check_logp( Moyal, R, {"mu": R, "sigma": Rplusbig}, @@ -2233,7 +2287,7 @@ def ref_pdf(value): -np.inf * np.ones(value.shape), ) - self.pymc3_matches_scipy(TestedInterpolated, R, {}, ref_pdf) + self.check_logp(TestedInterpolated, R, {}, ref_pdf) def test_bound():