Skip to content

Commit 0f20624

Browse files
committed
added docs to to_sampleable + removed the unnecessary macro exports
that we no longer need
1 parent bf35de4 commit 0f20624

File tree

6 files changed

+159
-217
lines changed

6 files changed

+159
-217
lines changed

docs/src/api.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,22 @@ These statements are rewritten by `@model` as calls of [internal functions](@ref
1414
@model
1515
```
1616

17-
One can nest models and call another model inside the model function with [`@submodel`](@ref) and [`@returned_quantities(model)`](@ref).
17+
One can nest models and call another model inside the model function with `left ~ to_sampleable(model)`.
18+
19+
```@docs
20+
to_sampleable
21+
```
22+
23+
In the past, one would instead embed sub-models using [`@submodel`](@ref), which has been deprecated since the introduction of [`to_sampleable(model)`](@ref)
1824

1925
```@docs
2026
@submodel
21-
@returned_quantities(model)
2227
```
2328

2429
In the context of nesting models, it's also useful to prefix the variables in sub-models to avoid variable names clashing:
2530

2631
```@docs
27-
@prefix
28-
DynamicPPL.prefix
32+
prefix
2933
```
3034

3135
### Type
@@ -126,11 +130,10 @@ It is possible to manually increase (or decrease) the accumulated log density fr
126130
@addlogprob!
127131
```
128132

129-
Return values of the model function for a collection of samples can be obtained with [`@returned_quantities`](@ref).
133+
Return values of the model function for a collection of samples can be obtained with [`returned_quantities`](@ref).
130134

131135
```@docs
132-
@returned_quantities(model, input)
133-
DynamicPPL.returned_quantities
136+
returned_quantities
134137
```
135138

136139
For a chain of samples, one can compute the pointwise log-likelihoods of each observed random variable with [`pointwise_loglikelihoods`](@ref). Similarly, the log-densities of the priors using

src/DynamicPPL.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ export AbstractVarInfo,
121121
decondition,
122122
fix,
123123
unfix,
124+
prefix,
125+
returned_quantities,
124126
# Convenience macros
125127
@addlogprob!,
126128
@submodel,
127-
@returned_quantities,
128-
@prefix,
129129
value_iterator_from_chain,
130130
check_model,
131131
check_model_and_trace,

src/compiler.jl

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,148 @@ struct SampleableModelWrapper{M}
44
model::M
55
end
66

7-
to_sampleable(model::DynamicPPL.Model) = SampleableModelWrapper(model)
7+
"""
8+
to_sampleable(model::Model)
9+
10+
Return a wrapper around `model` which indicates that this model can only be sampled from.
11+
12+
This is mainly meant to be used on the right-hand side of a `~` operator to indicate that
13+
the model can be sampled from but not necessarily evaluated for its log density.
14+
15+
!!! warning
16+
Note that other operations that one typically associate with expressions of the form `left ~ right`
17+
such as [`condition`](@ref) or [`fix`](@ref), will also not work with `to_sampleable`.
18+
19+
!!! warning
20+
It's generally recommended to use [`prefix(::Model, input)`](@ref) when working with submodels
21+
to ensure that the variables in `model` are unique and do not clash with other variables in the
22+
parent model or in other submodels.
23+
24+
# Examples
25+
26+
## Simple example
27+
```jldoctest submodel-to-sampleable; setup=:(using Distributions)
28+
julia> @model function demo1(x)
29+
x ~ Normal()
30+
return 1 + abs(x)
31+
end;
32+
33+
julia> @model function demo2(x, y)
34+
a ~ to_sampleable(demo1(x))
35+
return y ~ Uniform(0, a)
36+
end;
37+
```
38+
39+
When we sample from the model `demo2(missing, 0.4)` random variable `x` will be sampled:
40+
```jldoctest submodel-to-sampleable
41+
julia> vi = VarInfo(demo2(missing, 0.4));
42+
43+
julia> @varname(x) in keys(vi)
44+
true
45+
```
46+
47+
Variable `a` is not tracked since it can be computed from the random variable `x` that was
48+
tracked when running `demo1`:
49+
```jldoctest submodel-to-sampleable
50+
julia> @varname(a) in keys(vi)
51+
false
52+
```
53+
54+
We can check that the log joint probability of the model accumulated in `vi` is correct:
55+
56+
```jldoctest submodel-to-sampleable
57+
julia> x = vi[@varname(x)];
58+
59+
julia> getlogp(vi) ≈ logpdf(Normal(), x) + logpdf(Uniform(0, 1 + abs(x)), 0.4)
60+
true
61+
```
62+
63+
## With prefixing
64+
```jldoctest submodel-to-sampleable-prefix; setup=:(using Distributions)
65+
julia> @model function demo1(x)
66+
x ~ Normal()
67+
return 1 + abs(x)
68+
end;
69+
70+
julia> @model function demo2(x, y, z)
71+
a ~ to_sampleable(prefix(demo1(x), :sub1))
72+
b ~ to_sampleable(prefix(demo1(y), :sub2))
73+
return z ~ Uniform(-a, b)
74+
end;
75+
```
76+
77+
When we sample from the model `demo2(missing, missing, 0.4)` random variables `sub1.x` and
78+
`sub2.x` will be sampled:
79+
```jldoctest submodel-to-sampleable-prefix
80+
julia> vi = VarInfo(demo2(missing, missing, 0.4));
81+
82+
julia> @varname(var"sub1.x") in keys(vi)
83+
true
84+
85+
julia> @varname(var"sub2.x") in keys(vi)
86+
true
87+
```
88+
89+
Variables `a` and `b` are not tracked since they can be computed from the random variables `sub1.x` and
90+
`sub2.x` that were tracked when running `demo1`:
91+
```jldoctest submodel-to-sampleable-prefix
92+
julia> @varname(a) in keys(vi)
93+
false
94+
95+
julia> @varname(b) in keys(vi)
96+
false
97+
```
98+
99+
We can check that the log joint probability of the model accumulated in `vi` is correct:
100+
101+
```jldoctest submodel-to-sampleable-prefix
102+
julia> sub1_x = vi[@varname(var"sub1.x")];
103+
104+
julia> sub2_x = vi[@varname(var"sub2.x")];
105+
106+
julia> logprior = logpdf(Normal(), sub1_x) + logpdf(Normal(), sub2_x);
107+
108+
julia> loglikelihood = logpdf(Uniform(-1 - abs(sub1_x), 1 + abs(sub2_x)), 0.4);
109+
110+
julia> getlogp(vi) ≈ logprior + loglikelihood
111+
true
112+
```
113+
114+
## Different ways of setting the prefix
115+
```jldoctest submodel-to-sampleable-prefix-alts; setup=:(using DynamicPPL, Distributions)
116+
julia> @model inner() = x ~ Normal()
117+
inner (generic function with 2 methods)
118+
119+
julia> # When `prefix` is unspecified, no prefix is used.
120+
@model submodel_noprefix() = a ~ to_sampleable(inner())
121+
submodel_noprefix (generic function with 2 methods)
122+
123+
julia> @varname(x) in keys(VarInfo(submodel_noprefix()))
124+
true
125+
126+
julia> # Using a static string.
127+
@model submodel_prefix_string() = a ~ to_sampleable(prefix(inner(), "my prefix"))
128+
submodel_prefix_string (generic function with 2 methods)
129+
130+
julia> @varname(var"my prefix.x") in keys(VarInfo(submodel_prefix_string()))
131+
true
132+
133+
julia> # Using string interpolation.
134+
@model submodel_prefix_interpolation() = a = to_sampleable(prefix(inner(), "\$(nameof(inner()))"))
135+
submodel_prefix_interpolation (generic function with 2 methods)
136+
137+
julia> @varname(var"inner.x") in keys(VarInfo(submodel_prefix_interpolation()))
138+
true
139+
140+
julia> # Or using some arbitrary expression.
141+
@model submodel_prefix_expr() = a ~ to_sampleable(prefix(inner(), 1 + 2))
142+
submodel_prefix_expr (generic function with 2 methods)
143+
144+
julia> @varname(var"3.x") in keys(VarInfo(submodel_prefix_expr()))
145+
true
146+
```
147+
"""
148+
to_sampleable(model::Model) = SampleableModelWrapper(model)
8149

9150
"""
10151
need_concretize(expr)

src/contexts.jl

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -322,32 +322,6 @@ function prefix(model::Model, ::Val{x}) where {x}
322322
return contextualize(model, PrefixContext{Symbol(x)}(model.context))
323323
end
324324

325-
"""
326-
@prefix(model, prefix_expr)
327-
328-
Return `model` but with all random variables prefixed by `prefix_expr`.
329-
330-
The result of `prefix_expr` must will be converted to a `Symbol` and used as the prefix.
331-
332-
!!! note
333-
This is effectively just a convenience macro for the method [`DynamicPPL.prefix(::Model, x)`](@ref),
334-
which automatically converts the result of `prefix_expr` into a `Val` to avoid runtime overheads
335-
for static prefixes. For more control over the prefixing, use the method directly.
336-
337-
# Examples
338-
339-
```jldoctest
340-
julia> @model demo() = x ~ Dirac(1)
341-
demo (generic function with 2 methods)
342-
343-
julia> rand(@prefix(demo(), :my_prefix))
344-
(var"my_prefix.x" = 1,)
345-
```
346-
"""
347-
macro prefix(model, prefix_expr)
348-
return :($prefix($(esc(model)), $Val{$Symbol($(esc(prefix_expr)))}()))
349-
end
350-
351325
struct ConditionContext{Values,Ctx<:AbstractContext} <: AbstractContext
352326
values::Values
353327
context::Ctx

src/model.jl

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,15 +1250,3 @@ end
12501250
function returned_quantities(model::Model, values, keys)
12511251
return returned_quantities(model, NamedTuple{keys}(values))
12521252
end
1253-
1254-
"""
1255-
@returned_quantities(model, input)
1256-
1257-
Execute `model` and extract the return-values of `model` for `input`.
1258-
1259-
!!! note
1260-
This macro is in fact a simple wrapper around the method [`DynamicPPL.returned_quantities`](@ref).
1261-
"""
1262-
macro returned_quantities(model_expr, input_expr)
1263-
return :($returned_quantities($(esc(model_expr)), $(esc(input_expr))))
1264-
end

0 commit comments

Comments
 (0)