Skip to content

Commit 97f4b35

Browse files
authored
Merge branch 'master' into sample_ppc_ma
2 parents dad7d7f + bbd2de4 commit 97f4b35

27 files changed

+230
-96
lines changed

.travis.yml

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
language: python
2+
sudo: false
23

34
before_install:
45
- . ./scripts/install_miniconda.sh
5-
- "export DISPLAY=:99.0"
6-
- "sh -e /etc/init.d/xvfb start"
7-
- if [ ${MATPLOTLIB} = "1.2" ]; then mkdir $HOME/.matplotlib; fi
8-
- if [ ${MATPLOTLIB} = "1.2" ]; then cp ${SRCDIR}/tools/matplotlibrc $HOME/.matplotlib/matplotlibrc; fi
6+
- sh -e /etc/init.d/xvfb start
7+
- export DISPLAY=":99.0"
98

109
install:
1110
- . ./scripts/create_testenv.sh
1211
- pip install coveralls pylint
1312

1413
env:
15-
- PYTHON_VERSION=2.7 TESTCMD="--durations=10 --ignore=pymc3/tests/test_examples.py --cov-append --ignore=pymc3/tests/test_distributions_random.py --ignore=pymc3/tests/test_variational_inference.py --ignore=pymc3/tests/test_shared.py --ignore=pymc3/tests/test_smc.py --ignore=pymc3/tests/test_updates.py"
16-
- PYTHON_VERSION=2.7 RUN_PYLINT="true" TESTCMD="--durations=10 --cov-append pymc3/tests/test_distributions_random.py pymc3/tests/test_shared.py pymc3/tests/test_smc.py"
17-
- PYTHON_VERSION=2.7 TESTCMD="--durations=10 --cov-append pymc3/tests/test_examples.py pymc3/tests/test_variational_inference.py pymc3/tests/test_updates.py"
18-
- PYTHON_VERSION=3.6 TESTCMD="--durations=10 --cov-append --ignore=pymc3/tests/test_examples.py --ignore=pymc3/tests/test_distributions_random.py --ignore=pymc3/tests/test_variational_inference.py --ignore=pymc3/tests/test_shared.py --ignore=pymc3/tests/test_smc.py --ignore=pymc3/tests/test_updates.py"
19-
- PYTHON_VERSION=3.6 TESTCMD="--durations=10 --cov-append pymc3/tests/test_distributions_random.py pymc3/tests/test_shared.py pymc3/tests/test_smc.py"
20-
- PYTHON_VERSION=3.6 TESTCMD="--durations=10 --cov-append pymc3/tests/test_examples.py pymc3/tests/test_variational_inference.py pymc3/tests/test_updates.py"
14+
- PYTHON_VERSION=2.7 FLOATX='float32' TESTCMD="--durations=10 --ignore=pymc3/tests/test_examples.py --cov-append --ignore=pymc3/tests/test_distributions_random.py --ignore=pymc3/tests/test_variational_inference.py --ignore=pymc3/tests/test_shared.py --ignore=pymc3/tests/test_smc.py --ignore=pymc3/tests/test_updates.py"
15+
- PYTHON_VERSION=2.7 FLOATX='float32' RUN_PYLINT="true" TESTCMD="--durations=10 --cov-append pymc3/tests/test_distributions_random.py pymc3/tests/test_shared.py pymc3/tests/test_smc.py"
16+
- PYTHON_VERSION=2.7 FLOATX='float32' TESTCMD="--durations=10 --cov-append pymc3/tests/test_examples.py pymc3/tests/test_variational_inference.py pymc3/tests/test_updates.py"
17+
- PYTHON_VERSION=2.7 FLOATX='float64' TESTCMD="--durations=10 --ignore=pymc3/tests/test_examples.py --cov-append --ignore=pymc3/tests/test_distributions_random.py --ignore=pymc3/tests/test_variational_inference.py --ignore=pymc3/tests/test_shared.py --ignore=pymc3/tests/test_smc.py --ignore=pymc3/tests/test_updates.py"
18+
- PYTHON_VERSION=2.7 FLOATX='float64' RUN_PYLINT="true" TESTCMD="--durations=10 --cov-append pymc3/tests/test_distributions_random.py pymc3/tests/test_shared.py pymc3/tests/test_smc.py"
19+
- PYTHON_VERSION=2.7 FLOATX='float64' TESTCMD="--durations=10 --cov-append pymc3/tests/test_examples.py pymc3/tests/test_variational_inference.py pymc3/tests/test_updates.py"
20+
- PYTHON_VERSION=3.6 FLOATX='float64' TESTCMD="--durations=10 --cov-append --ignore=pymc3/tests/test_examples.py --ignore=pymc3/tests/test_distributions_random.py --ignore=pymc3/tests/test_variational_inference.py --ignore=pymc3/tests/test_shared.py --ignore=pymc3/tests/test_smc.py --ignore=pymc3/tests/test_updates.py"
21+
- PYTHON_VERSION=3.6 FLOATX='float64' TESTCMD="--durations=10 --cov-append pymc3/tests/test_distributions_random.py pymc3/tests/test_shared.py pymc3/tests/test_smc.py"
22+
- PYTHON_VERSION=3.6 FLOATX='float64' TESTCMD="--durations=10 --cov-append pymc3/tests/test_examples.py pymc3/tests/test_variational_inference.py pymc3/tests/test_updates.py"
2123
script:
2224
- . ./scripts/test.sh $TESTCMD
2325

