AbstractPPL.ConcretizedSliceType
ConcretizedSlice(::Base.Slice)

An indexing object wrapping the range of a Base.Slice object representing the concrete indices a : indicates. Behaves the same, but prints differently, namely, still as :.

AbstractPPL.VarNameType
VarName(vn::VarName, optic)
VarName(vn::VarName, indexing::Tuple)

Return a copy of vn with a new index optic/indexing.

julia> VarName(@varname(x[1][2:3]), Accessors.IndexLens((2,)))
x[2]

julia> VarName(@varname(x[1][2:3]), ((2,),))
x[2]

julia> VarName(@varname(x[1][2:3]))
x
AbstractPPL.VarNameType
VarName{sym}(optic=identity)

A variable identifier for a symbol sym and optic optic.

The Julia variable in the model corresponding to sym can refer to a single value or to a hierarchical array structure of univariate, multivariate or matrix variables. The field lens stores the indices requires to access the random variable from the Julia variable indicated by sym as a tuple of tuples. Each element of the tuple thereby contains the indices of one optic operation.

VarNames can be manually constructed using the VarName{sym}(optic) constructor, or from an optic expression through the @varname convenience macro.

Examples

julia> vn = VarName{:x}(Accessors.IndexLens((Colon(), 1)) ⨟ Accessors.IndexLens((2, )))
x[:, 1][2]

julia> getoptic(vn)
(@o _[Colon(), 1][2])

julia> @varname x[:, 1][1+1]
x[:, 1][2]
Core.SymbolMethod
Symbol(vn::VarName)

Return a Symbol representation of the variable identifier VarName.

Examples

julia> Symbol(@varname(x[1][2:3]))
Symbol("x[1][2:3]")

julia> Symbol(@varname(x[1][:]))
Symbol("x[1][:]")
AbstractPPL.combine_indicesMethod
combine_indices(optic)

Return sequential indexing into a single Tuple of indices, e.g. x[:][1][2] becomes ((Colon(), ), (1, ), (2, )).

The result is compatible with subsumes_indices for Tuple input.

AbstractPPL.concretizeMethod
concretize(l, x)

Return l instantiated on x, i.e. any information related to the runtime shape of x is evaluated. This concerns begin, end, and : slices.

Basically, every index is converted to a concrete value using Base.to_index on x. However, : slices are only converted to ConcretizedSlice (as opposed to Base.Slice{Base.OneTo}), to keep the result close to the original indexing.

AbstractPPL.concretizeMethod
concretize(vn::VarName, x)

Return vn concretized on x, i.e. any information related to the runtime shape of x is evaluated. This concerns begin, end, and : slices.

Examples

julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], );

julia> getoptic(@varname(x.a[1:end, end][:], true)) # concrete=true required for @varname
(@o _.a[1:3, 2][:])

julia> y = zeros(10, 10);

julia> @varname(y[:], true)
y[:]

julia> # The underlying value is conretized, though:
       AbstractPPL.getoptic(AbstractPPL.concretize(@varname(y[:]), y)).indices[1]
ConcretizedSlice(Base.OneTo(100))
AbstractPPL.conditionFunction
condition(model, observations)

Condition the generative model model on some observed data, creating a new model of the (possibly unnormalized) posterior distribution over them.

observations can be of any supported internal trace type, or a fixed probability expression.

The invariant

m = decondition(condition(m, obs))

should hold for generative models m and arbitrary obs.

AbstractPPL.deconditionFunction
decondition(conditioned_model)

Remove the conditioning (i.e., observation data) from conditioned_model, turning it into a generative model over prior and observed variables.

The invariant

m == condition(decondition(m), obs)

should hold for models m with conditioned variables obs.

AbstractPPL.evaluate!!Function

evaluate!!

General API for model operations, e.g. prior evaluation, log density, log joint etc.

AbstractPPL.getopticMethod
getoptic(vn::VarName)

Return the optic of the Julia variable used to generate vn.

Examples

julia> getoptic(@varname(x[1][2:3]))
(@o _[1][2:3])

