-
Notifications
You must be signed in to change notification settings - Fork 429
Extend gradlogpdf
to MixtureModels
#1827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
94cf6c0
e7dd8ef
3930983
65e3210
af7dde6
6ed9476
fe2f778
56860a1
b50f5eb
1d3c281
7ccc7dc
2c42066
c87d948
53e0977
4d4af7e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,13 @@ Here, `x` can be a single sample or an array of multiple samples. | |
""" | ||
logpdf(d::AbstractMixtureModel, x::Any) | ||
|
||
""" | ||
gradlogpdf(d::Union{UnivariateMixture, MultivariateMixture}, x) | ||
|
||
Evaluate the gradient of the logarithm of the (mixed) probability density function over a single sample `x`. | ||
""" | ||
gradlogpdf(d::AbstractMixtureModel, x::Any) | ||
|
||
""" | ||
rand(d::Union{UnivariateMixture, MultivariateMixture}) | ||
|
||
|
@@ -362,6 +369,38 @@ end | |
pdf(d::UnivariateMixture, x::Real) = _mixpdf1(d, x) | ||
logpdf(d::UnivariateMixture, x::Real) = _mixlogpdf1(d, x) | ||
|
||
function gradlogpdf(d::UnivariateMixture, x::Real) | ||
ps = probs(d) | ||
cs = components(d) | ||
|
||
# `d` is expected to have at least one distribution, otherwise this will just error | ||
psi, idxps = iterate(ps) | ||
csi, idxcs = iterate(cs) | ||
pdfx1 = pdf(csi, x) | ||
pdfx = psi * pdfx1 | ||
glp = pdfx * gradlogpdf(csi, x) | ||
if iszero(psi) || iszero(pdfx) | ||
glp = zero(glp) | ||
end | ||
|
||
while (iterps = iterate(ps, idxps)) !== nothing && (itercs = iterate(cs, idxcs)) !== nothing | ||
psi, idxps = iterps | ||
csi, idxcs = itercs | ||
if !iszero(psi) | ||
pdfxi = pdf(csi, x) | ||
if !iszero(pdfxi) | ||
pipdfxi = psi * pdfxi | ||
pdfx += pipdfxi | ||
glp += pipdfxi * gradlogpdf(csi, x) | ||
end | ||
end | ||
end | ||
if !iszero(pdfx) # else glp is already zero | ||
glp /= pdfx | ||
end | ||
Comment on lines
+398
to
+400
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it correct to return a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wondered about that, but decided to follow the current behavior already implemented. For example: julia> insupport(Beta(0.5, 0.5), -1)
false
julia> logpdf(Beta(0.5, 0.5), -1)
-Inf
julia> gradlogpdf(Beta(0.5, 0.5), -1)
0.0 I don't know. If it is constant There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most implementations return zero outside the support: and so on (Frechet, Gamma, ...), but some (Arcsin and Kumaraswamy) seem to just extend what happens at the edges of the support: while LogitNormal seems to be the only one that yields Meanwhile, Laplace seems to be the only one to error at a singular point: while Uniform, for example, is zero everywhere including the singular points. I think giving an error is a bit drastic, but yielding either zero or NaN (outside the support or at the singular points) seems reasonable to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should make this a separate issue and hopefully standardize the behavior. |
||
return glp | ||
end | ||
|
||
_pdf!(r::AbstractArray{<:Real}, d::UnivariateMixture{Discrete}, x::UnitRange) = _mixpdf!(r, d, x) | ||
_pdf!(r::AbstractArray{<:Real}, d::UnivariateMixture, x::AbstractArray{<:Real}) = _mixpdf!(r, d, x) | ||
_logpdf!(r::AbstractArray{<:Real}, d::UnivariateMixture, x::AbstractArray{<:Real}) = _mixlogpdf!(r, d, x) | ||
|
@@ -371,6 +410,37 @@ _logpdf(d::MultivariateMixture, x::AbstractVector{<:Real}) = _mixlogpdf1(d, x) | |
_pdf!(r::AbstractArray{<:Real}, d::MultivariateMixture, x::AbstractMatrix{<:Real}) = _mixpdf!(r, d, x) | ||
_logpdf!(r::AbstractArray{<:Real}, d::MultivariateMixture, x::AbstractMatrix{<:Real}) = _mixlogpdf!(r, d, x) | ||
|
||
function gradlogpdf(d::MultivariateMixture, x::AbstractVector{<:Real}) | ||
ps = probs(d) | ||
cs = components(d) | ||
|
||
# `d` is expected to have at least one distribution, otherwise this will just error | ||
psi, idxps = iterate(ps) | ||
csi, idxcs = iterate(cs) | ||
pdfx1 = pdf(csi, x) | ||
pdfx = psi * pdfx1 | ||
glp = pdfx * gradlogpdf(csi, x) | ||
if iszero(psi) || iszero(pdfx) | ||
rmsrosa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fill!(glp, zero(eltype(glp))) | ||
end | ||
|
||
while (iterps = iterate(ps, idxps)) !== nothing && (itercs = iterate(cs, idxcs)) !== nothing | ||
psi, idxps = iterps | ||
csi, idxcs = itercs | ||
if !iszero(psi) | ||
pdfxi = pdf(csi, x) | ||
if !iszero(pdfxi) | ||
pipdfxi = psi * pdfxi | ||
pdfx += pipdfxi | ||
glp .+= pipdfxi .* gradlogpdf(csi, x) | ||
end | ||
end | ||
end | ||
if !iszero(pdfx) # else glp is already zero | ||
glp ./= pdfx | ||
end | ||
return glp | ||
end | ||
|
||
## component-wise pdf and logpdf | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.