Distributions.jl
Distributions.jl copied to clipboard
Convolution between Gaussian mixture model and normal distribution
It would be nice to allow the convolution between Gaussian mixture model and normal distribution, for example:
using Distributions # v0.25.113
d1 = MixtureModel(Normal, [(-2.0, 1.0), (2.0, 1.0)],[0.5,0.5])
d2 = Normal(0,1)
convolve(d1,d2)
Currently, this fails with:
ERROR: MethodError: no method matching convolve(::MixtureModel{Univariate, Continuous, Normal, Categorical{Float64, Vector{Float64}}}, ::Normal{Float64})
Support for this would be quite easy to add:
import Distributions: convolve, MixtureModel
# special case: https://mathoverflow.net/questions/370982/convolution-of-two-gaussian-mixture-model
Distributions.convolve(d1::MixtureModel,d2::Normal) =
MixtureModel([convolve(c,d2) for c in d1.components],d1.prior)
Distributions.convolve(d1::Normal,d2::MixtureModel) = convolve(d2,d1)
d3 = convolve(d1,d2)
using Test
@test var(d3.components[1]) ≈ 2
@test var(d3.components[2]) ≈ 2
@test mean(d3.components[1]) ≈ -2
@test mean(d3.components[2]) ≈ 2
@test convolve(d1,d2) == convolve(d2,d1)
I can easily made a PR with the test case.
This doesn't necessarily need to be limited to a mixture of Gaussians and a Gaussian, right? It seems like it could generalize to any instance where you have a mixture where all of input models or mixture model components are of the same type, for example:
d1 = MixtureModel(Gamma, [(2.0, 1.0), (2.0, 2.0)],[0.5,0.5])
d2 = Gamma(3.,4.)
d3 = MixtureModel(Gamma, [(2.0, 1.0), (2.0, 1.0), (3.0, 1.0)],[0.5,0.25,0.25])
convolve(d1,d2)
convolve(d1,d3)
Edit: Something like
Distributions.convolve(d1::MixtureModel,d2::MixtureModel) =
MixtureModel([convolve(a,b) for a in d1.components for b in d2.components],[a.*b for a in d1.prior.p for b in d2.prior.p])
Edit 2:
Although this particular example with Gamma won't work due to the arg checking when convolving Gammas, but I think the general idea still holds.