1
+ # coding: utf-8
1
2
"""
2
3
pymc3.distributions
3
4
17
18
from pymc3 .theanof import floatX
18
19
from . import transforms
19
20
20
- from .dist_math import (bound , logpow , gammaln , betaln , std_cdf , i0 , i1 ,
21
- alltrue_elemwise )
21
+ from .dist_math import (
22
+ alltrue_elemwise , betaln , bound , gammaln , i0 , i1 , logpow , normallogcdf ,
23
+ std_cdf , zvalue
24
+ )
25
+
22
26
from .distribution import Continuous , draw_values , generate_samples , Bound
23
27
24
28
__all__ = ['Uniform' , 'Flat' , 'Normal' , 'Beta' , 'Exponential' , 'Laplace' ,
@@ -183,6 +187,17 @@ def random(self, point=None, size=None, repeat=None):
183
187
def logp (self , value ):
184
188
return tt .zeros_like (value )
185
189
190
+ def logcdf (self , value ):
191
+ return tt .switch (
192
+ tt .eq (value , - np .inf ),
193
+ - np .inf ,
194
+ tt .switch (
195
+ tt .eq (value , np .inf ),
196
+ 0 ,
197
+ tt .log (0.5 )
198
+ )
199
+ )
200
+
186
201
187
202
class Normal (Continuous ):
188
203
R"""
@@ -247,16 +262,7 @@ def logp(self, value):
247
262
sd > 0 )
248
263
249
264
def logcdf (self , value ):
250
- mu = self .mu
251
- sd = self .sd
252
- z = zvalue (value , mu = mu , sd = sd )
253
-
254
- return tt .switch (
255
- tt .lt (z , - 1.0 ),
256
- tt .log (tt .erfcx (- z / tt .sqrt (2. )) / 2. ) -
257
- tt .sqr (z ) / 2 ,
258
- tt .log1p (- tt .erfc (z / tt .sqrt (2. )) / 2. )
259
- )
265
+ return normallogcdf (value , mu = self .mu , sd = self .sd )
260
266
261
267
262
268
class HalfNormal (PositiveContinuous ):
@@ -373,6 +379,9 @@ class Wald(PositiveContinuous):
373
379
.. [Michael1976] Michael, J. R., Schucany, W. R. and Hass, R. W. (1976).
374
380
Generating Random Variates Using Transformations with Multiple Roots.
375
381
The American Statistician, Vol. 30, No. 2, pp. 88-90
382
+
383
+ .. [Giner2016] Göknur Giner, Gordon K. Smyth (2016)
384
+ statmod: Probability Calculations for the Inverse Gaussian Distribution
376
385
"""
377
386
378
387
def __init__ (self , mu = None , lam = None , phi = None , alpha = 0. , * args , ** kwargs ):
@@ -381,7 +390,7 @@ def __init__(self, mu=None, lam=None, phi=None, alpha=0., *args, **kwargs):
381
390
self .alpha = alpha = tt .as_tensor_variable (alpha )
382
391
self .mu = mu = tt .as_tensor_variable (mu )
383
392
self .lam = lam = tt .as_tensor_variable (lam )
384
- self .phi = phi = tt .as_tensor_variable (phi )
393
+ self .phi = phi = tt .as_tensor_variable (phi )
385
394
386
395
self .mean = self .mu + self .alpha
387
396
self .mode = self .mu * (tt .sqrt (1. + (1.5 * self .mu / self .lam )** 2 )
@@ -439,6 +448,46 @@ def logp(self, value):
439
448
value > 0 , value - alpha > 0 ,
440
449
mu > 0 , lam > 0 , alpha >= 0 )
441
450
451
+ def logcdf (self , value ):
452
+ # Distribution parameters
453
+ mu = self .mu
454
+ lam = self .lam
455
+ alpha = self .alpha
456
+
457
+ value -= alpha
458
+ q = value / mu
459
+ l = lam * mu
460
+ r = tt .sqrt (value * lam )
461
+
462
+ a = normallogcdf ((q - 1. )/ r )
463
+ b = 2. / l + normallogcdf (- (q + 1. )/ r )
464
+ return tt .switch (
465
+ (
466
+ # Left limit
467
+ tt .lt (value , 0 ) |
468
+ (tt .eq (value , 0 ) & tt .gt (mu , 0 ) & tt .lt (lam , np .inf )) |
469
+ (tt .lt (value , mu ) & tt .eq (lam , 0 ))
470
+ ),
471
+ - np .inf ,
472
+ tt .switch (
473
+ (
474
+ # Right limit
475
+ tt .eq (value , np .inf ) |
476
+ (tt .eq (lam , 0 ) & tt .gt (value , mu )) |
477
+ (tt .gt (value , 0 ) & tt .eq (lam , np .inf )) |
478
+ # Degenerate distribution
479
+ (
480
+ tt .lt (mu , np .inf ) &
481
+ tt .eq (mu , value ) &
482
+ tt .eq (lam , 0 )
483
+ ) |
484
+ (tt .eq (value , 0 ) & tt .eq (lam , np .inf ))
485
+ ),
486
+ 0 ,
487
+ a + tt .log1p (tt .exp (b - a ))
488
+ )
489
+ )
490
+
442
491
443
492
def cont_fraction_beta (value , a , b , max_iter = 200 ):
444
493
'''Evaluates the continued fraction form of the incomplete Beta function.
@@ -627,6 +676,31 @@ def logp(self, value):
627
676
lam = self .lam
628
677
return bound (tt .log (lam ) - lam * value , value > 0 , lam > 0 )
629
678
679
+ def logcdf (self , value ):
680
+ """
681
+ Compute the log CDF for the Exponential distribution
682
+
683
+ References
684
+ ----------
685
+ .. [Machler2012] Martin Mächler (2012).
686
+ "Accurately computing log(1-exp(-|a|)) Assessed by the Rmpfr
687
+ package"
688
+ """
689
+ value = floatX (tt .as_tensor (value ))
690
+ lam = self .lam
691
+ a = lam * value
692
+ return tt .switch (
693
+ tt .le (value , 0.0 ),
694
+ - np .inf ,
695
+ tt .switch (
696
+ tt .le (a , tt .log (2.0 )),
697
+ tt .log (- tt .expm1 (- a )),
698
+ tt .log1p (- tt .exp (- a )),
699
+ )
700
+ )
701
+
702
+
703
+
630
704
631
705
class Laplace (Continuous ):
632
706
R"""
@@ -892,6 +966,20 @@ def logp(self, value):
892
966
- logpow (value , alpha + 1 ),
893
967
value >= m , alpha > 0 , m > 0 )
894
968
969
+ def logcdf (self , value ):
970
+ m = self .m
971
+ alpha = self .alpha
972
+ arg = (m / value ) ** alpha
973
+ return tt .switch (
974
+ tt .lt (value , m ),
975
+ - np .inf ,
976
+ tt .switch (
977
+ tt .le (arg , 1e-5 ),
978
+ tt .log1p (- arg ),
979
+ tt .log (1 - arg )
980
+ )
981
+ )
982
+
895
983
896
984
class Cauchy (Continuous ):
897
985
R"""
0 commit comments