Turing error with truncated distribution

Hi,

I’m trying to use a truncated distribution within an @model block of the form data ~ truncated(D(parameter), l, u)). This doesn’t seem to work :frowning: . Here’s the full example:

@model function decay_estimator_trunc(decays::Array{Float64})
    λ ~ Exponential(100)
    for i in 1:length(decays)
        decays[i] ~ truncated(Exponential(λ), 0, 20)
    end
end;

It works correctly without the truncated call. Here’s the stacktrace:

Cannot determine ordering of Dual tags Nothing and ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64}

Stacktrace:
 [1] ≺(::Type{T} where T, ::Type{T} where T) at /Users/brad/.julia/packages/ForwardDiff/qTmqf/src/dual.jl:49
 [2] - at /Users/brad/.julia/packages/ForwardDiff/qTmqf/src/dual.jl:135 [inlined]
 [3] _logpdf at /Users/brad/.julia/packages/Distributions/HjzA0/src/truncate.jl:117 [inlined]
 [4] logpdf at /Users/brad/.julia/packages/Distributions/HjzA0/src/truncate.jl:135 [inlined]
 [5] loglikelihood at /Users/brad/.julia/packages/Distributions/HjzA0/src/univariates.jl:535 [inlined]
 [6] observe at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/context_implementations.jl:152 [inlined]
 [7] observe at /Users/brad/.julia/packages/Turing/IVoZH/src/inference/hmc.jl:561 [inlined]
 [8] _tilde at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/context_implementations.jl:109 [inlined]
 [9] tilde at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/context_implementations.jl:67 [inlined]
 [10] tilde_observe(::DynamicPPL.DefaultContext, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}, ::Truncated{Exponential{ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1}},Continuous,ForwardDiff.Dual{Nothing,Float64,1}}, ::Float64, ::DynamicPPL.VarName{:decays,Tuple{Tuple{Int64}}}, ::Tuple{Tuple{Int64}}, ::DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1},1},Array{Set{DynamicPPL.Selector},1}}}},ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1}}) at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/context_implementations.jl:89
 [11] #47 at ./In[86]:3 [inlined]
 [12] (::var"#47#48")(::Random._GLOBAL_RNG, ::DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}, ::DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1},1},Array{Set{DynamicPPL.Selector},1}}}},ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1}}, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}, ::DynamicPPL.DefaultContext, ::Array{Float64,1}) at ./none:0
 [13] macro expansion at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/model.jl:0 [inlined]
 [14] _evaluate at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/model.jl:154 [inlined]
 [15] evaluate_threadunsafe at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/model.jl:127 [inlined]
 [16] Model at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/model.jl:92 [inlined]
 [17] Model at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/model.jl:98 [inlined]
 [18] f at /Users/brad/.julia/packages/Turing/IVoZH/src/core/ad.jl:111 [inlined]
 [19] vector_mode_dual_eval at /Users/brad/.julia/packages/ForwardDiff/qTmqf/src/apiutils.jl:37 [inlined]
 [20] vector_mode_gradient!(::Array{Float64,1}, ::Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext}, ::Array{Float64,1}, ::ForwardDiff.GradientConfig{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1,Array{ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1},1}}) at /Users/brad/.julia/packages/ForwardDiff/qTmqf/src/gradient.jl:105
 [21] gradient! at /Users/brad/.julia/packages/ForwardDiff/qTmqf/src/gradient.jl:37 [inlined]
 [22] gradient!(::Array{Float64,1}, ::Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext}, ::Array{Float64,1}, ::ForwardDiff.GradientConfig{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1,Array{ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#1"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.DefaultContext},Float64},Float64,1},1}}) at /Users/brad/.julia/packages/ForwardDiff/qTmqf/src/gradient.jl:35
 [23] gradient_logp(::Turing.Core.ForwardDiffAD{40}, ::Array{Float64,1}, ::DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64}, ::DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}, ::DynamicPPL.DefaultContext) at /Users/brad/.julia/packages/Turing/IVoZH/src/core/ad.jl:121
 [24] gradient_logp at /Users/brad/.julia/packages/Turing/IVoZH/src/core/ad.jl:83 [inlined] (repeats 2 times)
 [25] ∂logπ∂θ at /Users/brad/.julia/packages/Turing/IVoZH/src/inference/hmc.jl:477 [inlined]
 [26] ∂H∂θ at /Users/brad/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:31 [inlined]
 [27] phasepoint(::AdvancedHMC.Hamiltonian{AdvancedHMC.UnitEuclideanMetric{Float64,Tuple{Int64}},Turing.Inference.var"#logπ#52"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}},Turing.Inference.var"#∂logπ∂θ#51"{DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}},DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}}}, ::Array{Float64,1}, ::Array{Float64,1}) at /Users/brad/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:69
 [28] phasepoint at /Users/brad/.julia/packages/AdvancedHMC/MIxdK/src/hamiltonian.jl:139 [inlined]
 [29] initialstep(::Random._GLOBAL_RNG, ::DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}, ::DynamicPPL.VarInfo{NamedTuple{(:λ,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:λ,Tuple{}},Int64},Array{Exponential{Float64},1},Array{DynamicPPL.VarName{:λ,Tuple{}},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64}; init_params::Nothing, nadapts::Int64, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:drop_warmup,),Tuple{Bool}}}) at /Users/brad/.julia/packages/Turing/IVoZH/src/inference/hmc.jl:174
 [30] step(::Random._GLOBAL_RNG, ::DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}; resume_from::Nothing, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:drop_warmup,),Tuple{Bool}}}) at /Users/brad/.julia/packages/DynamicPPL/K7t3L/src/sampler.jl:83
 [31] macro expansion at /Users/brad/.julia/packages/AbstractMCMC/Nw3Wn/src/sample.jl:78 [inlined]
 [32] macro expansion at /Users/brad/.julia/packages/AbstractMCMC/Nw3Wn/src/logging.jl:15 [inlined]
 [33] mcmcsample(::Random._GLOBAL_RNG, ::DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}, ::Int64; progress::Bool, progressname::String, callback::Nothing, discard_initial::Int64, thinning::Int64, chain_type::Type{T} where T, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:drop_warmup,),Tuple{Bool}}}) at /Users/brad/.julia/packages/AbstractMCMC/Nw3Wn/src/sample.jl:76
 [34] sample(::Random._GLOBAL_RNG, ::DynamicPPL.Model{var"#47#48",(:decays,),(),(),Tuple{Array{Float64,1}},Tuple{}}, ::DynamicPPL.Sampler{HMC{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.UnitEuclideanMetric}}, ::Int64; chain_type::Type{T} where T, resume_from::Nothing, progress::Bool, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:drop_warmup,),Tuple{Bool}}}) at /Users/brad/.julia/packages/Turing/IVoZH/src/inference/Inference.jl:156
 [35] #sample#2 at /Users/brad/.julia/packages/Turing/IVoZH/src/inference/Inference.jl:142 [inlined]
 [36] #sample#1 at /Users/brad/.julia/packages/Turing/IVoZH/src/inference/Inference.jl:132 [inlined]
 [37] top-level scope at In[87]:1
 [38] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091

Thanks!
Brad

For anyone coming to this in the future, I found the answer and it’s included in this post. The TLDR;

@model function decay_estimator_trunc(decays::Array{Float64})
    λ ~ Uniform(0, 50)
    T = typeof(λ)
    for i in 1:length(decays)
        decays[i] ~ truncated(Exponential(λ), T(0.0), T(20.0)) #wtf
    end
end;

You might be wondering what’s the story with T. Good question! My understanding is that there’s an issue in Distributions.jl where the truncated function ends up mixing up simple Number types (0.0 and 20.0 in this case) with Dual types (the types that track derivative information for auto-differentiation). There’s a discussion on this open issue. Anyway, by explicitly casting the Number values as T (which is some Dual type we peeked from λ here) we can make it work!

4 Likes