Type instability when evaluating prior distributions


#1

When looking at the @code_warntype output of the following function

using Distributions
const priors = [ Normal(0, 1), Beta(2, 5)]
const pars = [2.0, 0.9]

function prioreval_test(priors, pars::Vector{Float64})

    if all(insupport.(priors, pars))
        log_priorval = sum(logpdf.(priors, pars))
        alarm = false
    else
        log_priorval = -Inf
        alarm = true
    end

    return log_priorval, alarm
end

@code_warntype prioreval_test(priors, pars)

I find that it is not type stable

Body::Tuple{Any,Bool}
3  1 ── %1   = (Base.arraysize)(priors, 1)::Int64                                                                              β”‚β•»β•·β•·β•·β•·β•·         materialize
   β”‚    %2   = (Base.slt_int)(%1, 0)::Bool                                                                                     β”‚β”‚β•»β•·β•·β•·           instantiate
   β”‚    %3   = (Base.ifelse)(%2, 0, %1)::Int64                                                                                 │││┃││││││        combine_axes
   β”‚    %4   = %new(Base.OneTo{Int64}, %3)::Base.OneTo{Int64}                                                                  ││││┃││││          broadcast_axes
   β”‚    %5   = (Base.arraysize)(pars, 1)::Int64                                                                                β”‚β”‚β”‚β”‚β”‚β•»β•·β•·            broadcast_axes
   β”‚    %6   = (Base.slt_int)(%5, 0)::Bool                                                                                     β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·           axes
   β”‚    %7   = (Base.ifelse)(%6, 0, %5)::Int64                                                                                 │││││││┃│││           map
   β”‚    %8   = %new(Base.OneTo{Int64}, %7)::Base.OneTo{Int64}                                                                  ││││││││┃│             Type
   β”‚    %9   = (%7 === %3)::Bool                                                                                               β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·β•·          _bcs
   β”‚    %10  = (Base.and_int)(true, %9)::Bool                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚β•»              _bcs1
   └───        goto #3 if not %10                                                                                              │││││││┃              _bcsm
   2 ──        goto #4                                                                                                         β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   3 ── %13  = (%3 === 1)::Bool                                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              ==
   └───        goto #4                                                                                                         β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   4 ┄─ %15  = Ο† (#2 => %10, #3 => %13)::Bool                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   └───        goto #6 if not %15                                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   5 ──        goto #12                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   6 ── %18  = (%3 === %7)::Bool                                                                                               β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·             ==
   β”‚    %19  = (Base.and_int)(true, %18)::Bool                                                                                 β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              &
   └───        goto #8 if not %19                                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   7 ──        goto #9                                                                                                         β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   8 ── %22  = (%7 === 1)::Bool                                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              ==
   └───        goto #9                                                                                                         β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   9 ┄─ %24  = Ο† (#7 => %19, #8 => %22)::Bool                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   └───        goto #11 if not %24                                                                                             β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   10 ─        goto #12                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   11 ─ %27  = %new(Base.DimensionMismatch, "arrays could not be broadcast to a common size")::DimensionMismatch               β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              Type
   β”‚           (Base.Broadcast.throw)(%27)                                                                                     β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   └───        $(Expr(:unreachable))                                                                                           β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   12 β”„ %30  = Ο† (#5 => %7, #10 => %3)::Int64                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚         
   β”‚    %31  = Ο† (#5 => %7, #10 => %3)::Int64                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚         
   β”‚    %32  = Ο† (#5 => %7, #10 => %3)::Int64                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚         
   β”‚    %33  = Ο† (#5 => %7, #10 => %3)::Int64                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚         
   β”‚    %34  = Ο† (#5 => %8, #10 => %4)::Base.OneTo{Int64}                                                                      β”‚β”‚β”‚β”‚β”‚β”‚         
   β”‚    %35  = (Core.tuple)(%34)::Tuple{Base.OneTo{Int64}}                                                                     β”‚β”‚β”‚β”‚β”‚β”‚         
   └───        goto #13                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚         
   13 ─        goto #14                                                                                                        β”‚β”‚β”‚β”‚β”‚          
   14 ─        goto #15                                                                                                        β”‚β”‚β”‚β”‚           
   15 ─        goto #16                                                                                                        β”‚β”‚β•»              instantiate
   16 ─ %40  = (Base.arraysize)(priors, 1)::Int64                                                                              β”‚β”‚β”‚β•»β•·β•·β•·β•·β•·β•·β•·       preprocess
   β”‚    %41  = (Base.slt_int)(%40, 0)::Bool                                                                                    β”‚β”‚β”‚β”‚β•»β•·β•·β•·           preprocess_args
   β”‚    %42  = (Base.ifelse)(%41, 0, %40)::Int64                                                                               │││││┃││││││││      preprocess
   β”‚    %43  = (%42 === 1)::Bool                                                                                               β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·            extrude
   β”‚    %44  = (Base.not_int)(%43)::Bool                                                                                       β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              newindexer
   β”‚    %45  = (Core.tuple)(%44)::Tuple{Bool}                                                                                  ││││││││┃│             shapeindexer
   β”‚    %46  = (Core.tuple)(1)::Tuple{Int64}                                                                                   │││││││││┃              _newindexer
   β”‚    %47  = %new(Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}}, priors, %45, %46)::Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}}
   β”‚    %48  = (Base.arraysize)(pars, 1)::Int64                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·β•·β•·         preprocess
   β”‚    %49  = (Base.slt_int)(%48, 0)::Bool                                                                                    β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·           extrude
   β”‚    %50  = (Base.ifelse)(%49, 0, %48)::Int64                                                                               ││││││││┃││││││        newindexer
   β”‚    %51  = (%50 === 1)::Bool                                                                                               β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·            shapeindexer
   β”‚    %52  = (Base.not_int)(%51)::Bool                                                                                       β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              _newindexer
   β”‚    %53  = (Core.tuple)(%52)::Tuple{Bool}                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚    
   β”‚    %54  = (Core.tuple)(1)::Tuple{Int64}                                                                                   β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚    
   β”‚    %55  = %new(Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}, pars, %53, %54)::Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}
   β”‚    %56  = (Core.tuple)(%47, %55)::Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}
   β”‚    %57  = %new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(insupport),Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}}, Distributions.insupport, %56, %35)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(insupport),Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}}
   β”‚    %58  = (Base.slt_int)(%30, 1)::Bool                                                                                    β”‚β”‚β”‚β•»β•·β•·β•·           iterate
   └───        goto #18 if not %58                                                                                             β”‚β”‚β”‚β”‚           
   17 ─        goto #19                                                                                                        β”‚β”‚β”‚β”‚           
   18 ─        goto #19                                                                                                        β”‚β”‚β”‚β”‚           
   19 β”„ %62  = Ο† (#17 => true, #18 => false)::Bool                                                                             β”‚β”‚β”‚            
   β”‚    %63  = Ο† (#18 => 1)::Int64                                                                                             β”‚β”‚β”‚            
   β”‚    %64  = Ο† (#18 => 1)::Int64                                                                                             β”‚β”‚β”‚            
   └───        goto #21 if not %62                                                                                             β”‚β”‚β”‚            
   20 ─ %66  = $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), :(:ccall), 2, Array{Any,1}, :(%31), :(%31)))::Array{Any,1}lar
   └───        goto #31                                                                                                        β”‚β”‚β”‚            
   21 ─        goto #26 if not false                                                                                           β”‚β”‚β”‚β•»              getindex
   22 ─ %69  = (Base.sle_int)(1, %63)::Bool                                                                                    β”‚β”‚β”‚β”‚β•»β•·β•·            checkbounds
   β”‚    %70  = (Base.sle_int)(%63, %32)::Bool                                                                                  │││││┃││            checkbounds_indices
   β”‚    %71  = (Base.and_int)(%69, %70)::Bool                                                                                  β”‚β”‚β”‚β”‚β”‚β”‚β•»              checkindex
   β”‚    %72  = (Base.and_int)(%71, true)::Bool                                                                                 β”‚β”‚β”‚β”‚β”‚β”‚β•»              &
   └───        goto #24 if not %72                                                                                             β”‚β”‚β”‚β”‚β”‚          
   23 ─        goto #25                                                                                                        β”‚β”‚β”‚β”‚β”‚          
   24 ─ %75  = Base.throw_boundserror::typeof(Base.throw_boundserror)                                                          β”‚β”‚β”‚β”‚β”‚          
   β”‚    %76  = (Core.tuple)(%63)::Tuple{Int64}                                                                                 β”‚β”‚β”‚β”‚β”‚          
   β”‚           invoke %75(%57::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(insupport),Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}}, %76::Tuple{Int64})
   └───        $(Expr(:unreachable))                                                                                           β”‚β”‚β”‚β”‚β”‚          
   25 β”„        nothing                                                                                                         β”‚              
   26 ─ %80  = (Base.Broadcast.ifelse)(%44, %63, 1)::Int64                                                                     β”‚β”‚β”‚β”‚β•»β•·β•·β•·           _broadcast_getindex
   β”‚    %81  = (Base.arrayref)(false, priors, %80)::Distribution{Univariate,Continuous}                                        β”‚β”‚β”‚β”‚β”‚β•»              _getindex
   β”‚    %82  = (Base.Broadcast.ifelse)(%52, %63, 1)::Int64                                                                     β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·             _getindex
   β”‚    %83  = (Base.arrayref)(false, pars, %82)::Float64                                                                      β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              _broadcast_getindex
   β”‚    %84  = (Distributions.insupport)(%81, %83)::Any                                                                        β”‚β”‚β”‚β”‚β”‚β•»              _broadcast_getindex_evalf
   └───        goto #27                                                                                                        β”‚β”‚β”‚β”‚           
   27 ─ %86  = (Base.Broadcast.typeof)(%84)::DataType                                                                          β”‚β”‚β•»              copy
   β”‚    %87  = (isa)(%86, Type{Bool})::Bool                                                                                    β”‚β”‚β”‚            
   └───        goto #29 if not %87                                                                                             β”‚β”‚β”‚            
   28 ─ %89  = invoke BitArray{1}($(QuoteNode(array initializer with undefined values))::UndefInitializer, %33::Int64)::BitArray{1}β•·β•·            similar
   └───        goto #30                                                                                                        β”‚β”‚β”‚            
   29 ─ %91  = (Base.Broadcast.similar)(%57, %86)::Any                                                                         β”‚β”‚β”‚            
   └───        goto #30                                                                                                        β”‚β”‚β”‚            
   30 β”„ %93  = Ο† (#28 => %89, #29 => %91)::Any                                                                                 β”‚β”‚β”‚            
   β”‚           (Base.setindex!)(%93, %84, %63)                                                                                 β”‚β”‚β”‚            
   β”‚    %95  = (Base.Broadcast.copyto_nonleaf!)(%93, %57, %34, %64, 1)::Any                                                    β”‚β”‚β”‚            
   └───        goto #31                                                                                                        β”‚β”‚β”‚            
   31 β”„ %97  = Ο† (#20 => %66, #30 => %95)::Any                                                                                 β”‚β”‚             
   └───        goto #32                                                                                                        β”‚β”‚             
   32 ─ %99  = (Main.all)(%97)::Any                                                                                            β”‚              
   └───        goto #65 if not %99                                                                                             β”‚              
4  33 ─ %101 = (Base.arraysize)(priors, 1)::Int64                                                                              β”‚β•»β•·β•·β•·β•·β•·         materialize
   β”‚    %102 = (Base.slt_int)(%101, 0)::Bool                                                                                   β”‚β”‚β•»β•·β•·β•·           instantiate
   β”‚    %103 = (Base.ifelse)(%102, 0, %101)::Int64                                                                             │││┃││││││        combine_axes
   β”‚    %104 = %new(Base.OneTo{Int64}, %103)::Base.OneTo{Int64}                                                                ││││┃││││          broadcast_axes
   β”‚    %105 = (Base.arraysize)(pars, 1)::Int64                                                                                β”‚β”‚β”‚β”‚β”‚β•»β•·β•·            broadcast_axes
   β”‚    %106 = (Base.slt_int)(%105, 0)::Bool                                                                                   β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·           axes
   β”‚    %107 = (Base.ifelse)(%106, 0, %105)::Int64                                                                             │││││││┃│││           map
   β”‚    %108 = %new(Base.OneTo{Int64}, %107)::Base.OneTo{Int64}                                                                ││││││││┃│             Type
   β”‚    %109 = (%107 === %103)::Bool                                                                                           β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·β•·          _bcs
   β”‚    %110 = (Base.and_int)(true, %109)::Bool                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β•»              _bcs1
   └───        goto #35 if not %110                                                                                            │││││││┃              _bcsm
   34 ─        goto #36                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   35 ─ %113 = (%103 === 1)::Bool                                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              ==
   └───        goto #36                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   36 β”„ %115 = Ο† (#34 => %110, #35 => %113)::Bool                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   └───        goto #38 if not %115                                                                                            β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   37 ─        goto #44                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   38 ─ %118 = (%103 === %107)::Bool                                                                                           β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·             ==
   β”‚    %119 = (Base.and_int)(true, %118)::Bool                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              &
   └───        goto #40 if not %119                                                                                            β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   39 ─        goto #41                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   40 ─ %122 = (%107 === 1)::Bool                                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              ==
   └───        goto #41                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚       
   41 β”„ %124 = Ο† (#39 => %119, #40 => %122)::Bool                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   └───        goto #43 if not %124                                                                                            β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   42 ─        goto #44                                                                                                        β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   43 ─ %127 = %new(Base.DimensionMismatch, "arrays could not be broadcast to a common size")::DimensionMismatch               β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              Type
   β”‚           (Base.Broadcast.throw)(%127)                                                                                    β”‚β”‚β”‚β”‚β”‚β”‚β”‚        
   └───        $(Expr(:unreachable))                                                                                           β”‚β”‚β”‚β”‚β”‚β”‚β”‚        

...

%new(Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}}, priors, %145, %146)::Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}}
   β”‚    %148 = (Base.arraysize)(pars, 1)::Int64                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·β•·β•·         preprocess
   β”‚    %149 = (Base.slt_int)(%148, 0)::Bool                                                                                   β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·β•·           extrude
   β”‚    %150 = (Base.ifelse)(%149, 0, %148)::Int64                                                                             ││││││││┃││││││        newindexer
   β”‚    %151 = (%150 === 1)::Bool                                                                                              β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·β•·            shapeindexer
   β”‚    %152 = (Base.not_int)(%151)::Bool                                                                                      β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              _newindexer
   β”‚    %153 = (Core.tuple)(%152)::Tuple{Bool}                                                                                 β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚    
   β”‚    %154 = (Core.tuple)(1)::Tuple{Int64}                                                                                   β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚β”‚    
   β”‚    %155 = %new(Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}, pars, %153, %154)::Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}
   β”‚    %156 = (Core.tuple)(%147, %155)::Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}
   β”‚    %157 = %new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(logpdf),Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}}, Distributions.logpdf, %156, %135)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(logpdf),Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}}
   β”‚    %158 = (Base.slt_int)(%130, 1)::Bool                                                                                   β”‚β”‚β”‚β•»β•·β•·β•·           iterate
   └───        goto #50 if not %158                                                                                            β”‚β”‚β”‚β”‚           
   49 ─        goto #51                                                                                                        β”‚β”‚β”‚β”‚           
   50 ─        goto #51                                                                                                        β”‚β”‚β”‚β”‚           
   51 β”„ %162 = Ο† (#49 => true, #50 => false)::Bool                                                                             β”‚β”‚β”‚            
   β”‚    %163 = Ο† (#50 => 1)::Int64                                                                                             β”‚β”‚β”‚            
   β”‚    %164 = Ο† (#50 => 1)::Int64                                                                                             β”‚β”‚β”‚            
   └───        goto #53 if not %162                                                                                            β”‚β”‚β”‚            
   52 ─ %166 = $(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), :(:ccall), 2, Array{Any,1}, :(%131), :(%131)))::Array{Any,1}r
   └───        goto #63                                                                                                        β”‚β”‚β”‚            
   53 ─        goto #58 if not false                                                                                           β”‚β”‚β”‚β•»              getindex
   54 ─ %169 = (Base.sle_int)(1, %163)::Bool                                                                                   β”‚β”‚β”‚β”‚β•»β•·β•·            checkbounds
   β”‚    %170 = (Base.sle_int)(%163, %132)::Bool                                                                                │││││┃││            checkbounds_indices
   β”‚    %171 = (Base.and_int)(%169, %170)::Bool                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β•»              checkindex
   β”‚    %172 = (Base.and_int)(%171, true)::Bool                                                                                β”‚β”‚β”‚β”‚β”‚β”‚β•»              &
   └───        goto #56 if not %172                                                                                            β”‚β”‚β”‚β”‚β”‚          
   55 ─        goto #57                                                                                                        β”‚β”‚β”‚β”‚β”‚          
   56 ─ %175 = Base.throw_boundserror::typeof(Base.throw_boundserror)                                                          β”‚β”‚β”‚β”‚β”‚          
   β”‚    %176 = (Core.tuple)(%163)::Tuple{Int64}                                                                                β”‚β”‚β”‚β”‚β”‚          
   β”‚           invoke %175(%157::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(logpdf),Tuple{Base.Broadcast.Extruded{Array{Distribution{Univariate,Continuous},1},Tuple{Bool},Tuple{Int64}},Base.Broadcast.Extruded{Array{Float64,1},Tuple{Bool},Tuple{Int64}}}}, %176::Tuple{Int64})
   └───        $(Expr(:unreachable))                                                                                           β”‚β”‚β”‚β”‚β”‚          
   57 β”„        nothing                                                                                                         β”‚              
   58 ─ %180 = (Base.Broadcast.ifelse)(%144, %163, 1)::Int64                                                                   β”‚β”‚β”‚β”‚β•»β•·β•·β•·           _broadcast_getindex
   β”‚    %181 = (Base.arrayref)(false, priors, %180)::Distribution{Univariate,Continuous}                                       β”‚β”‚β”‚β”‚β”‚β•»              _getindex
   β”‚    %182 = (Base.Broadcast.ifelse)(%152, %163, 1)::Int64                                                                   β”‚β”‚β”‚β”‚β”‚β”‚β•»β•·             _getindex
   β”‚    %183 = (Base.arrayref)(false, pars, %182)::Float64                                                                     β”‚β”‚β”‚β”‚β”‚β”‚β”‚β•»              _broadcast_getindex
   β”‚    %184 = (Distributions.logpdf)(%181, %183)::Any                                                                         β”‚β”‚β”‚β”‚β”‚β•»              _broadcast_getindex_evalf
   └───        goto #59                                                                                                        β”‚β”‚β”‚β”‚           
   59 ─ %186 = (Base.Broadcast.typeof)(%184)::DataType                                                                         β”‚β”‚β•»              copy
   β”‚    %187 = (isa)(%186, Type{Bool})::Bool                                                                                   β”‚β”‚β”‚            
   └───        goto #61 if not %187                                                                                            β”‚β”‚β”‚            
   60 ─ %189 = invoke BitArray{1}($(QuoteNode(array initializer with undefined values))::UndefInitializer, %133::Int64)::BitArray{1}β•·            similar
   └───        goto #62                                                                                                        β”‚β”‚β”‚            
   61 ─ %191 = (Base.Broadcast.similar)(%157, %186)::Any                                                                       β”‚β”‚β”‚            
   └───        goto #62                                                                                                        β”‚β”‚β”‚            
   62 β”„ %193 = Ο† (#60 => %189, #61 => %191)::Any                                                                               β”‚β”‚β”‚            
   β”‚           (Base.setindex!)(%193, %184, %163)                                                                              β”‚β”‚β”‚            
   β”‚    %195 = (Base.Broadcast.copyto_nonleaf!)(%193, %157, %134, %164, 1)::Any                                                β”‚β”‚β”‚            
   └───        goto #63                                                                                                        β”‚β”‚β”‚            
   63 β”„ %197 = Ο† (#52 => %166, #62 => %195)::Any                                                                               β”‚β”‚             
   └───        goto #64                                                                                                        β”‚β”‚             
   64 ─ %199 = (Main.sum)(%197)::Any                                                                                           β”‚              
5  └───        goto #66                                                                                                        β”‚              
   65 ─        nothing                                                                                                         β”‚              
11 66 β”„ %202 = Ο† (#64 => %199, #65 => -Inf)::Any                                                                               β”‚              
   β”‚    %203 = Ο† (#64 => false, #65 => true)::Bool                                                                             β”‚              
   β”‚    %204 = (Core.tuple)(%202, %203)::Tuple{Any,Bool}                                                                       β”‚              
   └───        return %204  

I can force the output to Float64 by setting the last line to return log_priorval::Float64, alarm but I would like to understand where the type instability is coming from. It has to be the if/else statement but I don’t see why as typeof(Inf)is also Float64.

Thanks for your help.


#2

Since priors is a vector of heterogeneous elements (Normal and Beta), it does not have a concrete element type. The quickest fix is probably using tuples, and then I would do the same for pars. Eg

using Distributions
const priors = (Normal(0, 1), Beta(2, 5))
const pars = (2.0, 0.9)

function prioreval_test(priors, pars)
    if all(insupport.(priors, pars))
        log_priorval = sum(logpdf.(priors, pars))
        alarm = false
    else
        log_priorval = -Inf
        alarm = true
    end

    return log_priorval, alarm
end

@code_warntype prioreval_test(priors, pars)

That said, I would recommend you use NamedTuples for parameters, which can avoid order mixups.


#3

also, note that outside the support, you get -Inf automatically for the logpdf, eg

julia> logpdf(Beta(0.1, 0.7), -9)
-Inf

so testing for it separately may not be necessary.


#4

Thanks Tamas, that’s very helpful. Just two quick follow-ups so that I understand this better.

  1. (a) Why does it matter for type stability that the priors vector contains two different distributions? The outcome of sum(logpdf.()) will always be a Float64 scalar. (b) I tried using a tuple for priors and a vector for pars but that has the same issues as two vectors. Is that just the interplay between the two that then screws up type inference?

  2. I can easily construct the priors as a tuple (I use Flatten.jl and that allows to flatten the struct into tuple or vector). But the parameter vector comes directly from the optimizer (using Optim.jl). If I understand it correctly, Optim only outputs (and accepts) arrays. Of course I could transform the vector into a tuple but is there a smarter way?

Again, thanks for your help.


#5
using Distributions
const priors = [ Normal(0, 1), Beta(2, 5)]
const pars = [2.0, 0.9]

struct MyDegenerateDistribution <: Distributions.ContinuousUnivariateDistribution end
Distributions.logpdf(::MyDegenerateDistribution, ::Float64) = big(42)
Distributions.insupport(::MyDegenerateDistribution, ::Real) = true

push!(priors, MyDegenerateDistribution())
push!(pars, Inf)

Then,

julia> isa.(priors, Distributions.ContinuousUnivariateDistribution)
3-element BitArray{1}:
 true
 true
 true

julia> prioreval_test(priors, pars)
(33.1665579608234732944538336596451699733734130859375, false)

julia> typeof(ans)
Tuple{BigFloat,Bool}

Our answer is a BigFloat!
Or,

julia> using StaticArrays

julia> Distributions.logpdf(::MyDegenerateDistribution, ::Float64) = @SMatrix randn(3,3)

julia> prioreval_test(priors, pars)
([-9.15028 -8.84753 -7.32728; -9.23861 -8.53093 -9.21451; -9.76463 -8.44686 -6.88402], false)

Even worse, sum(logpdf.()) doesn’t have to be defined:

julia> Distributions.logpdf(::MyDegenerateDistribution, ::Float64) = "I don't play by the rules!"

julia> prioreval_test(priors, pars)
ERROR: MethodError: no method matching +(::Float64, ::String)
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:521
  +(::Float64, ::Float64) at float.jl:395
  +(::AbstractFloat, ::Bool) at bool.jl:114
  ...
Stacktrace:
 [1] add_sum(::Float64, ::String) at ./reduce.jl:21
 [2] _mapreduce(::typeof(identity), ::typeof(Base.add_sum), ::IndexLinear, ::Array{Any,1}) at ./reduce.jl:316
 [3] _mapreduce_dim at ./reducedim.jl:308 [inlined]
 [4] #mapreduce#549 at ./reducedim.jl:304 [inlined]
 [5] mapreduce at ./reducedim.jl:304 [inlined]
 [6] _sum at ./reducedim.jl:653 [inlined]
 [7] _sum at ./reducedim.jl:652 [inlined]
 [8] #sum#551 at ./reducedim.jl:648 [inlined]
 [9] sum(::Array{Any,1}) at ./reducedim.jl:648
 [10] prioreval_test(::Array{Distribution{Univariate,Continuous},1}, ::Array{Float64,1}) at ./REPL[21]:4
 [11] top-level scope at none:0

While it is hard to think of a good reason for anyone to do that, the compiler’s job is producing valid code. Because it is possible to do this, the compiler needs to generate code able to handle it.

In Tamas_Papps version, with the tuples, the function can specialize one each individual types. Receiving just the Beta and Normal distribution, the compiler is guaranteed silliness like these examples aren’t possible.


#6

a) Vectors are fast if they contain one type of data, otherwise data is boxed as ANY at some point which requires a lot more native code to handle (although small Union vectors are also pretty fast these days).
b) Good to see someone using Flatten.jl for this! Tuple is the default output for this very reason - the vector is just splatted from the tuple for convenience. I should put a warning somewhere in the readme about type stability. For the pars it seems strange that a vector creates type instability, as it’s all Float64. But it’s probably something to do with how broadcast is compiled when given a tuple and a vector. My answer to this kind of type instability is often to use recursion instead of for loops or broadcast. But you could just splat the vector to a tuple here.

As for Optim only working with Vectors it’s a broader problem I would also like to see addressed more often - accepting tuples instead of vectors for parameter lists. This would mean lists of prior distributions and parameters with different Unitful units could be type stable.


#7

I wrote TransformVariables precisely for this. It can also transform an unconstrained real to a constrained subset, eg

using TransformVariables
t = as((x = asℝ, a = as𝕀))
dimension(t)
t([0.1, 0.2])

#8

Thanks everyone! This helped me a lot in understanding the issue.