Skip to content

Commit 161edf8

Browse files
authored
Reverse order of prefixing & add changelog (#792)
* Reverse order of prefixing * Simplify generated function (the non-generated path wasn't being used) * Expand on submodel behaviour in changelog
1 parent f5c5fda commit 161edf8

File tree

3 files changed

+111
-23
lines changed

3 files changed

+111
-23
lines changed

HISTORY.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# DynamicPPL Changelog
2+
3+
## 0.35.0
4+
5+
**Breaking**
6+
7+
- For submodels constructed using `to_submodel`, the order in which nested prefixes are applied has been changed.
8+
Previously, the order was that outer prefixes were applied first, then inner ones.
9+
This version reverses that.
10+
To illustrate:
11+
12+
```julia
13+
using DynamicPPL, Distributions
14+
15+
@model function subsubmodel()
16+
x ~ Normal()
17+
end
18+
19+
@model function submodel()
20+
x ~ to_submodel(prefix(subsubmodel(), :c), false)
21+
return x
22+
end
23+
24+
@model function parentmodel()
25+
x1 ~ to_submodel(prefix(submodel(), :a), false)
26+
x2 ~ to_submodel(prefix(submodel(), :b), false)
27+
end
28+
29+
keys(VarInfo(parentmodel()))
30+
```
31+
32+
Previously, the final line would return the variable names `c.a.x` and `c.b.x`.
33+
With this version, it will return `a.c.x` and `b.c.x`, which is more intuitive.
34+
(Note that this change brings `to_submodel`'s behaviour in line with the now-deprecated `@submodel` macro.)
35+
36+
This change also affects sampling in Turing.jl.
37+
38+
39+
## 0.34.2
40+
41+
- Fixed bugs in ValuesAsInModelContext as well as DebugContext where underlying PrefixContexts were not being applied.
42+
From a user-facing perspective, this means that for models which use manually prefixed submodels, e.g.
43+
44+
```julia
45+
using DynamicPPL, Distributions
46+
47+
@model inner() = x ~ Normal()
48+
49+
@model function outer()
50+
x1 ~ to_submodel(prefix(inner(), :a), false)
51+
x2 ~ to_submodel(prefix(inner(), :b), false)
52+
end
53+
```
54+
55+
will: (1) no longer error when sampling due to `check_model_and_trace`; and (2) contain both submodel's variables in the resulting chain (the behaviour before this patch was that the second `x` would override the first `x`).
56+
57+
- More broadly, implemented a general `prefix(ctx::AbstractContext, ::VarName)` which traverses the context tree in `ctx` to apply all necessary prefixes. This was a necessary step in fixing the above issues, but it also means that `prefix` is now capable of handling context trees with e.g. multiple prefixes at different levels of nesting.
58+
59+
## 0.34.1
60+
61+
- Fix an issue that prevented merging two VarInfos if they had different dimensions for a variable.
62+
63+
- Upper bound the compat version of KernelAbstractions to work around an issue in determining the right VarInfo type to use.
64+
65+
## 0.34.0
66+
67+
**Breaking**
68+
69+
- `rng` argument removed from `values_as_in_model`, and `varinfo` made non-optional. This means that the only signatures allowed are
70+
71+
```
72+
values_as_in_model(::Model, ::Bool, ::AbstractVarInfo)
73+
values_as_in_model(::Model, ::Bool, ::AbstractVarInfo, ::AbstractContext)
74+
```
75+
76+
If you aren't using this function (it's probably only used in Turing.jl) then this won't affect you.
77+
78+
## 0.33.1
79+
80+
Reworked internals of `condition` and `decondition`.
81+
There are no changes to the public-facing API, but internally you can no longer use `condition` and `decondition` on an `AbstractContext`, you can only use it on a `DynamicPPL.Model`. If you want to modify a context, use `ConditionContext` and `decondition_context`.
82+
83+
## 0.33.0
84+
85+
**Breaking**
86+
87+
- `values_as_in_model()` now requires an extra boolean parameter, specifying whether variables on the lhs of `:=` statements are to be included in the resulting `OrderedDict` of values.
88+
The type signature is now `values_as_in_model([rng,] model, include_colon_eq::Bool [, varinfo, context])`
89+
90+
**Other**
91+
92+
- Moved the implementation of `predict` from Turing.jl to DynamicPPL.jl; the user-facing behaviour is otherwise the same
93+
- Improved error message when a user tries to initialise a model with parameters that don't correspond strictly to the underlying VarInfo used

src/contexts.jl

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -253,31 +253,26 @@ function PrefixContext{Prefix}(context::AbstractContext) where {Prefix}
253253
return PrefixContext{Prefix,typeof(context)}(context)
254254
end
255255

256-
NodeTrait(context::PrefixContext) = IsParent()
256+
NodeTrait(::PrefixContext) = IsParent()
257257
childcontext(context::PrefixContext) = context.context
258-
function setchildcontext(parent::PrefixContext{Prefix}, child) where {Prefix}
258+
function setchildcontext(::PrefixContext{Prefix}, child) where {Prefix}
259259
return PrefixContext{Prefix}(child)
260260
end
261261

262262
const PREFIX_SEPARATOR = Symbol(".")
263263

264-
# TODO(penelopeysm): Prefixing arguably occurs the wrong way round here
265-
function PrefixContext{PrefixInner}(
266-
context::PrefixContext{PrefixOuter}
267-
) where {PrefixInner,PrefixOuter}
268-
if @generated
269-
:(PrefixContext{$(QuoteNode(Symbol(PrefixOuter, PREFIX_SEPARATOR, PrefixInner)))}(
270-
context.context
271-
))
272-
else
273-
PrefixContext{Symbol(PrefixOuter, PREFIX_SEPARATOR, PrefixInner)}(context.context)
274-
end
264+
@generated function PrefixContext{PrefixOuter}(
265+
context::PrefixContext{PrefixInner}
266+
) where {PrefixOuter,PrefixInner}
267+
return :(PrefixContext{$(QuoteNode(Symbol(PrefixOuter, PREFIX_SEPARATOR, PrefixInner)))}(
268+
context.context
269+
))
275270
end
276271

277-
# TODO(penelopeysm): Prefixing arguably occurs the wrong way round here
278272
function prefix(ctx::PrefixContext{Prefix}, vn::VarName{Sym}) where {Prefix,Sym}
279-
return prefix(
280-
childcontext(ctx), VarName{Symbol(Prefix, PREFIX_SEPARATOR, Sym)}(getoptic(vn))
273+
vn_prefixed_inner = prefix(childcontext(ctx), vn)
274+
return VarName{Symbol(Prefix, PREFIX_SEPARATOR, getsym(vn_prefixed_inner))}(
275+
getoptic(vn_prefixed_inner)
281276
)
282277
end
283278
prefix(ctx::AbstractContext, vn::VarName) = prefix(NodeTrait(ctx), ctx, vn)

test/contexts.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ end
142142

143143
@testset "PrefixContext" begin
144144
@testset "prefixing" begin
145-
ctx = @inferred PrefixContext{:f}(
146-
PrefixContext{:e}(
147-
PrefixContext{:d}(
148-
PrefixContext{:c}(
149-
PrefixContext{:b}(PrefixContext{:a}(DefaultContext()))
145+
ctx = @inferred PrefixContext{:a}(
146+
PrefixContext{:b}(
147+
PrefixContext{:c}(
148+
PrefixContext{:d}(
149+
PrefixContext{:e}(PrefixContext{:f}(DefaultContext()))
150150
),
151151
),
152152
),
@@ -174,8 +174,8 @@ end
174174
vn_prefixed4 = prefix(ctx4, vn)
175175
@test DynamicPPL.getsym(vn_prefixed1) == Symbol("a.x")
176176
@test DynamicPPL.getsym(vn_prefixed2) == Symbol("a.x")
177-
@test DynamicPPL.getsym(vn_prefixed3) == Symbol("a.b.x")
178-
@test DynamicPPL.getsym(vn_prefixed4) == Symbol("a.b.x")
177+
@test DynamicPPL.getsym(vn_prefixed3) == Symbol("b.a.x")
178+
@test DynamicPPL.getsym(vn_prefixed4) == Symbol("b.a.x")
179179
@test DynamicPPL.getoptic(vn_prefixed1) === DynamicPPL.getoptic(vn)
180180
@test DynamicPPL.getoptic(vn_prefixed2) === DynamicPPL.getoptic(vn)
181181
@test DynamicPPL.getoptic(vn_prefixed3) === DynamicPPL.getoptic(vn)

0 commit comments

Comments
 (0)