Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

pymc-devs / pymc3 / 8412

28 Nov 2018 - 15:42 coverage decreased (-0.7%) to 88.7%
8412

Pull #3275

travis-ci

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Fix link to be relative
Pull Request #3275: Documentation rewrite

17630 of 19876 relevant lines covered (88.7%)

4.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/pymc3/tests/test_transforms.py
UNCOV
1
import pymc3.distributions.transforms as tr
3×
UNCOV
2
import pymc3 as pm
3×
UNCOV
3
import numpy as np
3×
UNCOV
4
import pytest
3×
5

UNCOV
6
import theano
3×
UNCOV
7
import theano.tensor as tt
3×
UNCOV
8
from .helpers import SeededTest
3×
UNCOV
9
from .test_distributions import (Simplex, Rplusbig, Rminusbig,
3×
10
                                 Unit, R, Vector, MultiSimplex,
11
                                 Circ, SortedVector, UnitSortedVector)
UNCOV
12
from .checks import close_to, close_to_logical
3×
UNCOV
13
from ..theanof import jacobian
3×
14

15

16
# some transforms (stick breaking) require additon of small slack in order to be numerically
17
# stable. The minimal addable slack for float32 is higher thus we need to be less strict
UNCOV
18
tol = 1e-7 if theano.config.floatX == 'float64' else 1e-6
3×
19

20

UNCOV
21
def check_transform(transform, domain, constructor=tt.dscalar, test=0):
3×
UNCOV
22
    x = constructor('x')
3×
UNCOV
23
    x.tag.test_value = test
3×
24
    # test forward and forward_val
UNCOV
25
    forward_f = theano.function([x], transform.forward(x))
3×
26
    # test transform identity
UNCOV
27
    identity_f = theano.function([x], transform.backward(transform.forward(x)))
3×
UNCOV
28
    for val in domain.vals:
3×
UNCOV
29
        close_to(val, identity_f(val), tol)
3×
UNCOV
30
        close_to(transform.forward_val(val), forward_f(val), tol)
3×
31

32

UNCOV
33
def check_vector_transform(transform, domain):
3×
UNCOV
34
    return check_transform(transform, domain, tt.dvector, test=np.array([0, 0]))
3×
35

36

UNCOV
37
def get_values(transform, domain=R, constructor=tt.dscalar, test=0):
3×
UNCOV
38
    x = constructor('x')
3×
UNCOV
39
    x.tag.test_value = test
3×
UNCOV
40
    f = theano.function([x], transform.backward(x))
3×
UNCOV
41
    return np.array([f(val) for val in domain.vals])
3×
42

43

UNCOV
44
def check_jacobian_det(transform, domain,
3×
45
                       constructor=tt.dscalar,
46
                       test=0,
47
                       make_comparable=None,
48
                       elemwise=False):
UNCOV
49
    y = constructor('y')
3×
UNCOV
50
    y.tag.test_value = test
3×
51

UNCOV
52
    x = transform.backward(y)
3×
UNCOV
53
    if make_comparable:
3×
UNCOV
54
        x = make_comparable(x)
3×
55

UNCOV
56
    if not elemwise:
3×
UNCOV
57
        jac = tt.log(tt.nlinalg.det(jacobian(x, [y])))
3×
58
    else:
UNCOV
59
        jac = tt.log(tt.abs_(tt.diag(jacobian(x, [y]))))
3×
60

61
    # ljd = log jacobian det
UNCOV
62
    actual_ljd = theano.function([y], jac)
3×
63

UNCOV
64
    computed_ljd = theano.function([y], tt.as_tensor_variable(
3×
65
        transform.jacobian_det(y)), on_unused_input='ignore')
66

UNCOV
67
    for yval in domain.vals:
3×
UNCOV
68
        close_to(
3×
69
            actual_ljd(yval),
70
            computed_ljd(yval), tol)
71

72

UNCOV
73
def test_simplex():
3×
UNCOV
74
    check_vector_transform(tr.stick_breaking, Simplex(2))
3×
UNCOV
75
    check_vector_transform(tr.stick_breaking, Simplex(4))
3×
76

UNCOV
77
    check_transform(tr.stick_breaking, MultiSimplex(
3×
78
        3, 2), constructor=tt.dmatrix, test=np.zeros((2, 2)))
79

80

UNCOV
81
def test_simplex_bounds():
3×
UNCOV
82
    vals = get_values(tr.stick_breaking, Vector(R, 2),
3×
83
                      tt.dvector, np.array([0, 0]))