pymc3/backends/smc_text.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,13 @@ def highest_sampled_stage(self):
177177
-------
178178
stage number : int
179179
"""
180-
return max(self.stage_number(s) for s in glob(self.path('*')))
180+
return max(self.stage_number(s) for s in glob(self.stage_path('*')))
181181

182182
def atmip_path(self, stage_number):
183183
"""Consistent naming for atmip params."""
184184
return os.path.join(self.stage_path(stage_number), 'atmip.params.pkl')
185185

186-
def load_atmip_params(self, stage_number):
186+
def load_atmip_params(self, stage_number, model):
187187
"""Load saved parameters from last sampled ATMIP stage.
188188
189189
Parameters
@@ -196,8 +196,14 @@ def load_atmip_params(self, stage_number):
196196
else:
197197
prev = stage_number - 1
198198
pm._log.info('Loading parameters from completed stage {}'.format(prev))
199-
with open(self.atmip_path(prev), 'rb') as buff:
200-
return pickle.load(buff)
199+
200+
with model:
201+
with open(self.atmip_path(prev), 'rb') as buff:
202+
step = pickle.load(buff)
203+
204+
# update step stage to current stage
205+
step.stage = stage_number
206+
return step
201207

202208
def dump_atmip_params(self, step):
203209
"""Save atmip params to file."""
@@ -278,7 +284,7 @@ def recover_existing_results(self, stage, draws, step, n_jobs, model=None):
278284
# load incomplete stage results
279285
pm._log.info('Reloading existing results ...')
280286
mtrace = self.load_multitrace(stage, model=model)
281-
if len(mtrace) > 0:
287+
if len(mtrace.chains) > 0:
282288
# continue sampling if traces exist
283289
pm._log.info('Checking for corrupted files ...')
284290
return self.check_multitrace(mtrace, draws=draws, n_chains=step.n_chains)

pymc3/distributions/distribution.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def getattr_value(self, val):
8787

8888
def _repr_latex_(self, name=None, dist=None):
8989
return None
90-
90+
9191