julia> getoptic(@varname(y))
identity (generic function with 1 method)
AbstractPPL.getsymMethod
getsym(vn::VarName)

Return the symbol of the Julia variable used to generate vn.

Examples

julia> getsym(@varname(x[1][2:3]))
:x

julia> getsym(@varname(y))
:y
AbstractPPL.inspaceMethod
inspace(vn::Union{VarName, Symbol}, space::Tuple)

Check whether vn's variable symbol is in space. The empty tuple counts as the "universal space" containing all variables. Subsumption (see subsume) is respected.

Examples

julia> inspace(@varname(x[1][2:3]), ())
true

julia> inspace(@varname(x[1][2:3]), (:x,))
true

julia> inspace(@varname(x[1][2:3]), (@varname(x),))
true

julia> inspace(@varname(x[1][2:3]), (@varname(x[1:10]), :y))
true

julia> inspace(@varname(x[1][2:3]), (@varname(x[:][2:4]), :y))
true

julia> inspace(@varname(x[1][2:3]), (@varname(x[1:10]),))
true
AbstractPPL.is_static_opticMethod
is_static_optic(l)

Return true if l is one or a composition of identity, PropertyLens, and IndexLens; false if l is one or a composition of DynamicIndexLens; and undefined otherwise.

AbstractPPL.reconcretize_indexMethod
reconcretize_index(original_index, lowered_index)

Create the index to be emitted in concretize. original_index is the original, unconcretized index, and lowered_index the respective position of the result of to_indices.

The only purpose of this are special cases like :, which we want to avoid becoming a Base.Slice(OneTo(...)) – it would confuse people when printed. Instead, we concretize to a ConcretizedSlice based on the lowered_index, just what you'd get with an explicit begin:end

AbstractPPL.subsumesMethod
subsumes(u::VarName, v::VarName)

Check whether the variable name v describes a sub-range of the variable u. Supported indexing:

  • Scalar:

```jldoctest julia> subsumes(@varname(x), @varname(x[1, 2])) true

julia> subsumes(@varname(x[1, 2]), @varname(x[1, 2][3])) true ```

  • Array of scalar: basically everything that fulfills issubset.

```jldoctest julia> subsumes(@varname(x[[1, 2], 3]), @varname(x[1, 3])) true

julia> subsumes(@varname(x[1:3]), @varname(x[2][1])) true ```

  • Slices:

jldoctest julia> subsumes(@varname(x[2, :]), @varname(x[2, 10][1])) true

Currently not supported are:

  • Boolean indexing, literal CartesianIndex (these could be added, though)
  • Linear indexing of multidimensional arrays: x[4] does not subsume x[2, 2] for a matrix x
  • Trailing ones: x[2, 1] does not subsume x[2] for a vector x
AbstractPPL.subsumes_indicesMethod
subsumes_indices(left_indices::Tuple, right_indices::Tuple)

Return true if right_indices is subsumed by left_indices. left_indices is assumed to be concretized and consist of either Ints or AbstractArrays of scalar indices that are supported by array A.

Currently not supported are:

  • Boolean indexing, literal CartesianIndex (these could be added, though)
  • Linear indexing of multidimensional arrays: x[4] does not subsume x[2, 2] for a matrix x
  • Trailing ones: x[2, 1] does not subsume x[2] for a vector x
AbstractPPL.subsumes_indicesMethod
subsumes_indices(t, u)

Return true if the indexing represented by t subsumes u.

This is mostly useful for comparing compositions involving IndexLens e.g. _[1][2].a[2] and _[1][2].a. In such a scenario we do the following:

  1. Combine [1][2] into a Tuple of indices using combine_indices.
  2. Do the same for [1][2].
  3. Compare the two tuples from (1) and (2) using subsumes_indices.
  4. Since we're still undecided, we call subsume(@o(_.a[2]), @o(_.a)) which then returns false.

Example

julia> t = @o(_[1].a); u = @o(_[1]);

julia> subsumes_indices(t, u)
false

julia> subsumes_indices(u, t)
true

julia> # `identity` subsumes all.
       subsumes_indices(identity, t)
true

