当参数类型依赖时如何在 Julia 中编写函数

How to write a function in Julia when the type the arguments are dependent

首先我要承认我是 Julia 的初学者,所以很可能存在针对我的问题的更好的体系结构。所以,也请考虑一下!不管怎样,问题来了。

我正在开发贝叶斯数据包 analysis.I 从最简单的模型开始,贝叶斯有限混合模型。我们假设数据是由有限数量的概率分布生成的。在贝叶斯分析中,我们将先验放在可能性上,并将其称为贝叶斯成分。

我已经为每个组件定义了一个新类型。例如 Gaussian1DGaussian1D, MultinomialDirichlet, ....

type Gaussian1DGaussian1D
    μ0::Float64             # mean hyper-parameter
    σ20::Float64            # variance hyper-parameter

    μ::Float64              # mean of the Gaussian1D likelihood
    σ2::Float64             # fixed variance of the Gaussian1D likelihood

    nn::Int64               # number of data points the component contains

    Gaussian1DGaussian1D(μ0::Real, σ20::Real, μ::Real, σ2::Real, nn::Real) = new(μ0, σ20, μ, σ2, nn)
end
Gaussian1DGaussian1D(μ0::Real, σ20::Real, σ2::Real) = Gaussian1DGaussian1D(μ0, σ20, μ0, σ2, 0)
Base.deepcopy(me::Gaussian1DGaussian1D) = Gaussian1DGaussian1D(me.μ0, me.σ20, me.μ, me.σ2, me.nn)   

function logpredictive(me::Gaussian1DGaussian1D, xx::Real)
    # returns the log-predictive of xx given the observed data
    # i.e. log p(xx|x1,...,xn)

    μ, σ2 = posterior(me)
    ll = exp(-(xx - μ)^2 / (2*(σ2 + me.σ2))) / sqrt(2*pi * (σ2 + me.σ2))
    return log(ll)
end

以及每种类型的许多其他功能。

现在我定义了一个参数化的 FiniteMixtureModel:

type FiniteMixtureModel{T}
    bayesian_component::Vector{T}  
    K::Int64

    FiniteMixtureModel{T}(c::T, K::Int64) = new([deepcopy(c) for k = 1:K], K)
end
FiniteMixtureModel{T}(c::T, K) = FiniteMixtureModel{eltype(c)}(c, K)

这使我能够定义先前定义的贝叶斯组件的 FiniteMixtureModel。例如,myFMM 将是 5 个高斯似然与高斯先验的混合模型。

myFMM = FiniteMixtureModel(Gaussian1DGaussian1D(1, 1, 1), 5)

现在为了推理,我定义了一个 Gibbs 采样器。

function gibbs_sampler(fmm::FiniteMixtureModel, xx::Vector{???}, ...)
    # TO BE IMPLEMENTED!
    println("Hi")
end

xx 的类型取决于 fmm 的元素类型。例如,如果 fmm 是 Gaussian1DGaussian1D 的 FMM,则 xx 将是浮点向量。如果 fmm 是 MultinomialDirichlet 的 FMM,则 xx 将是整数向量。函数的主体对于任何类型 (xx) 都是完全相同的。我如何编写一个函数来考虑其参数类型之间的这种依赖性?

xx的类型应该和bayesian_component的类型一样吧?

如果你不想让 xx 成为 FiniteMixtureModel 的组成部分(这似乎混淆了你的类型层次结构),你可以显式转换 xx 作为解决方法:

function gibbs_sampler(fmm::FiniteMixtureModel, xx::Vector, ...)
    xx = oftype(fmm.bayesian_component,xx)
    # TO BE IMPLEMENTED!
    println("Hi")
end

然而,这可能会导致一些 InexactErrors:

例如当 eltype(xx)=Float64, eltype(bayesian_component)=Int64

您可以编写多个具有 julia 的 多重分派 功能的函数。在这种情况下,你可以这样写:

function gibbs_sampler(fmm::FiniteMixtureModel{Gaussian1DGaussian1D}, xx::Vector{Float64}, ...)
    # TO BE IMPLEMENTED!
    println("Hi")
end
function gibbs_sampler(fmm::FiniteMixtureModel{MultinomialDirichlet}, xx::Vector{Int64}, ...)
    # TO BE IMPLEMENTED!
    println("Hi")
end
...
...

但这看起来多余。这就是 parameterised function 出现的地方,这是@ColinTBowers 推荐的。

或者您可以使用 fill 函数来减少冗余:

function fill(fmm, xx, ...)
    #TO BE IMPLEMENTED!
    println("Hi")
end
function gibbs_sampler(fmm::FiniteMixtureModel{Gaussian1DGaussian1D}, xx::Vector{Float64}, ...)
    fill(fmm, xx, ...)
end
function gibbs_sampler(fmm::FiniteMixtureModel{MultinomialDirichlet}, xx::Vector{Int64}, ...)
    fill(fmm, xx, ...)
end
...
...