Skip to content

Commit 9b1014d

Browse files
committed
Merge remote-tracking branch 'origin/master' into torfjelde/varnamevector
2 parents ff68206 + 138bd40 commit 9b1014d

Some content is hidden

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

46 files changed

+2228
-1020
lines changed

.github/workflows/DocsNav.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Add Navbar
2+
3+
on:
4+
page_build: # Triggers the workflow on push events to gh-pages branch
5+
workflow_dispatch: # Allows manual triggering
6+
schedule:
7+
- cron: '0 0 * * 0' # Runs every week on Sunday at midnight (UTC)
8+
9+
jobs:
10+
add-navbar:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: write
14+
steps:
15+
- name: Checkout gh-pages
16+
uses: actions/checkout@v4
17+
with:
18+
ref: gh-pages
19+
fetch-depth: 0
20+
21+
- name: Download insert_navbar.sh
22+
run: |
23+
curl -O https://raw.githubusercontent.com/TuringLang/turinglang.github.io/main/assets/scripts/insert_navbar.sh
24+
chmod +x insert_navbar.sh
25+
26+
- name: Update Navbar
27+
env:
28+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29+
run: |
30+
git config user.name github-actions[bot]
31+
git config user.email github-actions[bot]@users.noreply.github.com
32+
33+
# Define the URL of the navbar to be used
34+
NAVBAR_URL="https://raw.githubusercontent.com/TuringLang/turinglang.github.io/main/assets/scripts/TuringNavbar.html"
35+
36+
# Update all HTML files in the current directory (gh-pages root)
37+
./insert_navbar.sh . $NAVBAR_URL
38+
39+
# Remove the insert_navbar.sh file
40+
rm insert_navbar.sh
41+
42+
# Check if there are any changes
43+
if [[ -n $(git status -s) ]]; then
44+
git add .
45+
git commit -m "Added navbar and removed insert_navbar.sh"
46+
git push "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" gh-pages
47+
else
48+
echo "No changes to commit"
49+
fi

Project.toml

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

55
[deps]
6+
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
67
AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001"
78
AbstractPPL = "7a57a42e-76ec-4ea3-a279-07e840d6d9cf"
9+
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
810
BangBang = "198e06fe-97b7-11e9-32a5-e1d131e6ad66"
911
Bijectors = "76274a88-744f-5084-9051-94815aaf08c4"
1012
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
@@ -14,51 +16,61 @@ Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1416
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
1517
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1618
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
19+
LogDensityProblemsAD = "996a588d-648d-4e1f-a8f0-a84b347e47b1"
1720
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
1821
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
1922
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2023
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
21-
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
2224
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2325
ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"
2426

2527
[weakdeps]
2628
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
2729
EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869"
30+
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
2831
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
32+
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
2933
ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"
3034

3135
[extensions]
3236
DynamicPPLChainRulesCoreExt = ["ChainRulesCore"]
3337
DynamicPPLEnzymeCoreExt = ["EnzymeCore"]
38+
DynamicPPLForwardDiffExt = ["ForwardDiff"]
3439
DynamicPPLMCMCChainsExt = ["MCMCChains"]
40+
DynamicPPLReverseDiffExt = ["ReverseDiff"]
3541
DynamicPPLZygoteRulesExt = ["ZygoteRules"]
3642

3743
[compat]
44+
ADTypes = "1"
3845
AbstractMCMC = "5"
39-
AbstractPPL = "0.7"
40-
BangBang = "0.3"
41-
Bijectors = "0.13"
46+
AbstractPPL = "0.8.4"
47+
Accessors = "0.1"
48+
BangBang = "0.4.1"
49+
Bijectors = "0.13.9"
4250
ChainRulesCore = "1"
4351
Compat = "4"
4452
ConstructionBase = "1.5.4"
4553
Distributions = "0.25"
4654
DocStringExtensions = "0.9"
47-
EnzymeCore = "0.6"
55+
EnzymeCore = "0.6, 0.7"
56+
ForwardDiff = "0.10"
57+
LinearAlgebra = "1.6"
4858
LogDensityProblems = "2"
59+
LogDensityProblemsAD = "1.7.0"
4960
MCMCChains = "6"
5061
MacroTools = "0.5.6"
5162
OrderedCollections = "1"
52-
Requires = "1"
53-
Setfield = "1"
54-
ZygoteRules = "0.2"
55-
LinearAlgebra = "1.6"
5663
Random = "1.6"
64+
Requires = "1"
65+
ReverseDiff = "1"
5766
Test = "1.6"
67+
ZygoteRules = "0.2"
5868
julia = "1.6"
5969