9292
def TensorType(dtype, shape):
9393
return tt.TensorType(str(dtype), np.atleast_1d(shape) == 1)
@@ -123,6 +123,11 @@ def __init__(self, shape=(), dtype=None, defaults=('mode', ),
123123
dtype = 'int64'
124124
if dtype != 'int16' and dtype != 'int64':
125125
raise TypeError('Discrete classes expect dtype to be int16 or int64.')
126+
127+
if kwargs.get('transform', None) is not None:
128+
raise ValueError("Transformations for discrete distributions "
129+
"are not allowed.")
130+
126131
super(Discrete, self).__init__(
127132
shape, dtype, defaults=defaults, *args, **kwargs)
128133

pymc3/distributions/transforms.py

-7
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,6 @@ def __init__(self, dist, transform, *args, **kwargs):
7070
# force the last dim not broadcastable
7171
self.type = tt.TensorType(v.dtype, b)
7272

73-
def _repr_latex_(self, name=None, dist=None):
74-
if name is None:
75-
name = self.name
76-
if dist is None:
77-
dist = self.dist
78-
return dist._repr_latex_(self, name=name, dist=dist)
79-
8073
def logp(self, x):
8174
return (self.dist.logp(self.transform_used.backward(x)) +
8275
self.transform_used.jacobian_det(x))

pymc3/model.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ def Var(self, name, dist, data=None, total_size=None):
539539
name=name,
540540
orig_name=get_transformed_name(name, dist.transform)))
541541
self.deterministics.append(var)
542+
self.add_random_variable(var)
542543
return var
543544
elif isinstance(data, dict):
544545
with self:
@@ -985,7 +986,7 @@ def Deterministic(name, var, model=None):
985986
986987
Returns
987988
-------
988-
n : var but with name name
989+
var : var, with name attribute
989990
"""
990991
model = modelcontext(model)
991992
var.name = model.name_for(name)
@@ -1009,6 +1010,7 @@ def Potential(name, var, model=None):
10091010
model = modelcontext(model)
10101011
var.name = model.name_for(name)
10111012
model.potentials.append(var)
1013+
model.add_random_variable(var)
10121014
return var
10131015

10141016

pymc3/step_methods/smc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ def ATMIP_sample(n_steps, step=None, start=None, homepath=None, chain=0, stage=0
520520
step.stage = stage
521521
draws = 1
522522
else:
523-
step = stage_handler.load_atmip_params(stage)
523+
step = stage_handler.load_atmip_params(stage, model=model)
524524
draws = step.n_steps
525525

526526
stage_handler.clean_directory(stage, None, rm_flag)

pymc3/tests/backend_fixtures.py

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pymc3.tests import models
88
from pymc3.backends import base
99
import pytest
10+
import theano
1011

1112

1213
class ModelBackendSetupTestCase(object):
@@ -227,6 +228,7 @@ def record_point(self, val):
227228
else:
228229
self.strace.record(point=point)
229230

231+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
230232
def test_standard_close(self):
231233
for idx in range(self.draws):
232234
self.record_point(idx)
@@ -266,13 +268,15 @@ class SelectionTestCase(ModelBackendSampledTestCase):
266268
- shape
267269
"""
268270

271+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
269272
def test_get_values_default(self):
270273
for varname in self.test_point.keys():
271274
expected = np.concatenate([self.expected[chain][varname]
272275
for chain in [0, 1]])
273276
result = self.mtrace.get_values(varname)
274277
npt.assert_equal(result, expected)
275278

279+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
276280
def test_get_values_nocombine_burn_keyword(self):
277281
burn = 2
278282
for varname in self.test_point.keys():

pymc3/tests/test_diagnostics.py

+3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
from ..diagnostics import effective_n, geweke, gelman_rubin
1111
from .test_examples import build_disaster_model
1212
import pytest
13+
import theano
1314

1415

16+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
1517
class TestGelmanRubin(SeededTest):
1618
good_ratio = 1.1
1719

@@ -85,6 +87,7 @@ def test_right_shape_scalar_one(self):
8587
self.test_right_shape_python_float(shape=1, test_shape=(1,))
8688

8789

90+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
8891
class TestDiagnostics(SeededTest):
8992

9093
def get_switchpoint(self, n_samples):

pymc3/tests/test_distributions.py

+45-15
Original file line numberDiff line numberDiff line change
@@ -353,22 +353,23 @@ def PdMatrixCholUpper(n):
353353

354354

355355
class TestMatchesScipy(SeededTest):
356-
def pymc3_matches_scipy(self, pymc3_dist, domain, paramdomains, scipy_dist, extra_args={}):
356+
def pymc3_matches_scipy(self, pymc3_dist, domain, paramdomains, scipy_dist, decimal=None, extra_args={}):
357357
model = build_model(pymc3_dist, domain, paramdomains, extra_args)
358358
value = model.named_vars['value']
359359

360360
def logp(args):
361361
return scipy_dist(**args)
362-
self.check_logp(model, value, domain, paramdomains, logp)
362+
self.check_logp(model, value, domain, paramdomains, logp, decimal=decimal)
363363

364-
def check_logp(self, model, value, domain, paramdomains, logp_reference):
364+
def check_logp(self, model, value, domain, paramdomains, logp_reference, decimal=None):
365365
domains = paramdomains.copy()
366366
domains['value'] = domain
367367
logp = model.fastlogp
368368
for pt in product(domains, n_samples=100):
369369
pt = Point(pt, model=model)
370-
decimals = select_by_precision(float64=6, float32=4)
371-
assert_almost_equal(logp(pt), logp_reference(pt), decimal=decimals, err_msg=str(pt))
370+
if decimal is None:
371+
decimal = select_by_precision(float64=6, float32=3)
372+
assert_almost_equal(logp(pt), logp_reference(pt), decimal=decimal, err_msg=str(pt))
372373

373374
def check_int_to_1(self, model, value, domain, paramdomains):
374375
pdf = model.fastfn(exp(model.logpt))
@@ -424,10 +425,12 @@ def test_triangular(self):
424425
Triangular, Runif, {'lower': -Rplusunif, 'c': Runif, 'upper': Rplusunif},
425426
lambda value, c, lower, upper: sp.triang.logpdf(value, c-lower, lower, upper-lower))
426427

