Calling Distributions functions with keywords

Hi guys,

I want to create a (mutable) struct that lets me call functions from the Distributions module in a very generic way, an example container for this looks like this:

using Distributions, Parameters
import DataStructures: OrderedDict
##################################################################

mutable struct ParameterInfo{E,F}
    distr   :: Distribution{E,F}
    param   ::  #?? Question: Best type for this field?
end

#Would like to do this
function get_logpdf(info::ParameterInfo, x)
    @unpack distr, param = info
    return logpdf( distr(param ...), x )
end
  1. I need to update the param field over time. i) So I assume there is no way to make NamedTuples work with it?
  2. Ideally, distr(param ...) or distr(; param ...) recognizes the keywords, i.e., I will get the same distribution no matter the ordering in param:

Normal(μ=1., σ=2.) or Normal(; μ=1., σ=2.)
Normal(σ=2., μ=1.) or Normal(; σ=2., μ=1.)

ii) Unfortunately, it seems like keywords are not supported in the Distributions module? I read some articles about progress wrt to this questions, but I could not make it work with my examples.

In that case, I would need something that preservers the order of the input, even though it seems a lot safer to me if I could work with keywords. OrderedDicts let me change param fields and preserve ordering, so a possible solution would be:

###################### Use a OrderedDict
param3 = OrderedDict(:μ => 12.3, :σ => 1., :α => 2.) #Does NOT order
param3[:μ] =  123456 #and is mutable
#But I cannot call Distributions easily with it
param3 = Dict(:μ => 12.3, :σ => 1. )
Normal(param3 ...) #not working
Normal(; param3 ...) #not working

Normal( collect(values(param3) ) ... ) #working
#But does not take into account keywords
param3 = OrderedDict( :σ => 1., :μ => 12.3 ) #Switch ordering
Normal( collect(values(param3) ) ... ) #Normal{Float64}(μ=1.0, σ=12.3) -> wrong

iii) However, ordering still seems to not work in that case. Does someone know a way to work with keywords in that case, and the container of these is mutable and (ideally) preserves ordering?

It would be amazing if anyone knows a workaround for this!

Best regards,

You would need to implement a function that maps named parameters to arguments for the constructor.

That said, it is very likely that you are doing something unnecessary, and it may be possible to solve the actual problem in a much more idiomatic way — but you need to tell us what it is. (cf XY problem).

Thank you for your answer! This is part of a broader package that I use to solve specific state space models. They are all very niche (i.e., no closed form for the likelihood function\ inversions within the likelihood function \ etc…), so I decided to code the structure up myself (it was also fun).

This works for now, but I would like to generalize it a bit more and allow for arbitrary distributional forms, so I don’t need to manually add a new model structure and dispatch on all relevant functions if I have a new modelling idea.

Julia has lots of different StateSpace modules, but I have not come up with something that would suit my needs here. There is also your module DynamicHMC and Turing, which developed their own probabilistic DSL, but that is out of reach for me. I did not add the general problem question, because I think its just a too vague question, but in principle I just need to find something that allows me to call a inverse transform, transform and a likelihood function for any choice of such a struct:

mutable struct MyModel
    InitialDistribution :: #1) Vector{Distribution} or 2) a closure where I capture the current parameter values
    TransitionDistribution :: #1) Vector{Distribution} 2) or a closure where I capture the current parameter values
    ObservationDistribution :: #1) Vector{Distribution} 2) or a closure where I capture the current parameter values
    Prior :: ? # The tricky part where I try to take all parameter from the previous fields
end

The inversion usually comes from a vector of parameters, and not from the MyModel struct itself. Also parameter can be scalar, Vector or Matrix variate, and accounting for all that usually leaves me with longer and more code than desired, but there is not really something here where someone could help me.

Is there anything that precludes representing distributions with a the appropriate type from distributions? Eg Normal(1.0, 2.0) for a normal, etc. I am not sure I understand why they need to be constructed from interim representations with keywords.

DynamicHMC has no such thing by design (but Turing of course does).

Is there anything that precludes representing distributions with a the appropriate type from distributions? Eg Normal(1.0, 2.0) for a normal, etc. I am not sure I understand why they need to be constructed from interim representations with keywords

That is my current approach. It is working, but when transforming parameter from the model to a vector and back into the model I have to take care of lots of special cases (i.e., parameter may have scalar-, vector-, or matrixvariate form. I also need to store that information somewhere else). I have yet to come up with something better though.