6070
[extras]
6171
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
6272
EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869"
6373
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
6474
ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"
75+
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
76+
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"

docs/Project.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
[deps]
2+
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
23
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
34
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
45
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
56
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
67
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
78
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
89
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
9-
MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54"
10-
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
1110
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
1211

1312
[compat]
13+
Accessors = "0.1"
1414
DataStructures = "0.18"
1515
Distributions = "0.25"
1616
Documenter = "1"
1717
FillArrays = "0.13, 1"
1818
ForwardDiff = "0.10"
1919
LogDensityProblems = "2"
2020
MCMCChains = "5, 6"
21-
MLUtils = "0.3, 0.4"
22-
Setfield = "0.7.1, 0.8, 1"
2321
StableRNGs = "1"

docs/make.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ DocMeta.setdocmeta!(DynamicPPL, :DocTestSetup, :(using DynamicPPL); recursive=tr
1414

1515
makedocs(;
1616
sitename="DynamicPPL",
17-
format=Documenter.HTML(),
17+
# The API index.html page is fairly large, and violates the default HTML page size
18+
# threshold of 200KiB, so we double that.
19+
format=Documenter.HTML(; size_threshold=2^10 * 400),
1820
modules=[DynamicPPL],
1921
pages=[
2022
"Home" => "index.md",

docs/src/api.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ Sometimes it can be useful to extract the priors of a model. This is the possibl
143143
extract_priors
144144
```
145145

146+
Safe extraction of values from a given [`AbstractVarInfo`](@ref) as they are seen in the model can be done using [`values_as_in_model`](@ref).
147+
148+
```@docs
149+
values_as_in_model
150+
```
151+
146152
```@docs
147153
NamedDist
148154
```
@@ -187,6 +193,21 @@ DynamicPPL.TestUtils.update_values!!
187193
DynamicPPL.TestUtils.test_values
188194
```
189195

196+
## Debugging Utilities
197+
198+
DynamicPPL provides a few methods for checking validity of a model-definition.
199+
200+
```@docs
201+
check_model
202+
check_model_and_trace
203+
```
204+
205+
And some which might be useful to determine certain properties of the model based on the debug trace.
206+
207+
```@docs
208+
DynamicPPL.has_static_constraints
209+
```
210+
190211
## Advanced
191212

192213
### Variable names

docs/src/internals/transformations.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ For certain inference methods, it's necessary / much more convenient to work wit
2121

2222
We write "unconstrained" with quotes because there are many ways to transform a constrained variable to an unconstrained one, *and* DynamicPPL can work with a much broader class of bijective transformations of variables, not just ones that go to the entire real line. But for MCMC, unconstraining is the most common transformation so we'll stick with that terminology.
2323

24-
For a large family of constraints encoucntered in practice, it is indeed possible to transform a (partially) contrained model to a completely unconstrained one in such a way that sampling in the unconstrained space is equivalent to sampling in the constrained space.
24+
For a large family of constraints encountered in practice, it is indeed possible to transform a (partially) constrained model to a completely unconstrained one in such a way that sampling in the unconstrained space is equivalent to sampling in the constrained space.
2525

2626
In DynamicPPL.jl, this is often referred to as *linking* (a term originating in the statistics literature) and is done using transformations from [Bijectors.jl](https://github.com/TuringLang/Bijectors.jl).
2727

28-
For example, the above model could be transformed into (the following psuedo-code; it's not working code):
28+
For example, the above model could be transformed into (the following pseudo-code; it's not working code):
2929

3030
```julia
3131
@model function demo()
@@ -37,7 +37,7 @@ end
3737

3838
Here `log_s` is an unconstrained variable, and `s` is a constrained variable that is a deterministic function of `log_s`.
3939

40-
But to ensure that we stay consistent with what the user expects, DynamicPPL.jl does not actually transform the model as above, but can instead makes use of transformed variables internally to achieve the same effect, when desired.
40+
But to ensure that we stay consistent with what the user expects, DynamicPPL.jl does not actually transform the model as above, but instead makes use of transformed variables internally to achieve the same effect, when desired.
4141

4242
In the end, we'll end up with something that looks like this:
4343

@@ -55,7 +55,7 @@ There are two aspects to transforming from the internal representation of a vari
5555

5656
1. Different implementations of [`AbstractVarInfo`](@ref) represent realizations of a model in different ways internally, so we need to transform from this internal representation to the desired representation in the model. For example,
5757

58-
+ [`VarInfo`](@ref) represents a realization of a model as in a "flattened" / vector representation, regardless of form of the variable in the model.
58+
+ [`VarInfo`](@ref) represents a realization of a model as a "flattened" / vector representation, regardless of the form of the variable in the model.
5959
+ [`SimpleVarInfo`](@ref) represents a realization of a model exactly as in the model (unless it has been transformed; we'll get to that later).
6060

6161
2. We need the ability to transform from "constrained space" to "unconstrained space", as we saw in the previous section.
@@ -91,7 +91,7 @@ DynamicPPL.to_internal_transform
9191
DynamicPPL.from_internal_transform
9292
```
9393

94-
These methods allows us to extract the internal-to-model transformation function depending on the `varinfo`, the variable, and the distribution of the variable:
94+
These methods allow us to extract the internal-to-model transformation function depending on the `varinfo`, the variable, and the distribution of the variable:
9595

9696
- `varinfo` + `vn` defines the internal representation of the variable.
9797
- `dist` defines the representation expected within the model scope.
@@ -214,7 +214,7 @@ Unfortunately, this is not possible in general. Consider for example the followi
214214
end
215215
```
216216

217-
Here the variable `x` has is constrained to be on the domain `(m, Inf)`, where `m` is sampled according to a `Normal`.
217+
Here the variable `x` is constrained to be in the domain `(m, Inf)`, where `m` is sampled according to a `Normal`.
218218

219219
```@example transformations-internal
220220
model = demo_dynamic_constraint()
@@ -263,7 +263,7 @@ we see that we indeed satisfy the constraint `m < x`, as desired.
263263

264264
The reason for this is that internally in a model evaluation, we construct the transformation from the internal to the model representation based on the *current* realizations in the model! That is, we take the `dist` in a `x ~ dist` expression _at model evaluation time_ and use that to construct the transformation, thus allowing it to change between model evaluations without invalidating the transformation.
265265

266-
But to be able to do this, we need to know whether the variable is linked / "unconstrained" or not, since the transformation is different in the two cases. Hence we need to be able to determine this at model evaluation time. Hence the the internals end up looking something like this:
266+
But to be able to do this, we need to know whether the variable is linked / "unconstrained" or not, since the transformation is different in the two cases. Hence we need to be able to determine this at model evaluation time. Hence the internals end up looking something like this:
267267

268268
```julia
269269
if istrans(varinfo, varname)

docs/src/tutorials/prob-interface.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,28 @@ To give an example of the probability interface in use, we can use it to estimat
107107
In cross-validation, we split the dataset into several equal parts.
108108
Then, we choose one of these sets to serve as the validation set.
109109
Here, we measure fit using the cross entropy (Bayes loss).[^1]
110+
(For the sake of simplicity, in the following code, we enforce that `nfolds` must divide the number of data points. For a more competent implementation, see [MLUtils.jl](https://juliaml.github.io/MLUtils.jl/dev/api/#MLUtils.kfolds).)
110111

111112
```@example probinterface
112-
using MLUtils
113+
# Calculate the train/validation splits across `nfolds` partitions, assume `length(dataset)` divides `nfolds`
114+
function kfolds(dataset::Array{<:Real}, nfolds::Int)
115+
fold_size, remaining = divrem(length(dataset), nfolds)
116+
if remaining != 0
117+
error("The number of folds must divide the number of data points.")
118+
end
119+
first_idx = firstindex(dataset)
120+
last_idx = lastindex(dataset)
121+
splits = map(0:(nfolds - 1)) do i
122+
start_idx = first_idx + i * fold_size
123+
end_idx = start_idx + fold_size
124+
train_set_indices = [first_idx:(start_idx - 1); end_idx:last_idx]
125+
return (view(dataset, train_set_indices), view(dataset, start_idx:(end_idx - 1)))
126+
end
127+
return splits
128+
end
113129
114130
function cross_val(
115-
dataset::AbstractVector{<:Real};
131+
dataset::Vector{<:Real};
116132
nfolds::Int=5,
117133
nsamples::Int=1_000,
118134
rng::Random.AbstractRNG=Random.default_rng(),

ext/DynamicPPLForwardDiffExt.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module DynamicPPLForwardDiffExt
2+
3+
if isdefined(Base, :get_extension)
4+
using DynamicPPL: ADTypes, DynamicPPL, LogDensityProblems, LogDensityProblemsAD
5+
using ForwardDiff
6+
else
7+
using ..DynamicPPL: ADTypes, DynamicPPL, LogDensityProblems, LogDensityProblemsAD
8+
using ..ForwardDiff
9+
end
10+
11+
getchunksize(::ADTypes.AutoForwardDiff{chunk}) where {chunk} = chunk
12+
13+
standardtag(::ADTypes.AutoForwardDiff{<:Any,Nothing}) = true
14+
standardtag(::ADTypes.AutoForwardDiff) = false
15+
16+
function LogDensityProblemsAD.ADgradient(
17+
ad::ADTypes.AutoForwardDiff, ℓ::DynamicPPL.LogDensityFunction
18+
)
19+
θ = DynamicPPL.getparams(ℓ)
20+
f = Base.Fix1(LogDensityProblems.logdensity, ℓ)
21+
22+
# Define configuration for ForwardDiff.
23+
tag = if standardtag(ad)
24+
ForwardDiff.Tag(DynamicPPL.DynamicPPLTag(), eltype(θ))
25+
else
26+
ForwardDiff.Tag(f, eltype(θ))
27+
end
28+
chunk_size = getchunksize(ad)
29+
chunk = if chunk_size == 0 || chunk_size === nothing
30+
ForwardDiff.Chunk(θ)
31+
else
32+
ForwardDiff.Chunk(length(θ), chunk_size)
33+
end
34+
35+
return LogDensityProblemsAD.ADgradient(Val(:ForwardDiff), ℓ; chunk, tag, x=θ)
36+
end
37+
38+
# Allow Turing tag in gradient etc. calls of the log density function
39+
function ForwardDiff.checktag(
40+
::Type{ForwardDiff.Tag{DynamicPPL.DynamicPPLTag,V}},
41+
::DynamicPPL.LogDensityFunction,
42+
::AbstractArray{W},
43+
) where {V,W}
44+
return true
45+
end
46+
function ForwardDiff.checktag(
47+
::Type{ForwardDiff.Tag{DynamicPPL.DynamicPPLTag,V}},
48+
::Base.Fix1{typeof(LogDensityProblems.logdensity),<:DynamicPPL.LogDensityFunction},
49+
::AbstractArray{W},
50+
) where {V,W}
51+
return true
52+
end
53+
54+
end # module

ext/DynamicPPLReverseDiffExt.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module DynamicPPLReverseDiffExt
2+
3+
if isdefined(Base, :get_extension)
4+
using DynamicPPL: ADTypes, DynamicPPL, LogDensityProblems, LogDensityProblemsAD
5+
using ReverseDiff
6+
else
7+
using ..DynamicPPL: ADTypes, DynamicPPL, LogDensityProblems, LogDensityProblemsAD
8+
using ..ReverseDiff
9+
end
10+
11+
function LogDensityProblemsAD.ADgradient(
12+
ad::ADTypes.AutoReverseDiff{Tcompile}, ℓ::DynamicPPL.LogDensityFunction
13+
) where {Tcompile}
14+
return LogDensityProblemsAD.ADgradient(
15+
Val(:ReverseDiff),
16+
ℓ;
17+
compile=Val(Tcompile),
18+
# `getparams` can return `Vector{Real}`, in which case, `ReverseDiff` will initialize the gradients to Integer 0
19+
# because at https://github.com/JuliaDiff/ReverseDiff.jl/blob/c982cde5494fc166965a9d04691f390d9e3073fd/src/tracked.jl#L473
20+
# `zero(D)` will return 0 when D is Real.
21+
# here we use `identity` to possibly concretize the type to `Vector{Float64}` in the case of `Vector{Real}`.
22+
x=map(identity, DynamicPPL.getparams(ℓ)),
23+
)
24+
end
25+
26+
end # module

0 commit comments

Comments
 (0)