Expand Up
@@ -447,6 +447,19 @@ def check_logp(self, model, value, domain, paramdomains, logp_reference, decimal
decimal = select_by_precision (float64 = 6 , float32 = 3 )
assert_almost_equal (logp (pt ), logp_reference (pt ), decimal = decimal , err_msg = str (pt ))
def check_logcdf (self , pymc3_dist , domain , paramdomains , scipy_logcdf , decimal = None ):
domains = paramdomains .copy ()
domains ['value' ] = domain
if decimal is None :
decimal = select_by_precision (float64 = 6 , float32 = 3 )
for pt in product (domains , n_samples = 100 ):
params = dict (pt )
scipy_cdf = scipy_logcdf (** params )
value = params .pop ('value' )
dist = pymc3_dist .dist (** params )
assert_almost_equal (dist .logcdf (value ).tag .test_value , scipy_cdf ,
decimal = decimal , err_msg = str (pt ))
def check_int_to_1 (self , model , value , domain , paramdomains ):
pdf = model .fastfn (exp (model .logpt ))
for pt in product (paramdomains , n_samples = 10 ):
Expand Down
Expand Up
@@ -498,11 +511,15 @@ def test_uniform(self):
self .pymc3_matches_scipy (
Uniform , Runif , {'lower' : - Rplusunif , 'upper' : Rplusunif },
lambda value , lower , upper : sp .uniform .logpdf (value , lower , upper - lower ))
self .check_logcdf (Uniform , Runif , {'lower' : - Rplusunif , 'upper' : Rplusunif },
lambda value , lower , upper : sp .uniform .logcdf (value , lower , upper - lower ))
def test_triangular (self ):
self .pymc3_matches_scipy (
Triangular , Runif , {'lower' : - Rplusunif , 'c' : Runif , 'upper' : Rplusunif },
lambda value , c , lower , upper : sp .triang .logpdf (value , c - lower , lower , upper - lower ))
self .check_logcdf (Triangular , Runif , {'lower' : - Rplusunif , 'c' : Runif , 'upper' : Rplusunif },
lambda value , c , lower , upper : sp .triang .logcdf (value , c - lower , lower , upper - lower ))
def test_bound_normal (self ):
PositiveNormal = Bound (Normal , lower = 0. )
Expand All
@@ -522,19 +539,29 @@ def test_flat(self):
with Model ():
x = Flat ('a' )
assert_allclose (x .tag .test_value , 0 )
self .check_logcdf (Flat , Runif , {}, lambda value : np .log (0.5 ))
# Check infinite cases individually.
assert 0. == Flat .dist ().logcdf (np .inf ).tag .test_value
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 )
with Model ():
x = HalfFlat ('a' , shape = 2 )
assert_allclose (x .tag .test_value , 1 )
assert x .tag .test_value .shape == (2 ,)
self .check_logcdf (HalfFlat , Runif , {}, lambda value : - np .inf )
# Check infinite cases individually.
assert 0. == HalfFlat .dist ().logcdf (np .inf ).tag .test_value
assert - np .inf == HalfFlat .dist ().logcdf (- np .inf ).tag .test_value
def test_normal (self ):
self .pymc3_matches_scipy (Normal , R , {'mu' : R , 'sd' : Rplus },
lambda value , mu , sd : sp .norm .logpdf (value , mu , sd ),
decimal = select_by_precision (float64 = 6 , float32 = 1 )
)
self .check_logcdf (Normal , R , {'mu' : R , 'sd' : Rplus },
lambda value , mu , sd : sp .norm .logcdf (value , mu , sd ))
def test_truncated_normal (self ):
def scipy_logp (value , mu , sd , lower , upper ):
Expand All
@@ -558,16 +585,21 @@ def test_half_normal(self):
lambda value , sd : sp .halfnorm .logpdf (value , scale = sd ),
decimal = select_by_precision (float64 = 6 , float32 = - 1 )
)
self .check_logcdf (HalfNormal , Rplus , {'sd' : Rplus },
lambda value , sd : sp .halfnorm .logcdf (value , scale = sd ))
def test_chi_squared (self ):
self .pymc3_matches_scipy (ChiSquared , Rplus , {'nu' : Rplusdunif },
lambda value , nu : sp .chi2 .logpdf (value , df = nu ))
@pytest .mark .xfail (reason = "Poor CDF in SciPy. See scipy/scipy#869 for details." )
def test_wald_scipy (self ):
self .pymc3_matches_scipy (Wald , Rplus , {'mu' : Rplus },
lambda value , mu : sp .invgauss .logpdf (value , mu ),
self .pymc3_matches_scipy (Wald , Rplus , {'mu' : Rplus , 'alpha' : Rplus },
lambda value , mu , alpha : sp .invgauss .logpdf (value , mu = mu , loc = alpha ),
decimal = select_by_precision (float64 = 6 , float32 = 1 )
)
self .check_logcdf (Wald , Rplus , {'mu' : Rplus , 'alpha' : Rplus },
lambda value , mu , alpha : sp .invgauss .logcdf (value , mu = mu , loc = alpha ))
@pytest .mark .parametrize ('value,mu,lam,phi,alpha,logp' , [
(.5 , .001 , .5 , None , 0. , - 124500.7257914 ),
Expand Down
Expand Up
@@ -599,6 +631,8 @@ def test_beta(self):
self .pymc3_matches_scipy (Beta , Unit , {'alpha' : Rplus , 'beta' : Rplus },
lambda value , alpha , beta : sp .beta .logpdf (value , alpha , beta ))
self .pymc3_matches_scipy (Beta , Unit , {'mu' : Unit , 'sd' : Rplus }, beta_mu_sd )
self .check_logcdf (Beta , Unit , {'alpha' : Rplus , 'beta' : Rplus },
lambda value , alpha , beta : sp .beta .logcdf (value , alpha , beta ))
def test_kumaraswamy (self ):
# Scipy does not have a built-in Kumaraswamy pdf
Expand All
@@ -609,6 +643,8 @@ def scipy_log_pdf(value, a, b):
def test_exponential (self ):
self .pymc3_matches_scipy (Exponential , Rplus , {'lam' : Rplus },
lambda value , lam : sp .expon .logpdf (value , 0 , 1 / lam ))
self .check_logcdf (Exponential , Rplus , {'lam' : Rplus },
lambda value , lam : sp .expon .logcdf (value , 0 , 1 / lam ))
def test_geometric (self ):
self .pymc3_matches_scipy (Geometric , Nat , {'p' : Unit },
Expand All
@@ -623,23 +659,33 @@ def test_fun(value, mu, alpha):
def test_laplace (self ):
self .pymc3_matches_scipy (Laplace , R , {'mu' : R , 'b' : Rplus },
lambda value , mu , b : sp .laplace .logpdf (value , mu , b ))
self .check_logcdf (Laplace , R , {'mu' : R , 'b' : Rplus },
lambda value , mu , b : sp .laplace .logcdf (value , mu , b ))
def test_lognormal (self ):
self .pymc3_matches_scipy (
Lognormal , Rplus , {'mu' : R , 'tau' : Rplusbig },
lambda value , mu , tau : floatX (sp .lognorm .logpdf (value , tau ** - .5 , 0 , np .exp (mu ))))
self .check_logcdf (Lognormal , Rplus , {'mu' : R , 'tau' : Rplusbig },
lambda value , mu , tau : sp .lognorm .logcdf (value , tau ** - .5 , 0 , np .exp (mu )))
def test_t (self ):
self .pymc3_matches_scipy (StudentT , R , {'nu' : Rplus , 'mu' : R , 'lam' : Rplus },
lambda value , nu , mu , lam : sp .t .logpdf (value , nu , mu , lam ** - 0.5 ))
self .check_logcdf (StudentT , R , {'nu' : Rplus , 'mu' : R , 'lam' : Rplus },
lambda value , nu , mu , lam : sp .t .logcdf (value , nu , mu , lam ** - 0.5 ))
def test_cauchy (self ):
self .pymc3_matches_scipy (Cauchy , R , {'alpha' : R , 'beta' : Rplusbig },
lambda value , alpha , beta : sp .cauchy .logpdf (value , alpha , beta ))
self .check_logcdf (Cauchy , R , {'alpha' : R , 'beta' : Rplusbig },
lambda value , alpha , beta : sp .cauchy .logcdf (value , alpha , beta ))
def test_half_cauchy (self ):
self .pymc3_matches_scipy (HalfCauchy , Rplus , {'beta' : Rplusbig },
lambda value , beta : sp .halfcauchy .logpdf (value , scale = beta ))
self .check_logcdf (HalfCauchy , Rplus , {'beta' : Rplusbig },
lambda value , beta : sp .halfcauchy .logcdf (value , scale = beta ))
def test_gamma (self ):
self .pymc3_matches_scipy (
Expand All
@@ -659,12 +705,17 @@ def test_inverse_gamma(self):
def test_pareto (self ):
self .pymc3_matches_scipy (Pareto , Rplus , {'alpha' : Rplusbig , 'm' : Rplusbig },
lambda value , alpha , m : sp .pareto .logpdf (value , alpha , scale = m ))
self .check_logcdf (Pareto , Rplus , {'alpha' : Rplusbig , 'm' : Rplusbig },
lambda value , alpha , m : sp .pareto .logcdf (value , alpha , scale = m ))
@pytest .mark .xfail (condition = (theano .config .floatX == "float32" ), reason = "Fails on float32 due to inf issues" )
def test_weibull (self ):
self .pymc3_matches_scipy (Weibull , Rplus , {'alpha' : Rplusbig , 'beta' : Rplusbig },
lambda value , alpha , beta : sp .exponweib .logpdf (value , 1 , alpha , scale = beta ),
)
self .check_logcdf (Weibull , Rplus , {'alpha' : Rplusbig , 'beta' : Rplusbig },
lambda value , alpha , beta :
sp .exponweib .logcdf (value , 1 , alpha , scale = beta ),)
def test_half_studentt (self ):
# this is only testing for nu=1 (halfcauchy)
Expand Down
Expand Up
@@ -1064,6 +1115,25 @@ def test_ex_gaussian(self, value, mu, sigma, nu, logp):
pt = {'eg' : value }
assert_almost_equal (model .fastlogp (pt ), logp , decimal = select_by_precision (float64 = 6 , float32 = 2 ), err_msg = str (pt ))
@pytest .mark .parametrize ('value,mu,sigma,nu,logcdf' , [
(0.5 , - 50.000 , 0.500 , 0.500 , 0.0000000 ),
(1.0 , - 1.000 , 0.001 , 0.001 , 0.0000000 ),
(2.0 , 0.001 , 1.000 , 1.000 , - 0.2365674 ),
(5.0 , 0.500 , 2.500 , 2.500 , - 0.2886489 ),
(7.5 , 2.000 , 5.000 , 5.000 , - 0.5655104 ),
(15.0 , 5.000 , 7.500 , 7.500 , - 0.4545255 ),
(50.0 , 50.000 , 10.000 , 10.000 , - 1.433714 ),
(1000.0 , 500.000 , 10.000 , 20.000 , - 1.573708e-11 ),
])
def test_ex_gaussian_cdf (self , value , mu , sigma , nu , logcdf ):
"""Log probabilities calculated using the pexGAUS function from the R package gamlss.
See e.g., doi: 10.1111/j.1467-9876.2005.00510.x, or http://www.gamlss.org/."""
assert_almost_equal (
ExGaussian .dist (mu = mu , sigma = sigma , nu = nu ).logcdf (value ).tag .test_value ,
logcdf ,
decimal = select_by_precision (float64 = 6 , float32 = 2 ),
err_msg = str ((value , mu , sigma , nu , logcdf )))
@pytest .mark .xfail (condition = (theano .config .floatX == "float32" ), reason = "Fails on float32" )
def test_vonmises (self ):
self .pymc3_matches_scipy (
Expand All
@@ -1075,10 +1145,17 @@ 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 )
def gumbellcdf (value , mu , beta ):
return floatX (sp .gumbel_r .logcdf (value , loc = mu , scale = beta ))
self .check_logcdf (Gumbel , R , {'mu' : R , 'beta' : Rplusbig }, gumbellcdf )
def test_logistic (self ):
self .pymc3_matches_scipy (Logistic , R , {'mu' : R , 's' : Rplus },
lambda value , mu , s : sp .logistic .logpdf (value , mu , s ),
decimal = select_by_precision (float64 = 6 , float32 = 1 ))
self .check_logcdf (Logistic , R , {'mu' : R , 's' : Rplus },
lambda value , mu , s : sp .logistic .logcdf (value , mu , s ),
decimal = select_by_precision (float64 = 6 , float32 = 1 ))
def test_logitnormal (self ):
self .pymc3_matches_scipy (LogitNormal , Unit , {'mu' : R , 'sd' : Rplus },
Expand Down