Skip to content

Commit 4ca9528

Browse files
authored
Remove NodeTrait (#1133)
* Remove NodeTrait * Changelog * Fix exports * docs * fix a bug * Fix doctests * Fix test * tweak changelog
1 parent a8eb2e7 commit 4ca9528

File tree

12 files changed

+154
-175
lines changed

12 files changed

+154
-175
lines changed

HISTORY.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22

33
## 0.39.0
44

5+
### Breaking changes
6+
7+
#### Parent and leaf contexts
8+
9+
The `DynamicPPL.NodeTrait` function has been removed.
10+
Instead of implementing this, parent contexts should subtype `DynamicPPL.AbstractParentContext`.
11+
This is an abstract type which requires you to overload two functions, `DynamicPPL.childcontext` and `DynamicPPL.setchildcontext`.
12+
13+
There should generally be few reasons to define your own parent contexts (the only one we are aware of, outside of DynamicPPL itself, is `Turing.Inference.GibbsContext`), so this change should not really affect users.
14+
15+
Leaf contexts require no changes, apart from a removal of the `NodeTrait` function.
16+
17+
`ConditionContext` and `PrefixContext` are no longer exported.
18+
You should not need to use these directly, please use `AbstractPPL.condition` and `DynamicPPL.prefix` instead.
19+
20+
#### Miscellaneous
21+
522
Removed the method `returned(::Model, values, keys)`; please use `returned(::Model, ::AbstractDict{<:VarName})` instead.
623

724
## 0.38.9

docs/src/api.md

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,6 @@ Base.empty!
352352
SimpleVarInfo
353353
```
354354

355-
### Tilde-pipeline
356-
357-
```@docs
358-
tilde_assume!!
359-
tilde_observe!!
360-
```
361-
362355
### Accumulators
363356

364357
The subtypes of [`AbstractVarInfo`](@ref) store the cumulative log prior and log likelihood, and sometimes other variables that change during executing, in what are called accumulators.
@@ -463,15 +456,48 @@ By default, it does not perform any actual sampling: it only evaluates the model
463456
If you wish to sample new values, see the section on [VarInfo initialisation](#VarInfo-initialisation) just below this.
464457

465458
The behaviour of a model execution can be changed with evaluation contexts, which are a field of the model.
466-
Contexts are subtypes of `AbstractPPL.AbstractContext`.
459+
460+
All contexts are subtypes of `AbstractPPL.AbstractContext`.
461+
462+
Contexts are split into two kinds:
463+
464+
**Leaf contexts**: These are the most important contexts as they ultimately decide how model evaluation proceeds.
465+
For example, `DefaultContext` evaluates the model using values stored inside a VarInfo's metadata, whereas `InitContext` obtains new values either by sampling or from a known set of parameters.
466+
DynamicPPL has more leaf contexts which are used for internal purposes, but these are the two that are exported.
467467

468468
```@docs
469469
DefaultContext
470-
PrefixContext
471-
ConditionContext
472470
InitContext
473471
```
474472

473+
To implement a leaf context, you need to subtype `AbstractPPL.AbstractContext` and implement the `tilde_assume!!` and `tilde_observe!!` methods for your context.
474+
475+
```@docs
476+
tilde_assume!!
477+
tilde_observe!!
478+
```
479+
480+
**Parent contexts**: These essentially act as 'modifiers' for leaf contexts.
481+
For example, `PrefixContext` adds a prefix to all variable names during evaluation, while `ConditionContext` marks certain variables as observed.
482+
483+
To implement a parent context, you have to subtype `DynamicPPL.AbstractParentContext`, and implement the `childcontext` and `setchildcontext` methods.
484+
If needed, you can also implement `tilde_assume!!` and `tilde_observe!!` for your context.
485+
This is optional; the default implementation is to simply delegate to the child context.
486+
487+
```@docs
488+
AbstractParentContext
489+
childcontext
490+
setchildcontext
491+
```
492+
493+
Since contexts form a tree structure, these functions are automatically defined for manipulating context stacks.
494+
They are mainly useful for modifying the fundamental behaviour (i.e. the leaf context), without affecting any of the modifiers (i.e. parent contexts).
495+
496+
```@docs
497+
leafcontext
498+
setleafcontext
499+
```
500+
475501
### VarInfo initialisation
476502

477503
The function `init!!` is used to initialise, or overwrite, values in a VarInfo.

src/DynamicPPL.jl

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,21 @@ export AbstractVarInfo,
9494
values_as_in_model,
9595
# LogDensityFunction
9696
LogDensityFunction,
97-
# Contexts
97+
# Leaf contexts
98+
AbstractContext,
9899
contextualize,
99100
DefaultContext,
100-
PrefixContext,
101-
ConditionContext,
101+
InitContext,
102+
# Parent contexts
103+
AbstractParentContext,
104+
childcontext,
105+
setchildcontext,
106+
leafcontext,
107+
setleafcontext,
102108
# Tilde pipeline
103109
tilde_assume!!,
104110
tilde_observe!!,
105111
# Initialisation
106-
InitContext,
107112
AbstractInitStrategy,
108113
InitFromPrior,
109114
InitFromUniform,

src/contexts.jl

Lines changed: 33 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,32 @@
11
"""
2-
NodeTrait(context)
3-
NodeTrait(f, context)
2+
AbstractParentContext
43
5-
Specifies the role of `context` in the context-tree.
4+
An abstract context that has a child context.
65
7-
The officially supported traits are:
8-
- `IsLeaf`: `context` does not have any decendants.
9-
- `IsParent`: `context` has a child context to which we often defer.
10-
Expects the following methods to be implemented:
11-
- [`childcontext`](@ref)
12-
- [`setchildcontext`](@ref)
13-
"""
14-
abstract type NodeTrait end
15-
NodeTrait(_, context) = NodeTrait(context)
16-
17-
"""
18-
IsLeaf
19-
20-
Specifies that the context is a leaf in the context-tree.
21-
"""
22-
struct IsLeaf <: NodeTrait end
23-
"""
24-
IsParent
6+
Subtypes of `AbstractParentContext` must implement the following interface:
257
26-
Specifies that the context is a parent in the context-tree.
8+
- `DynamicPPL.childcontext(context::AbstractParentContext)`: Return the child context.
9+
- `DynamicPPL.setchildcontext(parent::AbstractParentContext, child::AbstractContext)`: Reconstruct
10+
`parent` but now using `child` as its child context.
2711
"""
28-
struct IsParent <: NodeTrait end
12+
abstract type AbstractParentContext <: AbstractContext end
2913

3014
"""
31-
childcontext(context)
15+
childcontext(context::AbstractParentContext)
3216
3317
Return the descendant context of `context`.
3418
"""
3519
childcontext
3620

3721
"""
38-
setchildcontext(parent::AbstractContext, child::AbstractContext)
22+
setchildcontext(parent::AbstractParentContext, child::AbstractContext)
3923
4024
Reconstruct `parent` but now using `child` is its [`childcontext`](@ref),
4125
effectively updating the child context.
4226
4327
# Examples
4428
```jldoctest
45-
julia> using DynamicPPL: DynamicTransformationContext
29+
julia> using DynamicPPL: DynamicTransformationContext, ConditionContext
4630
4731
julia> ctx = ConditionContext((; a = 1));
4832
@@ -60,12 +44,11 @@ setchildcontext
6044
"""
6145
leafcontext(context::AbstractContext)
6246
63-
Return the leaf of `context`, i.e. the first descendant context that `IsLeaf`.
47+
Return the leaf of `context`, i.e. the first descendant context that is not an
48+
`AbstractParentContext`.
6449
"""
65-
leafcontext(context::AbstractContext) =
66-
leafcontext(NodeTrait(leafcontext, context), context)
67-
leafcontext(::IsLeaf, context::AbstractContext) = context
68-
leafcontext(::IsParent, context::AbstractContext) = leafcontext(childcontext(context))
50+
leafcontext(context::AbstractContext) = context
51+
leafcontext(context::AbstractParentContext) = leafcontext(childcontext(context))
6952

7053
"""
7154
setleafcontext(left::AbstractContext, right::AbstractContext)
@@ -80,12 +63,10 @@ original leaf context of `left`.
8063
```jldoctest
8164
julia> using DynamicPPL: leafcontext, setleafcontext, childcontext, setchildcontext, AbstractContext, DynamicTransformationContext
8265
83-
julia> struct ParentContext{C} <: AbstractContext
66+
julia> struct ParentContext{C} <: AbstractParentContext
8467
context::C
8568
end
8669
87-
julia> DynamicPPL.NodeTrait(::ParentContext) = DynamicPPL.IsParent()
88-
8970
julia> DynamicPPL.childcontext(context::ParentContext) = context.context
9071
9172
julia> DynamicPPL.setchildcontext(::ParentContext, child) = ParentContext(child)
@@ -104,21 +85,10 @@ julia> # Append another parent context.
10485
ParentContext(ParentContext(ParentContext(DefaultContext())))
10586
```
10687
"""
107-
function setleafcontext(left::AbstractContext, right::AbstractContext)
108-
return setleafcontext(
109-
NodeTrait(setleafcontext, left), NodeTrait(setleafcontext, right), left, right
110-
)
111-
end
112-
function setleafcontext(
113-
::IsParent, ::IsParent, left::AbstractContext, right::AbstractContext
114-
)
88+
function setleafcontext(left::AbstractParentContext, right::AbstractContext)
11589
return setchildcontext(left, setleafcontext(childcontext(left), right))
11690
end
117-
function setleafcontext(::IsParent, ::IsLeaf, left::AbstractContext, right::AbstractContext)
118-
return setchildcontext(left, setleafcontext(childcontext(left), right))
119-
end
120-
setleafcontext(::IsLeaf, ::IsParent, left::AbstractContext, right::AbstractContext) = right
121-
setleafcontext(::IsLeaf, ::IsLeaf, left::AbstractContext, right::AbstractContext) = right
91+
setleafcontext(::AbstractContext, right::AbstractContext) = right
12292

12393
"""
12494
DynamicPPL.tilde_assume!!(
@@ -138,10 +108,15 @@ This function should return a tuple `(x, vi)`, where `x` is the sampled value (w
138108
must be in unlinked space!) and `vi` is the updated VarInfo.
139109
"""
140110
function tilde_assume!!(
141-
context::AbstractContext, right::Distribution, vn::VarName, vi::AbstractVarInfo
111+
context::AbstractParentContext, right::Distribution, vn::VarName, vi::AbstractVarInfo
142112
)
143113
return tilde_assume!!(childcontext(context), right, vn, vi)
144114
end
115+
function tilde_assume!!(
116+
context::AbstractContext, ::Distribution, ::VarName, ::AbstractVarInfo
117+
)
118+
return error("tilde_assume!! not implemented for context of type $(typeof(context))")
119+
end
145120

146121
"""
147122
DynamicPPL.tilde_observe!!(
@@ -171,11 +146,20 @@ This function should return a tuple `(left, vi)`, where `left` is the same as th
171146
`vi` is the updated VarInfo.
172147
"""
173148
function tilde_observe!!(
174-
context::AbstractContext,
149+
context::AbstractParentContext,
175150
right::Distribution,
176151
left,
177152
vn::Union{VarName,Nothing},
178153
vi::AbstractVarInfo,
179154
)
180155
return tilde_observe!!(childcontext(context), right, left, vn, vi)
181156
end
157+
function tilde_observe!!(
158+
context::AbstractContext,
159+
::Distribution,
160+
::Any,
161+
::Union{VarName,Nothing},
162+
::AbstractVarInfo,
163+
)
164+
return error("tilde_observe!! not implemented for context of type $(typeof(context))")
165+
end

0 commit comments

Comments
 (0)