Julia 具有指定分布的随机数据的类型不稳定性

Julia 具有指定分布的随机数据的类型不稳定性,julia,Julia,我想从带有噪声(Y=X*w+e)的线性模型中生成数据,在这里我可以指定输入向量X和标量噪声e的分布。为此,我指定以下结构 using Distributions struct NoisyLinearDataGenerator x_dist::ContinuousMultivariateDistribution noise_dist::ContinuousUnivariateDistribution weights::Vector{Float64} end 以及从中生成

我想从带有噪声(Y=X*w+e)的线性模型中生成数据,在这里我可以指定输入向量X和标量噪声e的分布。为此,我指定以下结构

using Distributions

struct NoisyLinearDataGenerator
    x_dist::ContinuousMultivariateDistribution
    noise_dist::ContinuousUnivariateDistribution
    weights::Vector{Float64}
end
以及从中生成N个点的函数:

function generate(nl::NoisyLinearDataGenerator, N)
    x = rand(nl.x_dist, N)'
    e = rand(nl.noise_dist, N)
    return x, x*nl.weights + e
end
这似乎是工作,但不稳定的类型,因为

nl = NoisyLinearDataGenerator(MvNormal(5, 1.0), Normal(), ones(5))

@code_warntype generate(nl,1)
屈服

Variables
  #self#::Core.Compiler.Const(generate, false)
  nl::NoisyLinearDataGenerator
  N::Int64
  x::Any
  e::Any

Body::Tuple{Any,Any}
1 ─ %1  = Base.getproperty(nl, :x_dist)::Distribution{Multivariate,Continuous}
│   %2  = Main.rand(%1, N)::Any
│         (x = Base.adjoint(%2))
│   %4  = Base.getproperty(nl, :noise_dist)::Distribution{Univariate,Continuous}
│         (e = Main.rand(%4, N))
│   %6  = x::Any
│   %7  = x::Any
│   %8  = Base.getproperty(nl, :weights)::Array{Float64,1}
│   %9  = (%7 * %8)::Any
│   %10 = (%9 + e)::Any
│   %11 = Core.tuple(%6, %10)::Tuple{Any,Any}
└──       return %11

我不知道为什么会这样,因为我希望通过使用
continuousmultivariateddistribution
continuousunivariateddistribution
来指定采样数据的类型


什么导致了这里的类型不稳定?类型稳定的实现应该是什么样子?

问题是
连续多变量分布
连续单变量分布
都是抽象类型。虽然您的统计知识告诉您,它们可能应该返回
Float64
,但无法保证在语言级别上有人不会实现返回其他对象的
连续单变量分布。因此,编译器无法知道所有
continuousunivariateddistribution
生成任何特定类型

例如,我可能会写:

struct BadDistribution <: ContinuousUnivariateDistribution end
Base.rand(::BadDistribution, ::Integer) = nothing
这里,
nl
的类型是
noiselyineardatagenerator{MvNormal{Float64,PDMats.ScalMat{Float64},fillarray.zero{Float64,1,Tuple{Base.OneTo{Int64}}},Normal{Float64}
(是的,我知道,读起来很糟糕),但它的类型包含编译器完全预测
generate
的输出类型所需的所有信息

using Distributions

struct NoisyLinearDataGenerator{X,N}
    x_dist::X
    noise_dist::N
    weights::Vector{Float64}

    function NoisyLinearDataGenerator{X,N}(x::X, n::N, w::Vector{Float64}) where {
                                    X <: ContinuousMultivariateDistribution,
                                    N <: ContinuousUnivariateDistribution}
        return new{X,N}(x,n,w)
    end
end

function NoisyLinearDataGenerator(x::X, n::N, w::Vector{Float64}) where {
                                X <: ContinuousMultivariateDistribution,
                                N <: ContinuousUnivariateDistribution}
    return NoisyLinearDataGenerator{X,N}(x,n,w)
end

function generate(nl::NoisyLinearDataGenerator, N)
    x = rand(nl.x_dist, N)'
    e = rand(nl.noise_dist, N)
    return x, x*nl.weights + e
end
nl = NoisyLinearDataGenerator(MvNormal(5, 1.0), Normal(), ones(5))