84

UNCOV
85
    close_to(vals.sum(axis=1), 1, tol)
3×
UNCOV
86
    close_to_logical(vals > 0, True, tol)
3×
UNCOV
87
    close_to_logical(vals < 1, True, tol)
3×
88

UNCOV
89
    check_jacobian_det(tr.stick_breaking, Vector(
3×
90
        R, 2), tt.dvector, np.array([0, 0]), lambda x: x[:-1])
91

92

UNCOV
93
def test_sum_to_1():
3×
UNCOV
94
    check_vector_transform(tr.sum_to_1, Simplex(2))
3×
UNCOV
95
    check_vector_transform(tr.sum_to_1, Simplex(4))
3×
96

UNCOV
97
    check_jacobian_det(tr.sum_to_1, Vector(Unit, 2),
3×
98
                       tt.dvector, np.array([0, 0]), lambda x: x[:-1])
99

100

UNCOV
101
def test_log():
3×
UNCOV
102
    check_transform(tr.log, Rplusbig)
3×
103

UNCOV
104
    check_jacobian_det(tr.log, Rplusbig, elemwise=True)
3×
UNCOV
105
    check_jacobian_det(tr.log, Vector(Rplusbig, 2),
3×
106
                       tt.dvector, [0, 0], elemwise=True)
107

UNCOV
108
    vals = get_values(tr.log)
3×
UNCOV
109
    close_to_logical(vals > 0, True, tol)
3×
110

111

UNCOV
112
def test_log_exp_m1():
3×
UNCOV
113
    check_transform(tr.log_exp_m1, Rplusbig)
3×
114

UNCOV
115
    check_jacobian_det(tr.log_exp_m1, Rplusbig, elemwise=True)
3×
UNCOV
116
    check_jacobian_det(tr.log_exp_m1, Vector(Rplusbig, 2),
3×
117
                       tt.dvector, [0, 0], elemwise=True)
118

UNCOV
119
    vals = get_values(tr.log_exp_m1)
3×
UNCOV
120
    close_to_logical(vals > 0, True, tol)
3×
121

122

UNCOV
123
def test_logodds():
3×
UNCOV
124
    check_transform(tr.logodds, Unit)
3×
125

UNCOV
126
    check_jacobian_det(tr.logodds, Unit, elemwise=True)
3×
UNCOV
127
    check_jacobian_det(tr.logodds, Vector(Unit, 2),
3×
128
                       tt.dvector, [.5, .5], elemwise=True)
129

UNCOV
130
    vals = get_values(tr.logodds)
3×
UNCOV
131
    close_to_logical(vals > 0, True, tol)
3×
UNCOV
132
    close_to_logical(vals < 1, True, tol)
3×
133

134

UNCOV
135
def test_lowerbound():
3×
UNCOV
136
    trans = tr.lowerbound(0.0)
3×
UNCOV
137
    check_transform(trans, Rplusbig)
3×
138

UNCOV
139
    check_jacobian_det(trans, Rplusbig, elemwise=True)
3×
UNCOV
140
    check_jacobian_det(trans, Vector(Rplusbig, 2),
3×
141
                       tt.dvector, [0, 0], elemwise=True)
142

UNCOV
143
    vals = get_values(trans)
3×
UNCOV
144
    close_to_logical(vals > 0, True, tol)
3×
145

146

UNCOV
147
def test_upperbound():
3×
UNCOV
148
    trans = tr.upperbound(0.0)
3×
UNCOV
149
    check_transform(trans, Rminusbig)
3×
150

UNCOV
151
    check_jacobian_det(trans, Rminusbig, elemwise=True)
3×
UNCOV
152
    check_jacobian_det(trans, Vector(Rminusbig, 2),
3×
153
                       tt.dvector, [-1, -1], elemwise=True)
154

UNCOV
155
    vals = get_values(trans)
3×
UNCOV
156
    close_to_logical(vals < 0, True, tol)
3×
157

158

UNCOV
159
def test_interval():
3×
UNCOV
160
    for a, b in [(-4, 5.5), (.1, .7), (-10, 4.3)]:
3×
UNCOV
161
        domain = Unit * np.float64(b - a) + np.float64(a)
3×
UNCOV
162
        trans = tr.interval(a, b)
3×
UNCOV
163
        check_transform(trans, domain)
3×
164

UNCOV
165
        check_jacobian_det(trans, domain, elemwise=True)
3×
166