428+
427429
def test_bound_normal(self):
428430
PositiveNormal = Bound(Normal, lower=0.)
429431
self.pymc3_matches_scipy(PositiveNormal, Rplus, {'mu': Rplus, 'sd': Rplus},
430-
lambda value, mu, sd: sp.norm.logpdf(value, mu, sd))
432+
lambda value, mu, sd: sp.norm.logpdf(value, mu, sd),
433+
decimal=select_by_precision(float64=6, float32=-1))
431434
with Model(): x = PositiveNormal('x', mu=0, sd=1, transform=None)
432435
assert np.isinf(x.logp({'x':-1}))
433436

@@ -441,19 +444,25 @@ def test_flat(self):
441444

442445
def test_normal(self):
443446
self.pymc3_matches_scipy(Normal, R, {'mu': R, 'sd': Rplus},
444-
lambda value, mu, sd: sp.norm.logpdf(value, mu, sd))
447+
lambda value, mu, sd: sp.norm.logpdf(value, mu, sd),
448+
decimal=select_by_precision(float64=6, float32=1)
449+
)
445450

446451
def test_half_normal(self):
447452
self.pymc3_matches_scipy(HalfNormal, Rplus, {'sd': Rplus},
448-
lambda value, sd: sp.halfnorm.logpdf(value, scale=sd))
453+
lambda value, sd: sp.halfnorm.logpdf(value, scale=sd),
454+
decimal=select_by_precision(float64=6, float32=-1)
455+
)
449456

450457
def test_chi_squared(self):
451458
self.pymc3_matches_scipy(ChiSquared, Rplus, {'nu': Rplusdunif},
452459
lambda value, nu: sp.chi2.logpdf(value, df=nu))
453460

454461
def test_wald_scipy(self):
455462
self.pymc3_matches_scipy(Wald, Rplus, {'mu': Rplus},
456-
lambda value, mu: sp.invgauss.logpdf(value, mu))
463+
lambda value, mu: sp.invgauss.logpdf(value, mu),
464+
decimal=select_by_precision(float64=6, float32=1)
465+
)
457466

458467
@pytest.mark.parametrize('value,mu,lam,phi,alpha,logp', [
459468
(.5, .001, .5, None, 0., -124500.7257914),
@@ -540,9 +549,11 @@ def test_pareto(self):
540549
self.pymc3_matches_scipy(Pareto, Rplus, {'alpha': Rplusbig, 'm': Rplusbig},
541550
lambda value, alpha, m: sp.pareto.logpdf(value, alpha, scale=m))
542551

552+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32 due to inf issues")
543553
def test_weibull(self):
544554
self.pymc3_matches_scipy(Weibull, Rplus, {'alpha': Rplusbig, 'beta': Rplusbig},
545-
scipy_exponweib_sucks)
555+
scipy_exponweib_sucks,
556+
)
546557

547558
def test_student_tpos(self):
548559
# TODO: this actually shouldn't pass
@@ -557,6 +568,7 @@ def test_binomial(self):
557568
self.pymc3_matches_scipy(Binomial, Nat, {'n': NatSmall, 'p': Unit},
558569
lambda value, n, p: sp.binom.logpmf(value, n, p))
559570

571+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") # Too lazy to propagate decimal parameter through the whole chain of deps
560572
def test_beta_binomial(self):
561573
self.checkd(BetaBinomial, Nat, {'alpha': Rplus, 'beta': Rplus, 'n': NatSmall})
562574

@@ -584,13 +596,16 @@ def test_constantdist(self):
584596
self.pymc3_matches_scipy(Constant, I, {'c': I},
585597
lambda value, c: np.log(c == value))
586598

599+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") # Too lazy to propagate decimal parameter through the whole chain of deps
587600
def test_zeroinflatedpoisson(self):
588601
self.checkd(ZeroInflatedPoisson, Nat, {'theta': Rplus, 'psi': Unit})
589602

603+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") # Too lazy to propagate decimal parameter through the whole chain of deps
590604
def test_zeroinflatednegativebinomial(self):
591605
self.checkd(ZeroInflatedNegativeBinomial, Nat,
592606
{'mu': Rplusbig, 'alpha': Rplusbig, 'psi': Unit})
593607

608+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32") # Too lazy to propagate decimal parameter through the whole chain of deps
594609
def test_zeroinflatedbinomial(self):
595610
self.checkd(ZeroInflatedBinomial, Nat,
596611
{'n': NatSmall, 'p': Unit, 'psi': Unit})
@@ -611,23 +626,27 @@ def test_mvnormal(self, n):
611626
normal_logpdf_cov)
612627
self.pymc3_matches_scipy(MvNormal, RealMatrix(5, n),
613628
{'mu': Vector(R, n), 'chol': PdMatrixChol(n)},
614-
normal_logpdf_chol)
629+
normal_logpdf_chol,
630+
decimal=select_by_precision(float64=6, float32=-1))
615631
self.pymc3_matches_scipy(MvNormal, Vector(R, n),
616632
{'mu': Vector(R, n), 'chol': PdMatrixChol(n)},
617-
normal_logpdf_chol)
633+
normal_logpdf_chol,
634+
decimal=select_by_precision(float64=6, float32=0))
618635

