Storing vectorised and raw values

VarInfo contains only accumulators. Two accumulators record parameter values, in different representations:

  • Raw values (RawValueAccumulator) are model-space values, as the model body and logpdf see them. For x ~ Dirichlet(ones(3)), the raw value is [0.2, 0.3, 0.5].
  • Vector values (VectorValueAccumulator) hold one TransformedValue per tilde statement: that variable's value flattened to a vector, together with its transform. Linked, the same x becomes TransformedValue([-0.69, -0.51], DynamicLink()).

Both are VarNamedTuples keyed by variable name, not one vector for the whole model. internal_values_as_vector concatenates the vector values into the flat vector that samplers and LogDensityFunction use. Neither accumulator supplies inputs during evaluation.

Vectorised values

Vectorised values preserve stochastic-site boundaries, including sites whose linked dimension differs from their model-space dimension.

using DynamicPPL, Distributions
using Random: Xoshiro

@model function dirichlet()
    x = zeros(3)
    return x[1:3] ~ Dirichlet(ones(3))
end
model = dirichlet()
context = InitContext(Xoshiro(1), InitFromPrior(), LinkAll())
_, vi = evaluate!!(model, context, VarInfo(VectorValueAccumulator()))
vector_values = get_vector_values(vi)
keys(vector_values)
1-element Vector{VarName}:
 x[1:3]

The entry for x[1:3] is one block, even though a linked Dirichlet value has only two coordinates. See Array-like blocks.

internal_values_as_vector(vector_values)
2-element Vector{Float64}:
 -2.9126512303929775
  0.4834619651484865

The flat vector concatenates the per-statement vectors in key order. These values can initialise a LogDensityFunction, which derives from them the range of each variable within the flat vector and its transform. There is no separate value store in VarInfo.

Raw values

A RawValueAccumulator records untransformed values. It does not retain stochastic-site block boundaries: indexed sites are represented by their individual indices.

context = InitContext(Xoshiro(1), InitFromPrior(), UnlinkAll())
_, vi = evaluate!!(model, context, VarInfo(RawValueAccumulator(false)))
raw_values = get_raw_values(vi)
keys(raw_values)
3-element Vector{VarName}:
 x[1]
 x[2]
 x[3]

Raw values are used for chain construction. A whole variable such as x ~ Dirichlet(ones(3)) remains one value when the chain format supports it.

Reusing outputs as inputs

To pass outputs of one evaluation, such as parameter values, as inputs to the next, convert them explicitly outside evaluation; the context holds inputs and the VarInfo holds only outputs:

context = InitContext(Xoshiro(1), InitFromParams(raw_values, nothing), LinkAll())
retval, outputs = evaluate!!(model, context, VarInfo(VectorValueAccumulator()))
get_vector_values(outputs)
VarNamedTuple
└─ x => PartialArray size=(3,) data::Vector{DynamicPPL.VarNamedTuples.ArrayLikeBlock{TransformedValue{Vector{Float64}, DynamicLink}, Tuple{UnitRange{Int64}}, @NamedTuple{}, Tuple{Int64}}}
        ├─ (1,) => DynamicPPL.VarNamedTuples.ArrayLikeBlock{TransformedValue{Vector{Float64}, DynamicLink}, Tuple{UnitRange{Int64}}, @NamedTuple{}, Tuple{Int64}}(TransformedValue{Vector{Float64}, DynamicLink}([-2.9126512303929775, 0.4834619651484865], DynamicLink()), (1:3,), NamedTuple(), (3,))
        ├─ (2,) => DynamicPPL.VarNamedTuples.ArrayLikeBlock{TransformedValue{Vector{Float64}, DynamicLink}, Tuple{UnitRange{Int64}}, @NamedTuple{}, Tuple{Int64}}(TransformedValue{Vector{Float64}, DynamicLink}([-2.9126512303929775, 0.4834619651484865], DynamicLink()), (1:3,), NamedTuple(), (3,))
        └─ (3,) => DynamicPPL.VarNamedTuples.ArrayLikeBlock{TransformedValue{Vector{Float64}, DynamicLink}, Tuple{UnitRange{Int64}}, @NamedTuple{}, Tuple{Int64}}(TransformedValue{Vector{Float64}, DynamicLink}([-2.9126512303929775, 0.4834619651484865], DynamicLink()), (1:3,), NamedTuple(), (3,))

The context determines the new output transforms, independently of the input representation. InitFromParams(vector_values, nothing) also accepts vectorised inputs, including dynamically linked values. Dynamic transforms are reconstructed from each site's current distribution, so parameter-dependent supports remain correct.

The nothing fallback makes an absent parameter an error. To sample absent sites from their priors instead, pass InitFromParams(raw_values, InitFromPrior()).