julia> # None subsumes `identity`.
       subsumes_indices(t, identity)
false

julia> AbstractPPL.subsumes(@o(_[1][2].a[2]), @o(_[1][2].a))
false

julia> AbstractPPL.subsumes(@o(_[1][2].a), @o(_[1][2].a[2]))
true
Accessors.setMethod
set(obj, vn::VarName{sym}, value)

Alias for set(obj, PropertyLens{sym}() ⨟ getoptic(vn), value).

Example

julia> Accessors.set(nt, @varname(a), 10)
(a = 10, b = (c = [1, 2, 3],))

julia> Accessors.set(nt, @varname(b.c[1]), 10)
(a = 1, b = (c = [10, 2, 3],))
Base.getMethod
get(obj, vn::VarName{sym})

Alias for (PropertyLens{sym}() ⨟ getoptic(vn))(obj). ```

Base.randMethod
rand([rng=Random.default_rng()], [T=NamedTuple], model::AbstractProbabilisticProgram) -> T

Draw a sample from the joint distribution of the model specified by the probabilistic program.

The sample will be returned as format specified by T.

DensityInterface.logdensityofMethod
logdensityof(model, trace)

Evaluate the (possibly unnormalized) density of the model specified by the probabilistic program in model, at specific values for the random variables given through trace.

trace can be of any supported internal trace type, or a fixed probability expression.

logdensityof should interact with conditioning and deconditioning in the way required by probability theory.

AbstractPPL.@varnameMacro
@varname(expr, concretize=false)

A macro that returns an instance of VarName given a symbol or indexing expression expr.

If concretize is true, the resulting expression will be wrapped in a concretize call.

Note that expressions involving dynamic indexing, i.e. begin and/or end, will always need to be concretized as VarName only supports non-dynamic indexing as determined by is_static_index. See examples below.

Examples

Dynamic indexing

julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], );

julia> @varname(x.a[1:end, end][:], true)
x.a[1:3, 2][:]

julia> @varname(x.a[end], false)  # disable concretization
ERROR: LoadError: Variable name `x.a[end]` is dynamic and requires concretization!
[...]

julia> @varname(x.a[end])  # concretization occurs by default if deemed necessary
x.a[6]

julia> # Note that "dynamic" here refers to usage of `begin` and/or `end`,
       # _not_ "information only available at runtime", i.e. the following works.
       [@varname(x.a[i]) for i = 1:length(x.a)][end]
x.a[6]

julia> # Potentially surprising behaviour, but this is equivalent to what Base does:
       @varname(x[2:2:5]), 2:2:5
(x[2:2:4], 2:2:4)

General indexing

Under the hood optics are used for the indexing:

julia> getoptic(@varname(x))
identity (generic function with 1 method)

julia> getoptic(@varname(x[1]))
(@o _[1])

julia> getoptic(@varname(x[:, 1]))
(@o _[Colon(), 1])

julia> getoptic(@varname(x[:, 1][2]))
(@o _[Colon(), 1][2])

julia> getoptic(@varname(x[1,2][1+5][45][3]))
(@o _[1, 2][6][45][3])

This also means that we support property access:

julia> getoptic(@varname(x.a))
(@o _.a)

julia> getoptic(@varname(x.a[1]))
(@o _.a[1])

julia> x = (a = [(b = rand(2), )], ); getoptic(@varname(x.a[1].b[end], true))
(@o _.a[1].b[2])

Interpolation can be used for variable names, or array name, but not the lhs of a . expression. Variables within indices are always evaluated in the calling scope.

julia> name, i = :a, 10;

julia> @varname(x.$name[i, i+1])
x.a[10, 11]

julia> @varname($name)
a

julia> @varname($name[1])
a[1]

julia> @varname($name.x[1])
a.x[1]

julia> @varname(b.$name.x[1])
b.a.x[1]
AbstractPPL.@vsymMacro
@vsym(expr)

A macro that returns the variable symbol given the input variable expression expr. For example, @vsym x[1] returns :x.

Examples

julia> @vsym x
:x

julia> @vsym x[1,1][2,3]
:x

julia> @vsym x[end]
:x