UNCOV
167
        vals = get_values(trans)
3×
UNCOV
168
        close_to_logical(vals > a, True, tol)
3×
UNCOV
169
        close_to_logical(vals < b, True, tol)
3×
170

171

UNCOV
172
def test_circular():
3×
UNCOV
173
    trans = tr.circular
3×
UNCOV
174
    check_transform(trans, Circ)
3×
175

UNCOV
176
    check_jacobian_det(trans, Circ)
3×
177

UNCOV
178
    vals = get_values(trans)
3×
UNCOV
179
    close_to_logical(vals > -np.pi, True, tol)
3×
UNCOV
180
    close_to_logical(vals < np.pi, True, tol)
3×
181

UNCOV
182
    assert isinstance(trans.forward(1), tt.TensorConstant)
3×
183

184

UNCOV
185
def test_ordered():
3×
UNCOV
186
    check_vector_transform(tr.ordered, SortedVector(6))
3×
187

UNCOV
188
    check_jacobian_det(tr.ordered, Vector(R, 2),
3×
189
                       tt.dvector, np.array([0, 0]), elemwise=False)
190

UNCOV
191
    vals = get_values(tr.ordered, Vector(R, 3),
3×
192
                      tt.dvector, np.zeros(3))
UNCOV
193
    close_to_logical(np.diff(vals) >= 0, True, tol)
3×
194

195

UNCOV
196
@pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
3×
197
def test_chain():
UNCOV
198
    chain_tranf = tr.Chain([tr.logodds, tr.ordered])
3×
UNCOV
199
    check_vector_transform(chain_tranf, UnitSortedVector(3))
3×
200

UNCOV
201
    check_jacobian_det(chain_tranf, Vector(R, 4),
2×
202
                       tt.dvector, np.zeros(4), elemwise=False)
203

UNCOV
204
    vals = get_values(chain_tranf, Vector(R, 5),
2×
205
                      tt.dvector, np.zeros(5))
UNCOV
206
    close_to_logical(np.diff(vals) >= 0, True, tol)
2×
207

208

UNCOV
209
class TestElementWiseLogp(SeededTest):
3×
UNCOV
210
    def build_model(self, distfam, params, shape, transform, testval=None):
3×
UNCOV
211
        if testval is not None:
3×
UNCOV
212
            testval = pm.floatX(testval)
3×
UNCOV
213
        with pm.Model() as m:
3×
UNCOV
214
            distfam('x', shape=shape, transform=transform, testval=testval, **params)
3×
UNCOV
215
        return m
3×
216

UNCOV
217
    def check_transform_elementwise_logp(self, model):
3×
UNCOV
218
        x0 = model.deterministics[0]
3×
UNCOV
219
        x = model.free_RVs[0]
3×
UNCOV
220
        assert x.ndim == x.logp_elemwiset.ndim
3×
221

UNCOV
222
        pt = model.test_point
3×
UNCOV
223
        array = np.random.randn(*pt[x.name].shape)
3×
UNCOV
224
        pt[x.name] = array
3×
UNCOV
225
        dist = x.distribution
3×
UNCOV
226
        logp_nojac = x0.distribution.logp(dist.transform_used.backward(array))
3×
UNCOV
227
        jacob_det = dist.transform_used.jacobian_det(theano.shared(array))
3×
UNCOV
228
        assert x.logp_elemwiset.ndim == jacob_det.ndim
3×
229

UNCOV
230
        elementwiselogp = logp_nojac + jacob_det
3×
231

UNCOV
232
        close_to(x.logp_elemwise(pt), elementwiselogp.eval(), tol)
3×
233

UNCOV
234
    def check_vectortransform_elementwise_logp(self, model, vect_opt=0):
3×
UNCOV
235
        x0 = model.deterministics[0]
3×
UNCOV
236
        x = model.free_RVs[0]
3×
UNCOV
237
        assert (x.ndim-1) == x.logp_elemwiset.ndim
3×
238

UNCOV
239
        pt = model.test_point
3×
UNCOV
240
        array = np.random.randn(*pt[x.name].shape)
3×
UNCOV
241
        pt[x.name] = array
3×
UNCOV
242
        dist = x.distribution
3×
UNCOV
243
        logp_nojac = x0.distribution.logp(dist.transform_used.backward(array))
3×
UNCOV
244
        jacob_det = dist.transform_used.jacobian_det(theano.shared(array))
3×
UNCOV
245
        assert x.logp_elemwiset.ndim == jacob_det.ndim