619636
def MvNormalUpper(*args, **kwargs):
620637
return MvNormal(lower=False, *args, **kwargs)
621638

622639
self.pymc3_matches_scipy(MvNormalUpper, Vector(R, n),
623640
{'mu': Vector(R, n), 'chol': PdMatrixCholUpper(n)},
624-
normal_logpdf_chol_upper)
641+
normal_logpdf_chol_upper,
642+
decimal=select_by_precision(float64=6, float32=0))
625643

644+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32 due to inf issues")
626645
def test_mvnormal_indef(self):
627646
cov_val = np.array([[1, 0.5], [0.5, -2]])
628647
cov = tt.matrix('cov')
629648
cov.tag.test_value = np.eye(2)
630-
mu = np.zeros(2)
649+
mu = floatX(np.zeros(2))
631650
x = tt.vector('x')
632651
x.tag.test_value = np.zeros(2)
633652
logp = MvNormal.dist(mu=mu, cov=cov).logp(x)
@@ -786,7 +805,7 @@ def test_ex_gaussian(self, value, mu, sigma, nu, logp):
786805
with Model() as model:
787806
ExGaussian('eg', mu=mu, sigma=sigma, nu=nu)
788807
pt = {'eg': value}
789-
assert_almost_equal(model.fastlogp(pt), logp, decimal=6, err_msg=str(pt))
808+
assert_almost_equal(model.fastlogp(pt), logp, decimal=select_by_precision(float64=6, float32=2), err_msg=str(pt))
790809

791810
def test_vonmises(self):
792811
self.pymc3_matches_scipy(
@@ -801,6 +820,7 @@ def test_multidimensional_beta_construction(self):
801820
with Model():
802821
Beta('beta', alpha=1., beta=1., shape=(10, 20))
803822

823+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
804824
def test_interpolated(self):
805825
for mu in R.vals:
806826
for sd in Rplus.vals:
@@ -840,3 +860,13 @@ def test_repr_latex_():
840860
assert x2._repr_latex_()=='$Timeseries \\sim \\text{GaussianRandomWalk}(\\mathit{mu}=Continuous, \\mathit{sd}=1.0)$'
841861
assert x3._repr_latex_()=='$Multivariate \\sim \\text{MvStudentT}(\\mathit{nu}=5, \\mathit{mu}=Timeseries, \\mathit{Sigma}=array)$'
842862
assert x4._repr_latex_()=='$Mixture \\sim \\text{NormalMixture}(\\mathit{w}=array, \\mathit{mu}=Multivariate, \\mathit{sigma}=f(Discrete))$'
863+
864+
865+
def test_discrete_trafo():
866+
with pytest.raises(ValueError) as err:
867+
Binomial.dist(n=5, p=0.5, transform='log')
868+
err.match('Transformations for discrete distributions')
869+
with Model():
870+
with pytest.raises(ValueError) as err:
871+
Binomial('a', n=5, p=0.5, transform='log')
872+
err.match('Transformations for discrete distributions')

pymc3/tests/test_distributions_random.py

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import scipy.stats as st
77
from scipy import linalg
88
import numpy.random as nr
9+
import theano
910

1011
import pymc3 as pm
1112
from .helpers import SeededTest
@@ -580,6 +581,7 @@ def ref_rand(size, mu, beta):
580581
return st.gumbel_r.rvs(loc=mu, scale=beta, size=size)
581582
pymc3_random(pm.Gumbel, {'mu': R, 'beta': Rplus}, ref_rand=ref_rand)
582583

584+
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
583585
def test_interpolated(self):
584586
for mu in R.vals:
585587
for sd in Rplus.vals:

0 commit comments

Comments
 (0)