1- # TODO : this distribution may need clean-up
21"""
32 PoissonBinomial(p)
43
@@ -24,35 +23,45 @@ External links:
2423* [Poisson-binomial distribution on Wikipedia](http://en.wikipedia.org/wiki/Poisson_binomial_distribution)
2524
2625"""
27- struct PoissonBinomial{T<: Real } <: DiscreteUnivariateDistribution
28- p:: Vector{T}
29- pmf:: Vector{T}
30-
31- function PoissonBinomial {T} (p:: AbstractArray ) where {T <: Real }
32- pb = poissonbinomial_pdf (p)
33- @assert isprobvec (pb)
34- new {T} (p, pb)
26+ mutable struct PoissonBinomial{T<: Real ,P<: AbstractVector{T} } <: DiscreteUnivariateDistribution
27+ p:: P
28+ pmf:: Union{Nothing,Vector{T}} # lazy computation of the probability mass function
29+
30+ function PoissonBinomial {T} (p:: AbstractVector{T} ; check_args= true ) where {T <: Real }
31+ check_args && @check_args (PoissonBinomial, all (x -> zero (x) <= x <= one (x), p))
32+ return new {T,typeof(p)} (p, nothing )
3533 end
3634end
3735
38- function PoissonBinomial (p:: AbstractArray{T} ; check_args= true ) where {T <: Real }
39- if check_args
40- for i in eachindex (p)
41- @check_args (PoissonBinomial, 0 <= p[i] <= 1 )
36+ function PoissonBinomial (p:: AbstractVector{T} ; check_args= true ) where {T<: Real }
37+ return PoissonBinomial {T} (p; check_args= check_args)
38+ end
39+
40+ function Base. getproperty (d:: PoissonBinomial , x:: Symbol )
41+ if x === :pmf
42+ z = getfield (d, :pmf )
43+ if z === nothing
44+ y = poissonbinomial_pdf (d. p)
45+ isprobvec (y) || error (" probability mass function is not normalized" )
46+ setfield! (d, :pmf , y)
47+ return y
48+ else
49+ return z
4250 end
51+ else
52+ return getfield (d, x)
4353 end
44- return PoissonBinomial {T} (p)
4554end
4655
4756@distr_support PoissonBinomial 0 length (d. p)
4857
4958# ### Conversions
5059
51- function PoissonBinomial (:: Type{PoissonBinomial{T}} , p:: Vector {S} ) where {T, S}
52- return PoissonBinomial (Vector {T} (p))
60+ function PoissonBinomial (:: Type{PoissonBinomial{T}} , p:: AbstractVector {S} ) where {T, S}
61+ return PoissonBinomial (AbstractVector {T} (p))
5362end
5463function PoissonBinomial (:: Type{PoissonBinomial{T}} , d:: PoissonBinomial{S} ) where {T, S}
55- return PoissonBinomial (Vector {T} (d. p), check_args= false )
64+ return PoissonBinomial (AbstractVector {T} (d. p), check_args= false )
5665end
5766
5867# ### Parameters
@@ -67,7 +76,7 @@ partype(::PoissonBinomial{T}) where {T} = T
6776# ### Properties
6877
6978mean (d:: PoissonBinomial ) = sum (succprob (d))
70- var (d:: PoissonBinomial ) = sum (succprob (d) .* failprob (d))
79+ var (d:: PoissonBinomial ) = sum (p * ( 1 - p) for p in succprob (d))
7180
7281function skewness (d:: PoissonBinomial{T} ) where {T}
7382 v = zero (T)
@@ -91,23 +100,27 @@ function kurtosis(d::PoissonBinomial{T}) where {T}
91100 s / v / v
92101end
93102
94- entropy (d:: PoissonBinomial ) = entropy (Categorical ( d. pmf) )
103+ entropy (d:: PoissonBinomial ) = entropy (d. pmf)
95104median (d:: PoissonBinomial ) = median (Categorical (d. pmf)) - 1
96105mode (d:: PoissonBinomial ) = argmax (d. pmf) - 1
97- modes (d:: PoissonBinomial ) = [x - 1 for x in modes (Categorical (d . pmf))]
106+ modes (d:: PoissonBinomial ) = modes (DiscreteNonParametric ( support (d), d . pmf))
98107
99108# ### Evaluation
100109
101110quantile (d:: PoissonBinomial , x:: Float64 ) = quantile (Categorical (d. pmf), x) - 1
102111
103- function mgf (d:: PoissonBinomial{T} , t:: Real ) where {T}
104- p, = params (d)
105- prod (one (T) .- p .+ p .* exp (t))
112+ function mgf (d:: PoissonBinomial , t:: Real )
113+ expm1_t = expm1 (t)
114+ mapreduce (* , succprob (d)) do p
115+ 1 + p * expm1_t
116+ end
106117end
107118
108- function cf (d:: PoissonBinomial{T} , t:: Real ) where {T}
109- p, = params (d)
110- prod (one (T) .- p .+ p .* cis (t))
119+ function cf (d:: PoissonBinomial , t:: Real )
120+ cis_t = cis (t)
121+ mapreduce (* , succprob (d)) do p
122+ 1 - p + p * cis_t
123+ end
111124end
112125
113126pdf (d:: PoissonBinomial , k:: Real ) = insupport (d, k) ? d. pmf[k+ 1 ] : zero (eltype (d. pmf))
@@ -120,19 +133,17 @@ logpdf(d::PoissonBinomial, k::Real) = log(pdf(d, k))
120133# Calculating binomial probabilities when the trial probabilities are unequal,
121134# Journal of Statistical Computation and Simulation, 14:2, 125-131, DOI: 10.1080/00949658208810534
122135#
123- function poissonbinomial_pdf (p:: AbstractArray{T,1} ) where {T <: Real }
124- n = length (p)
125- S = zeros (T, n + 1 )
126- S[ 1 ] = 1 - p[ 1 ]
127- S[ 2 ] = p[ 1 ]
128- @inbounds for col in 2 : n
129- for r in 1 : col
130- row = col - r + 1
131- S[row + 1 ] = ( 1 - p[col]) * S[row + 1 ] + p[col] * S[row]
136+ function poissonbinomial_pdf (p)
137+ S = zeros ( eltype (p), length (p) + 1 )
138+ S[ 1 ] = 1
139+ @inbounds for (col, p_col) in enumerate (p)
140+ q_col = 1 - p_col
141+ for row in col : ( - 1 ) : 1
142+ S[row + 1 ] = q_col * S[row + 1 ] + p_col * S[row]
143+ end
144+ S[1 ] *= q_col
132145 end
133- S[1 ] *= 1 - p[col]
134- end
135- return S
146+ return S
136147end
137148
138149# Computes the pdf of a poisson-binomial random variable using
0 commit comments