MCMCChains.jl
You can convert FlexiChain objects to and from MCMCChains.Chains.
FlexiChain to MCMCChains
The conversion from FlexiChain to MCMCChains is much more straightforward. Since an MCMCChains.Chains object contains much less information than a FlexiChain, this is just a one-liner, with no real customisation available:
using FlexiChains, MCMCChainschain = FlexiChains.EXAMPLE_CHAIN╭─FlexiChain (10 iterations, 2 chains) ────────────────────────────────────────╮
│ ↓ iter = 101:110 │
│ → chain = 1:2 │
│ │
│ Parameters (3) ── VarName │
│ Float64 mu, tau │
│ Vector{Float64} theta (8,) │
│ │
│ Extras (2) │
│ Float64 logjoint │
│ Bool is_divergent │
╰──────────────────────────────────────────────────────────────────────────────╯mc = MCMCChains.Chains(chain)Chains MCMC chain (10×12×2 Array{Float64, 3}):
Iterations = 101:110
Number of chains = 2
Samples per chain = 10
parameters = mu, tau, theta[1], theta[2], theta[3], theta[4], theta[5], theta[6], theta[7], theta[8]
internals = logjoint, is_divergent
Use `describe(chains)` for summary statistics and quantiles.
MCMCChains to FlexiChain
Let's now explore how we can convert this object back into a FlexiChain, putting all the type and shape information back in.
The relevant function is FlexiChains.from_mcmcchains. If we naively call this we will get a FlexiChain{Symbol}, since that is the key type of MCMCChains:
FlexiChains.from_mcmcchains(mc)╭─FlexiChain (10 iterations, 2 chains) ────────────────────────────────────────╮
│ ↓ iter = [101 … 110] │
│ → chain = [1, 2] │
│ │
│ Parameters (10) ── Symbol │
│ Float64 mu, tau, theta[1], theta[2], theta[3], theta[4], theta[5] │
│ theta[6], theta[7], theta[8] │
│ │
│ Extras (2) │
│ Float64 logjoint, is_divergent │
╰──────────────────────────────────────────────────────────────────────────────╯Notice that we don't have the vector structure of the parameter theta, and instead have different scalar parameters theta[1] through theta[8]. Furthermore, the is_divergent extra key has been converted into a Float64.
This is a direct result of the fact that MCMCChains.Chains objects don't store any type information, and only store scalar parameters.
Let's tackle both of these separately. We can regain the structure of theta by specifying a set of keys as the second argument:
using FlexiChains: Parameter, Extra, @vnfc = FlexiChains.from_mcmcchains( mc, ( Parameter(@vn(mu)), Parameter(@vn(tau)), Parameter(@vn(theta)) => (8,), Extra(:logjoint), Extra(:is_divergent), ),)╭─FlexiChain (10 iterations, 2 chains) ────────────────────────────────────────╮
│ ↓ iter = [101 … 110] │
│ → chain = [1, 2] │
│ │
│ Parameters (3) ── VarName │
│ Float64 mu, tau │
│ Vector{Float64} theta (8,) │
│ │
│ Extras (2) │
│ Float64 logjoint, is_divergent │
╰──────────────────────────────────────────────────────────────────────────────╯By passing VarName parameters instead of Symbols, we can 'upconvert' this into a VNChain rather than a SymChain. Furthermore, by specifying the shape of theta as (8,), we can recover the vector structure of that parameter. In general array-valued parameters can be 'recovered' in this way, but more complicated structs cannot be.
The parameters provided as the second argument must add up to exactly the same number of columns in the original MCMCChains object, and must also be in the same order as they appear in the original object. The order of the parameters in an MCMCChains object is not always obvious, so be careful with this.
After that, we can also convert is_divergent back into a Boolean:
fc = FlexiChains.transform_values(fc, Extra(:is_divergent) => Bool)╭─FlexiChain (10 iterations, 2 chains) ────────────────────────────────────────╮
│ ↓ iter = [101 … 110] │
│ → chain = [1, 2] │
│ │
│ Parameters (3) ── VarName │
│ Float64 mu, tau │
│ Vector{Float64} theta (8,) │
│ │
│ Extras (2) │
│ Float64 logjoint │
│ Bool is_divergent │
╰──────────────────────────────────────────────────────────────────────────────╯Docstrings
FlexiChains.from_mcmcchains — Function
FlexiChains.from_mcmcchains(chains::MCMCChains.Chains, key_spec=nothing)Convert an MCMCChains.Chains object to a FlexiChain.
If key_spec is not provided, parameters in the :parameters section are stored as Parameter{Symbol} keys and all other sections (e.g. :internals) as Extra keys, giving a FlexiChain{Symbol}.
If key_spec is provided, it is passed directly to the FlexiChain from-array constructor. The key type of the resulting FlexiChain is inferred from key_spec. You can pass this argument if you want to override the parameter names stored in the MCMCChains.Chains object, or to group array-valued parameters together, for example.
Please see the FlexiChain constructor documentation for details on what key_spec is allowed.
Iteration indices, chain indices, and per-chain sampling times are inherited from the MCMCChains.Chains object. If the MCMCChains.Chains object contains a samplerstate field in its info NamedTuple, this is also preserved in the resulting FlexiChain.
MCMCChains.Chains — Method
MCMCChains.Chains(chain::FlexiChain)Convert a FlexiChain to an MCMCChains.Chains object.
Array-valued parameters are split up into their individual real-valued elements, much like the output that you get directly from sampling with Turing + MCMCChains.