3×
246

UNCOV
247
        if vect_opt == 0:
3×
248
            # the original distribution is univariate
UNCOV
249
            elementwiselogp = logp_nojac.sum(axis=-1) + jacob_det
3×
250
        else:
UNCOV
251
            elementwiselogp = logp_nojac + jacob_det
3×
252

UNCOV
253
        close_to(x.logp_elemwise(pt), elementwiselogp.eval(), tol)
3×
254

UNCOV
255
    @pytest.mark.parametrize('sd,shape', [
3×
256
        (2.5, 2),
257
        (5., (2, 3)),
258
        (np.ones(3)*10., (4, 3)),
259
    ])
260
    def test_half_normal(self, sd, shape):
UNCOV
261
        model = self.build_model(pm.HalfNormal, {'sd': sd}, shape=shape, transform=tr.log)
3×
UNCOV
262
        self.check_transform_elementwise_logp(model)
3×
263

UNCOV
264
    @pytest.mark.parametrize('lam,shape', [
3×
265
        (2.5, 2),
266
        (5., (2, 3)),
267
        (np.ones(3), (4, 3))
268
    ])
269
    def test_exponential(self, lam, shape):
UNCOV
270
        model = self.build_model(pm.Exponential, {'lam': lam}, shape=shape, transform=tr.log)
3×
UNCOV
271
        self.check_transform_elementwise_logp(model)
3×
272

UNCOV
273
    @pytest.mark.parametrize('a,b,shape', [
3×
274
        (1., 1., 2),
275
        (.5, .5, (2, 3)),
276
        (np.ones(3), np.ones(3), (4, 3)),
277
    ])
278
    def test_beta(self, a, b, shape):
UNCOV
279
        model = self.build_model(pm.Beta, {'alpha': a, 'beta': b}, shape=shape, transform=tr.logodds)
3×
UNCOV
280
        self.check_transform_elementwise_logp(model)
3×
281

UNCOV
282
    @pytest.mark.parametrize('lower,upper,shape', [
3×
283
        (0., 1., 2),
284
        (.5, 5.5, (2, 3)),
285
        (pm.floatX(np.zeros(3)), pm.floatX(np.ones(3)), (4, 3))
286
    ])
287
    def test_uniform(self, lower, upper, shape):
UNCOV
288
        interval = tr.Interval(lower, upper)
3×
UNCOV
289
        model = self.build_model(pm.Uniform, {'lower': lower, 'upper': upper},
3×
290
                                 shape=shape, transform=interval)
UNCOV
291
        self.check_transform_elementwise_logp(model)
3×
292

UNCOV
293
    @pytest.mark.parametrize('mu,kappa,shape', [
3×
294
        (0., 1., 2),
295
        (-.5, 5.5, (2, 3)),
296
        (np.zeros(3), np.ones(3), (4, 3))
297
    ])
298
    def test_vonmises(self, mu, kappa, shape):
UNCOV
299
        model = self.build_model(pm.VonMises, {'mu': mu, 'kappa': kappa}, shape=shape, transform=tr.circular)
3×
UNCOV
300
        self.check_transform_elementwise_logp(model)
3×
301

UNCOV
302
    @pytest.mark.parametrize('a,shape', [
3×
303
        (np.ones(2), 2),
304
        (np.ones((2, 3))*.5, (2, 3)),
305
        (np.ones(3), (4, 3))
306
    ])
307
    def test_dirichlet(self, a, shape):
UNCOV
308
        model = self.build_model(pm.Dirichlet, {'a': a}, shape=shape, transform=tr.stick_breaking)
3×
UNCOV
309
        self.check_vectortransform_elementwise_logp(model, vect_opt=1)
3×
310

UNCOV
311
    def test_normal_ordered(self):
3×
UNCOV
312
        model = self.build_model(pm.Normal, {'mu': 0., 'sd': 1.}, shape=3,
3×
313
                                 testval=np.asarray([-1., 1., 4.]),
314
                                 transform=tr.ordered)
UNCOV
315
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
316

UNCOV
317
    @pytest.mark.parametrize('sd,shape', [
3×
318
        (2.5, (2,)),
319
        (np.ones(3), (4, 3)),
320
    ])
UNCOV
321
    @pytest.mark.xfail(condition=(theano.config.floatX == "float32"), reason="Fails on float32")
3×
322
    def test_half_normal_ordered(self, sd, shape):
UNCOV
323
        testval = np.sort(np.abs(np.random.randn(*shape)))
