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

当参数依赖于类型时,如何在Julia中编写函数,julia,bayesian,Julia,Bayesian,在开始的时候,我会承认我是Julia的初学者,所以很有可能存在一个更好的架构来解决我的问题。所以,请考虑一下!无论如何,问题出在这里 我正在开发一个用于贝叶斯数据分析的软件包。我从最简单的模型开始,即贝叶斯有限混合模型。我们假设数据是由有限个概率分布生成的。在贝叶斯分析中,我们将先验知识放在可能性上,称之为贝叶斯分量 我为每个组件定义了一个新类型。例如Gaussian1DGaussian1D、多项式虹膜网等 type Gaussian1DGaussian1D μ0::Float64

在开始的时候,我会承认我是Julia的初学者,所以很有可能存在一个更好的架构来解决我的问题。所以,请考虑一下!无论如何,问题出在这里

我正在开发一个用于贝叶斯数据分析的软件包。我从最简单的模型开始,即贝叶斯有限混合模型。我们假设数据是由有限个概率分布生成的。在贝叶斯分析中,我们将先验知识放在可能性上,称之为贝叶斯分量

我为每个组件定义了一个新类型。例如Gaussian1DGaussian1D、多项式虹膜网等

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)
这使我能够定义以前定义的贝叶斯组件的有限混合模型。例如,myFMM将是5个高斯似然数与高斯先验数的混合模型

myFMM = FiniteMixtureModel(Gaussian1DGaussian1D(1, 1, 1), 5)
现在,为了进行推断,我定义了一个吉布斯取样器

function gibbs_sampler(fmm::FiniteMixtureModel, xx::Vector{???}, ...)
    # TO BE IMPLEMENTED!
    println("Hi")
end
xx的类型取决于fmm元素的类型。例如,如果fmm是Gaussian1DGaussian1D的fmm,则xx将是浮点向量。如果fmm是多项式dirichlet的fmm,那么xx将是整数向量。函数体对于任何类型(xx)都是完全相同的。我如何编写一个函数来考虑它的参数类型之间的关系?

< p>类型<代码> xx <代码>应该与<代码> BayeSianguni组件< /代码>类型相同,对吗? 如果您不想使
xx
成为
FiniteMixtureModel
的一个组件(这似乎会弄脏类型层次结构的水),您可以显式转换
xx
的类型作为解决方法:

function gibbs_sampler(fmm::FiniteMixtureModel, xx::Vector, ...)
    xx = oftype(fmm.bayesian_component,xx)
    # TO BE IMPLEMENTED!
    println("Hi")
end
但是,这可能会导致一些
不精确错误
s:

e、 g.当
eltype(xx)=Float64
时,
eltype(贝叶斯分量)=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
...
...
但这看起来是多余的。这正是@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
...
...
xx
的类型应该与
bayesian\u组件的类型相同,对吗

如果您不想使
xx
成为
FiniteMixtureModel
的一个组件(这似乎会弄脏类型层次结构的水),您可以显式转换
xx
的类型作为解决方法:

function gibbs_sampler(fmm::FiniteMixtureModel, xx::Vector, ...)
    xx = oftype(fmm.bayesian_component,xx)
    # TO BE IMPLEMENTED!
    println("Hi")
end
但是,这可能会导致一些
不精确错误
s:

e、 g.当
eltype(xx)=Float64
时,
eltype(贝叶斯分量)=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
...
...
但这看起来是多余的。这正是@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
...
...

我可能遗漏了一些东西,但为什么不能直接使用
函数gibbs_sampler{T1,T2}(fmm::FiniteMixtureModel{T1},xx::Vector{T2},…)
?除非代码中的其他地方存在类型不稳定性,否则不会有任何性能开销。或者,考虑到
FiniteMixtureModel
的内容,是否需要进行错误检查以确保
xx
的类型是适当的?如果是这样的话,也许您可以使用
T1
T2
明确地将其作为函数的第一行来实现?@ColinTBowers您可以再详细说明一下吗。我不熟悉这个概念。那么我必须编写多个函数吗?对于任何参数化函数,例如
f1{T1,T2,…}(x1::T1,x2::T2,…)
,在运行时为调用函数的每一组特定输入类型预编译一个特定的(有效的)方法。这个预编译的有效方法随后将用于具有相同输入类型的任何后续调用。所有这些都是在“幕后”发生的,所以只要你的代码是正确的,你就可以像我一样定义函数,朱莉娅会处理剩下的事情。你只需要写一个版本。顺便说一句,我还是不太喜欢你构建类型的方式。正如我们所讨论的,您的字段
K
似乎是多余的。@ColinTBowers,您是对的。K在FiniteMixtureModel中是多余的,但在我计划开发的进一步模型中(在了解Julia之后),我需要它。所以这更像是一个一致性的问题。我可能遗漏了一些东西,但是为什么你不能只使用
函数gibbs_sampler{T1,T2}(fmm::FiniteMixtureModel{T1},xx::Vector{T2},…)
?除非代码中的其他地方存在类型不稳定性,否则不会有任何性能开销。或者,考虑到
FiniteMixtureModel
的内容,是否需要进行错误检查以确保
xx
的类型是适当的?如果是这样的话,也许您可以使用
T1
T2
明确地将其作为函数的第一行来实现?@ColinTBowers您可以再详细说明一下吗。我不熟悉这个概念。那么我必须编写多个函数吗?对于任何参数化函数,例如
f1{T1,T2,…}(x1::T1,x2::T2,…)
,在运行时为调用函数的每一组特定输入类型预编译一个特定的(有效的)方法。这个预编译的有效方法随后将用于具有相同输入类型的任何后续调用。所有这些都是在“幕后”发生的,所以只要你的代码是正确的,你就可以像我一样定义函数,朱莉娅会处理剩下的事情。你只需要写一个版本。顺便说一句,我还是不太喜欢你构建类型的方式。正如我们所讨论的,您的字段
K
似乎是多余的。@ColinTBowers,您是对的。K在FiniteMixtureModel中是多余的,但在我计划开发的进一步模型中(在了解Julia之后),我需要它。所以这更像是一个一致性的问题。事实上,
typeof(xx