Skip to content

Commit 1d1b11e

Browse files
committed
Merge remote-tracking branch 'origin/main' into tor/benchmark-update
2 parents c34e489 + 6fe46ee commit 1d1b11e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1412
-2338
lines changed

HISTORY.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# DynamicPPL Changelog
2+
3+
## 0.35.0
4+
5+
**Breaking changes**
6+
7+
### `.~` right hand side must be a univariate distribution
8+
9+
Previously we allowed statements like
10+
11+
```julia
12+
x .~ [Normal(), Gamma()]
13+
```
14+
15+
where the right hand side of a `.~` was an array of distributions, and ones like
16+
17+
```julia
18+
x .~ MvNormal(fill(0.0, 2), I)
19+
```
20+
21+
where the right hand side was a multivariate distribution.
22+
23+
These are no longer allowed. The only things allowed on the right hand side of a `.~` statement are univariate distributions, such as
24+
25+
```julia
26+
x = Array{Float64,3}(undef, 2, 3, 4)
27+
x .~ Normal()
28+
```
29+
30+
The reasons for this are internal code simplification and the fact that broadcasting where both sides are multidimensional but of different dimensions is typically confusing to read.
31+
32+
If the right hand side and the left hand side have the same dimension, one can simply use `~`. Arrays of distributions can be replaced with `product_distribution`. So instead of
33+
34+
```julia
35+
x .~ [Normal(), Gamma()]
36+
x .~ Normal.(y)
37+
x .~ MvNormal(fill(0.0, 2), I)
38+
```
39+
40+
do
41+
42+
```julia
43+
x ~ product_distribution([Normal(), Gamma()])
44+
x ~ product_distribution(Normal.(y))
45+
x ~ MvNormal(fill(0.0, 2), I)
46+
```
47+
48+
This is often more performant as well. Note that using `~` rather than `.~` does change the internal storage format a bit: With `.~` `x[i]` are stored as separate variables, with `~` as a single multivariate variable `x`. In most cases this does not change anything for the user, but if it does cause issues, e.g. if you are dealing with `VarInfo` objects directly and need to keep the old behavior, you can always expand into a loop, such as
49+
50+
```julia
51+
dists = Normal.(y)
52+
for i in 1:length(dists)
53+
x[i] ~ dists[i]
54+
end
55+
```
56+
57+
Cases where the right hand side is of a different dimension than the left hand side, and neither is a scalar, must be replaced with a loop. For example,
58+
59+
```julia
60+
x = Array{Float64,3}(undef, 2, 3, 4)
61+
x .~ MvNormal(fill(0, 2), I)
62+
```
63+
64+
should be replaced with something like
65+
66+
```julia
67+
x = Array{Float64,3}(2, 3, 4)
68+
for i in 1:3, j in 1:4
69+
x[:, i, j] ~ MvNormal(fill(0, 2), I)
70+
end
71+
```
72+
73+
This release also completely rewrites the internal implementation of `.~`, where from now on all `.~` statements are turned into loops over `~` statements at macro time. However, the only breaking aspect of this change is the above change to what's allowed on the right hand side.
74+
75+
### Remove indexing by samplers
76+
77+
This release removes the feature of `VarInfo` where it kept track of which variable was associated with which sampler. This means removing all user-facing methods where `VarInfo`s where being indexed with samplers. In particular,
78+
79+
- `link` and `invlink`, and their `!!` versions, no longer accept a sampler as an argument to specify which variables to (inv)link. The `link(varinfo, model)` methods remain in place, and as a new addition one can give a `Tuple` of `VarName`s to (inv)link only select variables, as in `link(varinfo, varname_tuple, model)`.
80+
- `set_retained_vns_del_by_spl!` has been replaced by `set_retained_vns_del!` which applies to all variables.
81+
- `getindex`, `setindex!`, and `setindex!!` no longer accept samplers as arguments
82+
- `unflatten` no longer accepts a sampler as an argument
83+
- `eltype(::VarInfo)` no longer accepts a sampler as an argument
84+
- `keys(::VarInfo)` no longer accepts a sampler as an argument
85+
- `VarInfo(::VarInfo, ::Sampler, ::AbstractVector)` no longer accepts the sampler argument.
86+
- `push!!` and `push!` no longer accept samplers or `Selector`s as arguments
87+
- `getgid`, `setgid!`, `updategid!`, `getspace`, and `inspace` no longer exist
88+
89+
### Reverse prefixing order
90+
91+
- For submodels constructed using `to_submodel`, the order in which nested prefixes are applied has been changed.
92+
Previously, the order was that outer prefixes were applied first, then inner ones.
93+
This version reverses that.
94+
To illustrate:
95+
96+
```julia
97+
using DynamicPPL, Distributions
98+
99+
@model function subsubmodel()
100+
return x ~ Normal()
101+
end
102+
103+
@model function submodel()
104+
x ~ to_submodel(prefix(subsubmodel(), :c), false)
105+
return x
106+
end
107+
108+
@model function parentmodel()
109+
x1 ~ to_submodel(prefix(submodel(), :a), false)
110+
return x2 ~ to_submodel(prefix(submodel(), :b), false)
111+
end
112+
113+
keys(VarInfo(parentmodel()))
114+
```
115+
116+
Previously, the final line would return the variable names `c.a.x` and `c.b.x`.
117+
With this version, it will return `a.c.x` and `b.c.x`, which is more intuitive.
118+
(Note that this change brings `to_submodel`'s behaviour in line with the now-deprecated `@submodel` macro.)
119+
120+
This change also affects sampling in Turing.jl.
121+
122+
### `LogDensityFunction` argument order
123+
124+
- The method `LogDensityFunction(varinfo, model, sampler)` has been removed.
125+
The only accepted order is `LogDensityFunction(model, varinfo, context; adtype)`.
126+
(For an explanation of `adtype`, see below.)
127+
The varinfo and context arguments are both still optional.
128+
129+
**Other changes**
130+
131+
### New exports
132+
133+
`LogDensityFunction` and `predict` are now exported from DynamicPPL.
134+
135+
### `LogDensityProblems` interface
136+
137+
LogDensityProblemsAD is now removed as a dependency.
138+
Instead of constructing a `LogDensityProblemAD.ADgradient` object, we now directly use `DifferentiationInterface` to calculate the gradient of the log density with respect to model parameters.
139+
140+
Note that if you wish, you can still construct an `ADgradient` out of a `LogDensityFunction` object (there is nothing preventing this).
141+
142+
However, in this version, `LogDensityFunction` now takes an extra AD type argument.
143+
If this argument is not provided, the behaviour is exactly the same as before, i.e. you can calculate `logdensity` but not its gradient.
144+
However, if you do pass an AD type, that will allow you to calculate the gradient as well.
145+
You may thus find that it is easier to instead do this:
146+
147+
```julia
148+
@model f() = ...
149+
150+
ldf = LogDensityFunction(f(); adtype=AutoForwardDiff())
151+
```
152+
153+
This will return an object which satisfies the `LogDensityProblems` interface to first-order, i.e. you can now directly call both
154+
155+
```
156+
LogDensityProblems.logdensity(ldf, params)
157+
LogDensityProblems.logdensity_and_gradient(ldf, params)
158+
```
159+
160+
without having to construct a separate `ADgradient` object.
161+
162+
If you prefer, you can also construct a new `LogDensityFunction` with a new AD type afterwards.
163+
The model, varinfo, and context will be taken from the original `LogDensityFunction`:
164+
165+
```julia
166+
@model f() = ...
167+
168+
ldf = LogDensityFunction(f()) # by default, no adtype set
169+
ldf_with_ad = LogDensityFunction(ldf, AutoForwardDiff())
170+
```
171+
172+
## 0.34.2
173+
174+
- Fixed bugs in ValuesAsInModelContext as well as DebugContext where underlying PrefixContexts were not being applied.
175+
From a user-facing perspective, this means that for models which use manually prefixed submodels, e.g.
176+
177+
```julia
178+
using DynamicPPL, Distributions
179+
180+
@model inner() = x ~ Normal()
181+
182+
@model function outer()
183+
x1 ~ to_submodel(prefix(inner(), :a), false)
184+
return x2 ~ to_submodel(prefix(inner(), :b), false)
185+
end
186+
```
187+
188+
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`).
189+
190+
- 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.
191+
192+
## 0.34.1
193+
194+
- Fix an issue that prevented merging two VarInfos if they had different dimensions for a variable.
195+
196+
- Upper bound the compat version of KernelAbstractions to work around an issue in determining the right VarInfo type to use.
197+
198+
## 0.34.0
199+
200+
**Breaking**
201+
202+
- `rng` argument removed from `values_as_in_model`, and `varinfo` made non-optional. This means that the only signatures allowed are
203+
204+
```
205+
values_as_in_model(::Model, ::Bool, ::AbstractVarInfo)
206+
values_as_in_model(::Model, ::Bool, ::AbstractVarInfo, ::AbstractContext)
207+
```
208+
209+
If you aren't using this function (it's probably only used in Turing.jl) then this won't affect you.
210+
211+
## 0.33.1
212+
213+
Reworked internals of `condition` and `decondition`.
214+
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`.
215+
216+
## 0.33.0
217+
218+
**Breaking**
219+
220+
- `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.
221+
The type signature is now `values_as_in_model([rng,] model, include_colon_eq::Bool [, varinfo, context])`
222+
223+
**Other**
224+
225+
- Moved the implementation of `predict` from Turing.jl to DynamicPPL.jl; the user-facing behaviour is otherwise the same
226+
- Improved error message when a user tries to initialise a model with parameters that don't correspond strictly to the underlying VarInfo used

Project.toml

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "DynamicPPL"
22
uuid = "366bfd00-2699-11ea-058f-f148b4cae6d8"
3-
version = "0.34.2"
3+
version = "0.35.0"
44

55
[deps]
66
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -12,19 +12,18 @@ Bijectors = "76274a88-744f-5084-9051-94815aaf08c4"
1212
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
1313
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
1414
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
15+
DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
1516
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1617
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
1718
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
1819
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
1920
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2021
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
21-
LogDensityProblemsAD = "996a588d-648d-4e1f-a8f0-a84b347e47b1"
2222
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
2323
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
2424
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2525
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
2626
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
27-
ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"
2827

2928
[weakdeps]
3029
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
@@ -33,7 +32,6 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
3332
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
3433
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
3534
Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6"
36-
ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"
3735

3836
[extensions]
3937
DynamicPPLChainRulesCoreExt = ["ChainRulesCore"]
@@ -42,7 +40,6 @@ DynamicPPLForwardDiffExt = ["ForwardDiff"]
4240
DynamicPPLJETExt = ["JET"]
4341
DynamicPPLMCMCChainsExt = ["MCMCChains"]
4442
DynamicPPLMooncakeExt = ["Mooncake"]
45-
DynamicPPLZygoteRulesExt = ["ZygoteRules"]
4643

4744
[compat]
4845
ADTypes = "1"
@@ -54,21 +51,20 @@ Bijectors = "0.13.18, 0.14, 0.15"
5451
ChainRulesCore = "1"
5552
Compat = "4"
5653
ConstructionBase = "1.5.4"
54+
DifferentiationInterface = "0.6.41"
5755
Distributions = "0.25"
5856
DocStringExtensions = "0.9"
59-
KernelAbstractions = "0.9.33"
6057
EnzymeCore = "0.6 - 0.8"
61-
ForwardDiff = "0.10"
58+
ForwardDiff = "0.10.12"
6259
JET = "0.9"
60+
KernelAbstractions = "0.9.33"
6361
LinearAlgebra = "1.6"
6462
LogDensityProblems = "2"
65-
LogDensityProblemsAD = "1.7.0"
6663
MCMCChains = "6"
6764
MacroTools = "0.5.6"
68-
Mooncake = "0.4.59"
65+
Mooncake = "0.4.95"
6966
OrderedCollections = "1"
7067
Random = "1.6"
7168
Requires = "1"
7269
Test = "1.6"
73-
ZygoteRules = "0.2"
7470
julia = "1.10"

docs/make.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@ using DynamicPPL: AbstractPPL
99
# consistent with that.
1010
using Distributions
1111
using DocumenterMermaid
12+
# load MCMCChains package extension to make `predict` available
13+
using MCMCChains
1214

1315
# Doctest setup
14-
DocMeta.setdocmeta!(DynamicPPL, :DocTestSetup, :(using DynamicPPL); recursive=true)
16+
DocMeta.setdocmeta!(
17+
DynamicPPL, :DocTestSetup, :(using DynamicPPL, MCMCChains); recursive=true
18+
)
1519

1620
makedocs(;
1721
sitename="DynamicPPL",
1822
# The API index.html page is fairly large, and violates the default HTML page size
1923
# threshold of 200KiB, so we double that.
2024
format=Documenter.HTML(; size_threshold=2^10 * 400),
21-
modules=[DynamicPPL],
25+
modules=[DynamicPPL, Base.get_extension(DynamicPPL, :DynamicPPLMCMCChainsExt)],
2226
pages=[
2327
"Home" => "index.md", "API" => "api.md", "Internals" => ["internals/varinfo.md"]
2428
],

0 commit comments

Comments
 (0)