3×
UNCOV
324
        model = self.build_model(pm.HalfNormal, {'sd': sd}, shape=shape,
3×
325
                                 testval=testval,
326
                                 transform=tr.Chain([tr.log, tr.ordered]))
UNCOV
327
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
328

UNCOV
329
    @pytest.mark.parametrize('lam,shape', [
3×
330
        (2.5, (2,)),
331
        (np.ones(3), (4, 3))
332
    ])
333
    def test_exponential_ordered(self, lam, shape):
UNCOV
334
        testval = np.sort(np.abs(np.random.randn(*shape)))
3×
UNCOV
335
        model = self.build_model(pm.Exponential, {'lam': lam}, shape=shape,
3×
336
                                 testval=testval,
337
                                 transform=tr.Chain([tr.log, tr.ordered]))
UNCOV
338
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
339

UNCOV
340
    @pytest.mark.parametrize('a,b,shape', [
3×
341
        (1., 1., (2,)),
342
        (np.ones(3), np.ones(3), (4, 3)),
343
    ])
344
    def test_beta_ordered(self, a, b, shape):
UNCOV
345
        testval = np.sort(np.abs(np.random.rand(*shape)))
3×
UNCOV
346
        model = self.build_model(pm.Beta, {'alpha': a, 'beta': b}, shape=shape,
3×
347
                                 testval=testval,
348
                                 transform=tr.Chain([tr.logodds, tr.ordered]))
UNCOV
349
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
350

UNCOV
351
    @pytest.mark.parametrize('lower,upper,shape', [
3×
352
        (0., 1., (2,)),
353
        (pm.floatX(np.zeros(3)), pm.floatX(np.ones(3)), (4, 3))
354
    ])
355
    def test_uniform_ordered(self, lower, upper, shape):
UNCOV
356
        interval = tr.Interval(lower, upper)
3×
UNCOV
357
        testval = np.sort(np.abs(np.random.rand(*shape)))
3×
UNCOV
358
        model = self.build_model(pm.Uniform, {'lower': lower, 'upper': upper}, shape=shape,
3×
359
                                 testval=testval,
360
                                 transform=tr.Chain([interval, tr.ordered]))
UNCOV
361
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
362

UNCOV
363
    @pytest.mark.parametrize('mu,kappa,shape', [
3×
364
        (0., 1., (2,)),
365
        (np.zeros(3), np.ones(3), (4, 3))
366
    ])
367
    def test_vonmises_ordered(self, mu, kappa, shape):
UNCOV
368
        testval = np.sort(np.abs(np.random.rand(*shape)))
3×
UNCOV
369
        model = self.build_model(pm.VonMises, {'mu': mu, 'kappa': kappa}, shape=shape,
3×
370
                                 testval=testval,
371
                                 transform=tr.Chain([tr.circular, tr.ordered]))
UNCOV
372
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
373

UNCOV
374
    @pytest.mark.parametrize('lower,upper,shape,transform', [
3×
375
        (0., 1., (2,), tr.stick_breaking),
376
        (.5, 5.5, (2, 3), tr.stick_breaking),
377
        (np.zeros(3), np.ones(3), (4, 3), tr.Chain([tr.sum_to_1, tr.logodds]))
378
    ])
379
    def test_uniform_other(self, lower, upper, shape, transform):
UNCOV
380
        testval = np.ones(shape)/shape[-1]
3×
UNCOV
381
        model = self.build_model(pm.Uniform, {'lower': lower, 'upper': upper},
3×
382
                                 shape=shape,
383
                                 testval=testval,
384
                                 transform=transform)
UNCOV
385
        self.check_vectortransform_elementwise_logp(model, vect_opt=0)
3×
386

UNCOV
387
    @pytest.mark.parametrize('mu,cov,shape', [
3×
388
        (np.zeros(2), np.diag(np.ones(2)), (2,)),
389
        (np.zeros(3), np.diag(np.ones(3)), (4, 3)),
390
    ])
391
    def test_mvnormal_ordered(self, mu, cov, shape):
UNCOV
392
        testval = np.sort(np.random.randn(*shape))
3×
UNCOV
393
        model = self.build_model(pm.MvNormal, {'mu': mu, 'cov': cov}, shape=shape,
3×
394
                                 testval=testval,
395
                                 transform=tr.ordered)
UNCOV
396
        self.check_vectortransform_elementwise_logp(model, vect_opt=1)
3×
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2021 Coveralls, Inc