|
1 | 1 | # DynamicPPL Changelog
|
2 | 2 |
|
| 3 | +## 0.36.0 |
| 4 | + |
| 5 | +**Breaking changes** |
| 6 | + |
| 7 | +### Submodels: conditioning |
| 8 | + |
| 9 | +Variables in a submodel can now be conditioned and fixed in a correct way. |
| 10 | +See https://github.com/TuringLang/DynamicPPL.jl/issues/857 for a full illustration, but essentially it means you can now do this: |
| 11 | + |
| 12 | +```julia |
| 13 | +@model function inner() |
| 14 | + x ~ Normal() |
| 15 | + return y ~ Normal() |
| 16 | +end |
| 17 | +@model function outer() |
| 18 | + return a ~ to_submodel(inner() | (x=1.0,)) |
| 19 | +end |
| 20 | +``` |
| 21 | + |
| 22 | +and the `a.x` variable will be correctly conditioned. |
| 23 | +(Previously, you would have to condition `inner()` with the variable `a.x`, meaning that you would need to know what prefix to use before you had actually prefixed it.) |
| 24 | + |
| 25 | +### Submodel prefixing |
| 26 | + |
| 27 | +The way in which VarNames in submodels are prefixed has been changed. |
| 28 | +This is best explained through an example. |
| 29 | +Consider this model and submodel: |
| 30 | + |
| 31 | +```julia |
| 32 | +using DynamicPPL, Distributions |
| 33 | +@model inner() = x ~ Normal() |
| 34 | +@model outer() = a ~ to_submodel(inner()) |
| 35 | +``` |
| 36 | + |
| 37 | +In previous versions, the inner variable `x` would be saved as `a.x`. |
| 38 | +However, this was represented as a single symbol `Symbol("a.x")`: |
| 39 | + |
| 40 | +```julia |
| 41 | +julia> dump(keys(VarInfo(outer()))[1]) |
| 42 | +VarName{Symbol("a.x"), typeof(identity)} |
| 43 | + optic: identity (function of type typeof(identity)) |
| 44 | +``` |
| 45 | + |
| 46 | +Now, the inner variable is stored as a field `x` on the VarName `a`: |
| 47 | + |
| 48 | +```julia |
| 49 | +julia> dump(keys(VarInfo(outer()))[1]) |
| 50 | +VarName{:a, Accessors.PropertyLens{:x}} |
| 51 | + optic: Accessors.PropertyLens{:x} (@o _.x) |
| 52 | +``` |
| 53 | + |
| 54 | +In practice, this means that if you are trying to condition a variable in the submodel, you now need to use |
| 55 | + |
| 56 | +```julia |
| 57 | +outer() | (@varname(a.x) => 1.0,) |
| 58 | +``` |
| 59 | + |
| 60 | +instead of either of these (which would have worked previously) |
| 61 | + |
| 62 | +```julia |
| 63 | +outer() | (@varname(var"a.x") => 1.0,) |
| 64 | +outer() | (a.x=1.0,) |
| 65 | +``` |
| 66 | + |
| 67 | +In a similar way, if the variable on the left-hand side of your tilde statement is not just a single identifier, any fields or indices it accesses are now properly respected. |
| 68 | +Consider the following setup: |
| 69 | + |
| 70 | +```julia |
| 71 | +using DynamicPPL, Distributions |
| 72 | +@model inner() = x ~ Normal() |
| 73 | +@model function outer() |
| 74 | + a = Vector{Float64}(undef, 1) |
| 75 | + a[1] ~ to_submodel(inner()) |
| 76 | + return a |
| 77 | +end |
| 78 | +``` |
| 79 | + |
| 80 | +In this case, the variable sampled is actually the `x` field of the first element of `a`: |
| 81 | + |
| 82 | +```julia |
| 83 | +julia> only(keys(VarInfo(outer()))) == @varname(a[1].x) |
| 84 | +true |
| 85 | +``` |
| 86 | + |
| 87 | +Before this version, it used to be a single variable called `var"a[1].x"`. |
| 88 | + |
| 89 | +Note that if you are sampling from a model with submodels, this doesn't affect the way you interact with the `MCMCChains.Chains` object, because VarNames are converted into Symbols when stored in the chain. |
| 90 | +(This behaviour will likely be changed in the future, in that Chains should be indexable by VarNames and not just Symbols, but that has not been implemented yet.) |
| 91 | + |
| 92 | +### AD testing utilities |
| 93 | + |
| 94 | +`DynamicPPL.TestUtils.AD.run_ad` now links the VarInfo by default. |
| 95 | +To disable this, pass the `linked=false` keyword argument. |
| 96 | +If the calculated value or gradient is incorrect, it also throws a `DynamicPPL.TestUtils.AD.ADIncorrectException` rather than a test failure. |
| 97 | +This exception contains the actual and expected gradient so you can inspect it if needed; see the documentation for more information. |
| 98 | +From a practical perspective, this means that if you need to add this to a test suite, you need to use `@test run_ad(...) isa Any` rather than just `run_ad(...)`. |
| 99 | + |
| 100 | +### SimpleVarInfo linking / invlinking |
| 101 | + |
| 102 | +Linking a linked SimpleVarInfo, or invlinking an unlinked SimpleVarInfo, now displays a warning instead of an error. |
| 103 | + |
| 104 | +### VarInfo constructors |
| 105 | + |
| 106 | +`VarInfo(vi::VarInfo, values)` has been removed. You can replace this directly with `unflatten(vi, values)` instead. |
| 107 | + |
| 108 | +The `metadata` argument to `VarInfo([rng, ]model[, sampler, context, metadata])` has been removed. |
| 109 | +If you were not using this argument (most likely), then there is no change needed. |
| 110 | +If you were using the `metadata` argument to specify a blank `VarNamedVector`, then you should replace calls to `VarInfo` with `DynamicPPL.typed_vector_varinfo` instead (see 'Other changes' below). |
| 111 | + |
| 112 | +The `UntypedVarInfo` constructor and type is no longer exported. |
| 113 | +If you needed to construct one, you should now use `DynamicPPL.untyped_varinfo` instead. |
| 114 | + |
| 115 | +The `TypedVarInfo` constructor and type is no longer exported. |
| 116 | +The _type_ has been replaced with `DynamicPPL.NTVarInfo`. |
| 117 | +The _constructor_ has been replaced with `DynamicPPL.typed_varinfo`. |
| 118 | + |
| 119 | +Note that the exact kind of VarInfo returned by `VarInfo(rng, model, ...)` is an implementation detail. |
| 120 | +Previously, it was guaranteed that this would always be a VarInfo whose metadata was a `NamedTuple` containing `Metadata` structs. |
| 121 | +Going forward, this is no longer the case, and you should only assume that the returned object obeys the `AbstractVarInfo` interface. |
| 122 | + |
| 123 | +**Other changes** |
| 124 | + |
| 125 | +While these are technically breaking, they are only internal changes and do not affect the public API. |
| 126 | +The following four functions have been added and/or reworked to make it easier to construct VarInfos with different types of metadata: |
| 127 | + |
| 128 | + 1. `DynamicPPL.untyped_varinfo([rng, ]model[, sampler, context])` |
| 129 | + 2. `DynamicPPL.typed_varinfo([rng, ]model[, sampler, context])` |
| 130 | + 3. `DynamicPPL.untyped_vector_varinfo([rng, ]model[, sampler, context])` |
| 131 | + 4. `DynamicPPL.typed_vector_varinfo([rng, ]model[, sampler, context])` |
| 132 | + |
| 133 | +The reason for this change is that there were several flavours of VarInfo. |
| 134 | +Some, like `typed_varinfo`, were easy to construct because we had convenience methods for them; however, the others were more difficult. |
| 135 | +This change makes it easier to access different VarInfo types, and also makes it more explicit which one you are constructing. |
| 136 | + |
3 | 137 | ## 0.35.9
|
4 | 138 |
|
5 | 139 | Fixed the `isnan` check introduced in 0.35.7 for distributions which returned NamedTuple.
|
|
0 commit comments