Distributions.jl icon indicating copy to clipboard operation
Distributions.jl copied to clipboard

Convolution between Gaussian mixture model and normal distribution

Open Alexander-Barth opened this issue 1 year ago • 1 comments

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.

Alexander-Barth avatar Dec 05 '24 07:12 Alexander-Barth

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.

BA1437 avatar Jan 15 '25 18:01 BA1437