What's in a FlexiChain?

A FlexiChain{T}, at its core, is a wrapper around a dictionary which maps keys to matrices of size (niters x nchains).

Let's start by loading an example FlexiChain.

using FlexiChainschain = 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                                                       │
╰──────────────────────────────────────────────────────────────────────────────╯

Keys: parameters and extras

Each key in a FlexiChain{T} can be either:

Each Parameter or Extra itself carries a name, which can be retrieved with FlexiChains.get_name.

using FlexiChains: get_name, Parametername = FlexiChains.get_name(FlexiChains.Parameter(@vn(mu)))name, typeof(name)
(mu, VarName{:mu, VarNames.Iden})

For a Parameter{T}, the name must be a T. For an Extra, the name must always be a Symbol, regardless of the parameter key type.

You can list all keys, all parameters, or all extras:

keys(chain)
KeySet for a OrderedCollections.OrderedDict{Union{FlexiChains.Extra, FlexiChains.Parameter{var"#s91"}} where var"#s91"<:VarName, Matrix} with 5 entries. Keys:
  Parameter(mu)
  Parameter(tau)
  Parameter(theta)
  Extra(:logjoint)
  Extra(:is_divergent)
FlexiChains.parameters(chain)
3-element Vector{VarName}:
 mu
 tau
 theta
FlexiChains.extras(chain)
2-element Vector{FlexiChains.Extra}:
 Extra(:logjoint)
 Extra(:is_divergent)

Values: matrices

Because each key maps to a different matrix, FlexiChains can store values of different types and sizes.

For example, mu is stored as Float64, and theta as a Vector{Float64}. Indexing into a chain returns an niters x nchains matrix of these samples:

chain[@vn(mu)]
┌ 10×2 DimArray{Float64, 2} Parameter(mu) ┐
├─────────────────────────────────────────┴─────────────── dims ┐
  ↓ iter Sampled{Int64} 101:110 ForwardOrdered Regular Points,
  → chain Sampled{Int64} 1:2 ForwardOrdered Regular Points
└───────────────────────────────────────────────────────────────┘
   ↓ →   1         2
 101    11.3517    4.78008
 102    11.3517    4.59214
 103    11.3517    5.68752
 104    11.3517    7.10065
   ⋮               
 107     1.30113   5.48149
 108     0.915619  6.2456
 109     0.284842  6.25491
 110     0.516548  1.47832
chain[:is_divergent]
┌ 10×2 DimArray{Bool, 2} Extra(:is_divergent) ┐
├─────────────────────────────────────────────┴─────────── dims ┐
  ↓ iter Sampled{Int64} 101:110 ForwardOrdered Regular Points,
  → chain Sampled{Int64} 1:2 ForwardOrdered Regular Points
└───────────────────────────────────────────────────────────────┘
   ↓ →  1  2
 101    0  0
 102    0  0
 103    0  0
 104    1  0
   ⋮       
 107    1  0
 108    0  0
 109    0  0
 110    0  0

In this introductory page we don't go into the details of indexing; there's one full page on that.

To obtain the number of iterations or chains, you can use FlexiChains.niters and FlexiChains.nchains:

FlexiChains.niters(chain), FlexiChains.nchains(chain)
(10, 2)

Alternatively, size(chain) returns (niters, nchains):

size(chain)
(10, 2)

Notice that there is no measure of the number of parameters. Unlike other chains packages, such as MCMCChains.jl, FlexiChains does not have a third 'parameter axis'. If you want to get such a number, you can use length(keys(chain)) or length(FlexiChains.parameters(chain)).