diff --git a/docs/Project.toml b/docs/Project.toml index e79e44aba..f725f467a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -3,6 +3,7 @@ Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterMermaid = "a078cd44-4d9c-4618-b545-3ab9d77f9177" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c" diff --git a/docs/make.jl b/docs/make.jl index ebf15df06..b0168076d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -8,6 +8,7 @@ using DynamicPPL: AbstractPPL # in the doctest as run in `test/runtests.jl`, and so we need to stay # consistent with that. using Distributions +using DocumenterMermaid # Doctest setup DocMeta.setdocmeta!(DynamicPPL, :DocTestSetup, :(using DynamicPPL); recursive=true) diff --git a/docs/src/assets/images/transformations-assume-without-istrans.dot b/docs/src/assets/images/transformations-assume-without-istrans.dot deleted file mode 100644 index 6eb6865c3..000000000 --- a/docs/src/assets/images/transformations-assume-without-istrans.dot +++ /dev/null @@ -1,17 +0,0 @@ -digraph { - # `assume` block - subgraph cluster_assume { - label = "assume"; - fontname = "Courier"; - - assume [shape=box, label=< assume(varinfo, @varname(x), Normal())>, fontname="Courier"]; - without_linking_assume [shape=box, label="f = from_internal_transform(varinfo, varname, dist)", fontname="Courier"]; - with_logabsdetjac [shape=box, label="x, logjac = with_logabsdet_jacobian(f, assume_internal(varinfo, varname, dist))", fontname="Courier"]; - return_assume [shape=box, label=< return x, logpdf(dist, x) - logjac, varinfo >, style=dashed, fontname="Courier"]; - - assume -> without_linking_assume; - without_linking_assume -> with_logabsdetjac; - with_logabsdetjac -> return_assume; - } -} - diff --git a/docs/src/assets/images/transformations-assume-without-istrans.dot.png b/docs/src/assets/images/transformations-assume-without-istrans.dot.png deleted file mode 100644 index f58727ad2..000000000 Binary files a/docs/src/assets/images/transformations-assume-without-istrans.dot.png and /dev/null differ diff --git a/docs/src/assets/images/transformations-assume-without-istrans.dot.svg b/docs/src/assets/images/transformations-assume-without-istrans.dot.svg deleted file mode 100644 index be91de2ad..000000000 --- a/docs/src/assets/images/transformations-assume-without-istrans.dot.svg +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - -%3 - - - -tilde_node - -x ~ Normal() - - - -base_node - - varname = -@varname -(x) -dist = Normal() -x, varinfo = ... - - - -tilde_node->base_node - - -   -@model - - - -assume - -assume(varname, dist, varinfo) - - - -base_node->assume - - -  tilde-pipeline - - - -without_linking - -f = from_internal_transform(varinfo, varname, dist) - - - -assume->without_linking - - - - - -with_logabsdetjac - -x, logjac = with_logabsdet_jacobian(f, getindex_internal(varinfo, varname, dist)) - - - -without_linking->with_logabsdetjac - - - - - -return - - -return - x, logpdf(dist, x) - logjac, varinfo - - - -with_logabsdetjac->return - - - - - diff --git a/docs/src/assets/images/transformations-assume.dot b/docs/src/assets/images/transformations-assume.dot deleted file mode 100644 index f1952b63f..000000000 --- a/docs/src/assets/images/transformations-assume.dot +++ /dev/null @@ -1,22 +0,0 @@ -digraph { - # `assume` block - subgraph cluster_assume { - label = "assume"; - fontname = "Courier"; - - assume [shape=box, label=< assume(varinfo, @varname(x), Normal())>, fontname="Courier"]; - iflinked_assume [label=< if istrans(varinfo, varname) >, fontname="Courier"]; - without_linking_assume [shape=box, label="f = from_internal_transform(varinfo, varname, dist)", fontname="Courier"]; - with_linking_assume [shape=box, label="f = from_linked_internal_transform(varinfo, varname, dist)", fontname="Courier"]; - with_logabsdetjac [shape=box, label="x, logjac = with_logabsdet_jacobian(f, assume_internal(varinfo, varname, dist))", fontname="Courier"]; - return_assume [shape=box, label=< return x, logpdf(dist, x) - logjac, varinfo >, style=dashed, fontname="Courier"]; - - assume -> iflinked_assume; - iflinked_assume -> without_linking_assume [label=< false>, fontname="Courier"]; - iflinked_assume -> with_linking_assume [label=< true>, fontname="Courier"]; - without_linking_assume -> with_logabsdetjac; - with_linking_assume -> with_logabsdetjac; - with_logabsdetjac -> return_assume; - } -} - diff --git a/docs/src/assets/images/transformations-assume.dot.png b/docs/src/assets/images/transformations-assume.dot.png deleted file mode 100644 index b8b0ec734..000000000 Binary files a/docs/src/assets/images/transformations-assume.dot.png and /dev/null differ diff --git a/docs/src/assets/images/transformations-getindex-with-dist.dot b/docs/src/assets/images/transformations-getindex-with-dist.dot deleted file mode 100644 index e44fc0ce6..000000000 --- a/docs/src/assets/images/transformations-getindex-with-dist.dot +++ /dev/null @@ -1,20 +0,0 @@ -digraph { - # `getindex` block - subgraph cluster_getindex { - label = "getindex"; - fontname = "Courier"; - - getindex [shape=box, label=< x = getindex(varinfo, @varname(x), Normal()) >, fontname="Courier"]; - iflinked_getindex [label=< if istrans(varinfo, varname) >, fontname="Courier"]; - without_linking_getindex [shape=box, label="f = from_internal_transform(varinfo, varname, dist)", fontname="Courier"]; - with_linking_getindex [shape=box, label="f = from_linked_internal_transform(varinfo, varname, dist)", fontname="Courier"]; - return_getindex [shape=box, label=< return f(getindex_internal(varinfo, varname)) >, style=dashed, fontname="Courier"]; - - getindex -> iflinked_getindex; - iflinked_getindex -> without_linking_getindex [label=< false>, fontname="Courier"]; - iflinked_getindex -> with_linking_getindex [label=< true>, fontname="Courier"]; - without_linking_getindex -> return_getindex; - with_linking_getindex -> return_getindex; - } -} - diff --git a/docs/src/assets/images/transformations-getindex-with-dist.dot.png b/docs/src/assets/images/transformations-getindex-with-dist.dot.png deleted file mode 100644 index 381ba45a2..000000000 Binary files a/docs/src/assets/images/transformations-getindex-with-dist.dot.png and /dev/null differ diff --git a/docs/src/assets/images/transformations-getindex-without-dist.dot b/docs/src/assets/images/transformations-getindex-without-dist.dot deleted file mode 100644 index 38dd296e1..000000000 --- a/docs/src/assets/images/transformations-getindex-without-dist.dot +++ /dev/null @@ -1,20 +0,0 @@ -digraph { - # `getindex` block - subgraph cluster_getindex { - label = "getindex"; - fontname = "Courier"; - - getindex [shape=box, label=< x = getindex(varinfo, @varname(x)) >, fontname="Courier"]; - iflinked_getindex [label=< if istrans(varinfo, varname) >, fontname="Courier"]; - without_linking_getindex [shape=box, label="f = from_internal_transform(varinfo, varname)", fontname="Courier"]; - with_linking_getindex [shape=box, label="f = from_linked_internal_transform(varinfo, varname)", fontname="Courier"]; - return_getindex [shape=box, label=< return f(getindex_internal(varinfo, varname)) >, style=dashed, fontname="Courier"]; - - getindex -> iflinked_getindex; - iflinked_getindex -> without_linking_getindex [label=< false>, fontname="Courier"]; - iflinked_getindex -> with_linking_getindex [label=< true>, fontname="Courier"]; - without_linking_getindex -> return_getindex; - with_linking_getindex -> return_getindex; - } -} - diff --git a/docs/src/assets/images/transformations-getindex-without-dist.dot.png b/docs/src/assets/images/transformations-getindex-without-dist.dot.png deleted file mode 100644 index a869326d3..000000000 Binary files a/docs/src/assets/images/transformations-getindex-without-dist.dot.png and /dev/null differ diff --git a/docs/src/assets/images/transformations.dot b/docs/src/assets/images/transformations.dot deleted file mode 100644 index 2ca40ddd0..000000000 --- a/docs/src/assets/images/transformations.dot +++ /dev/null @@ -1,28 +0,0 @@ -digraph { - # Nodes. - tilde_node [shape=box, label="x ~ Normal()", fontname="Courier"]; - base_node [shape=box, label=< vn = @varname(x)
dist = Normal()
x, vi = ... >, fontname="Courier"]; - assume [shape=box, label="assume(vn, dist, vi)", fontname="Courier"]; - - iflinked [label=< if istrans(vi, vn) >, fontname="Courier"]; - - without_linking [shape=box, label="f = from_internal_transform(vi, vn, dist)", styled=dashed, fontname="Courier"]; - with_linking [shape=box, label="f = from_linked_internal_transform(vi, vn, dist)", styled=dashed, fontname="Courier"]; - - with_logabsdetjac [shape=box, label="x, logjac = with_logabsdet_jacobian(f, getindex_internal(vi, vn, dist))", styled=dashed, fontname="Courier"]; - return [shape=box, label=< return x, logpdf(dist, x) - logjac, vi >, styled=dashed, fontname="Courier"]; - - # Edges. - tilde_node -> base_node [style=dashed, label=< @model>, fontname="Courier"] - base_node -> assume [style=dashed, label=" tilde-pipeline", fontname="Courier"]; - - assume -> iflinked; - - iflinked -> without_linking [label=< false>, fontname="Courier"]; - iflinked -> with_linking [label=< true>, fontname="Courier"]; - - without_linking -> with_logabsdetjac; - with_linking -> with_logabsdetjac; - - with_logabsdetjac -> return; -} diff --git a/docs/src/assets/images/transformations.dot.png b/docs/src/assets/images/transformations.dot.png deleted file mode 100644 index 1343a81e7..000000000 Binary files a/docs/src/assets/images/transformations.dot.png and /dev/null differ diff --git a/docs/src/assets/images/transformations.dot.svg b/docs/src/assets/images/transformations.dot.svg deleted file mode 100644 index 1e98f612d..000000000 --- a/docs/src/assets/images/transformations.dot.svg +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - -%3 - - - -tilde_node - -x ~ Normal() - - - -base_node - - vn = -@varname -(x) -dist = Normal() -x, vi = ... - - - -tilde_node->base_node - - -   -@model - - - -assume - -assume(vn, dist, vi) - - - -base_node->assume - - -  tilde-pipeline - - - -iflinked - - -if - istrans(vi, vn) - - - -assume->iflinked - - - - - -without_linking - -f = from_internal_transform(vi, vn, dist) - - - -iflinked->without_linking - - -   -false - - - -with_linking - -f = from_linked_internal_transform(vi, vn, dist) - - - -iflinked->with_linking - - -   -true - - - -with_logabsdetjac - -x, logjac = with_logabsdet_jacobian(f, getindex_internal(vi, vn, dist)) - - - -without_linking->with_logabsdetjac - - - - - -with_linking->with_logabsdetjac - - - - - -return - - -return - x, logpdf(dist, x) - logjac, vi - - - -with_logabsdetjac->return - - - - - diff --git a/docs/src/internals/transformations.md b/docs/src/internals/transformations.md index d948290ec..ae629dbd6 100644 --- a/docs/src/internals/transformations.md +++ b/docs/src/internals/transformations.md @@ -41,10 +41,35 @@ But to ensure that we stay consistent with what the user expects, DynamicPPL.jl In the end, we'll end up with something that looks like this: -```@raw html -
- -
+```mermaid +%%{ init: { 'themeVariables': { 'lineColor': '#000000' } } }%% +%%{ init: { 'flowchart': { 'curve': 'linear' } } }%% +graph TD + subgraph assume ["assume"] + style assume fill:#ffffff,font-family:Courier + + A["x ~ Normal()"]:::boxStyle + B["vn = @varname(x)
dist = Normal()
x, vi = ..."]:::boxStyle + C["assume(vn, dist, vi)"]:::boxStyle + D(["if istrans(vi, vn)"]):::boxStyle + E["f = from_internal_transform(vi, vn, dist)"]:::boxStyle + F["f = from_linked_internal_transform(vi, vn, dist)"]:::boxStyle + G["x, logjac = with_logabsdet_jacobian(f, getindex_internal(vi, vn, dist))"]:::boxStyle + H["return x, logpdf(dist, x) - logjac, vi"]:::boxStyle + + A -.->|@model| B + B -.->|tilde-pipeline| C + C --> D + D -->|false| E + D -->|true| F + E --> G + F --> G + G --> H + end + + classDef boxStyle fill:#ffffff,stroke:#000000,font-family:Courier,color:#000000 + + linkStyle default stroke:#000000,stroke-width:1px,color:#000000 ``` Below we'll see how this is done. @@ -197,10 +222,27 @@ One might wonder why we need both `to_internal_transform` and `to_linked_interna That is, why can't we just do -```@raw html -
- -
+```mermaid +%%{ init: { 'flowchart': { 'curve': 'linear' } } }%% +%%{ init: { 'themeVariables': { 'lineColor': '#000000' } } }%% +graph TD + subgraph assume ["assume"] + style assume fill:#ffffff,font-family:Courier + + A["assume(varinfo, @varname(x), Normal())"]:::boxStyle + B["f = from_internal_transform(varinfo, varname, dist)"]:::boxStyle + C["x, logjac = with_logabsdet_jacobian(f, assume_internal(varinfo, varname, dist))"]:::boxStyle + D["return x, logpdf(dist, x) - logjac, varinfo"]:::dashedBox + + A --> B + B --> C + C --> D + end + + classDef dashedBox fill:#ffffff,stroke:#000000,stroke-dasharray: 5 5,font-family:Courier,color:#000000 + classDef boxStyle fill:#ffffff,stroke:#000000,font-family:Courier,color:#000000 + + linkStyle default stroke:#000000,stroke-width:1px,color:#000000 ``` Unfortunately, this is not possible in general. Consider for example the following model: @@ -277,10 +319,32 @@ That is, if the variable is linked / "unconstrained", we use the [`DynamicPPL.fr And so the earlier diagram becomes: -```@raw html -
- -
+```mermaid +%%{ init: { 'flowchart': { 'curve': 'linear' } } }%% +%%{ init: { 'themeVariables': { 'lineColor': '#000000' } } }%% +graph TD + subgraph assume ["assume"] + style assume fill:#ffffff,font-family:Courier + + A["assume(varinfo, @varname(x), Normal())"]:::boxStyle + B(["if istrans(varinfo, varname)"]):::boxStyle + C["f = from_internal_transform(varinfo, varname, dist)"]:::boxStyle + D["f = from_linked_internal_transform(varinfo, varname, dist)"]:::boxStyle + E["x, logjac = with_logabsdet_jacobian(f, assume_internal(varinfo, varname, dist))"]:::boxStyle + F["return x, logpdf(dist, x) - logjac, varinfo"]:::dashedBox + + A --> B + B -->|false| C + B -->|true| D + C --> E + D --> E + E --> F + end + + classDef dashedBox fill:#ffffff,stroke:#000000,stroke-dasharray: 5 5,font-family:Courier,color:#000000 + classDef boxStyle fill:#ffffff,stroke:#000000,font-family:Courier,color:#000000 + + linkStyle default stroke:#000000,stroke-width:1px,color:#000000 ``` !!! note @@ -294,18 +358,58 @@ This is also the reason why we have two definitions of `getindex`: For `getindex` we have the following diagram: -```@raw html -
- -
+```mermaid +%%{ init: { 'flowchart': { 'curve': 'linear' } } }%% +%%{ init: { 'themeVariables': { 'lineColor': '#000000' } } }%% +graph TD + subgraph getindex ["getindex"] + style getindex fill:#ffffff,font-family:Courier + + A["x = getindex(varinfo, @varname(x), Normal())"]:::boxStyle + B(["if istrans(varinfo, varname)"]):::boxStyle + C["f = from_internal_transform(varinfo, varname, dist)"]:::boxStyle + D["f = from_linked_internal_transform(varinfo, varname, dist)"]:::boxStyle + E["return f(getindex_internal(varinfo, varname))"]:::dashedBox + + A --> B + B -->|false| C + B -->|true| D + C --> E + D --> E + end + + classDef dashedBox fill:#ffffff,stroke:#000000,stroke-dasharray: 5 5,font-family:Courier,color:#000000 + classDef boxStyle fill:#ffffff,stroke:#000000,font-family:Courier,color:#000000 + + linkStyle default stroke:#000000,stroke-width:1px,color:#000000 ``` While if `dist` is not provided, we have: -```@raw html -
- -
+```mermaid +%%{ init: { 'flowchart': { 'curve': 'linear' } } }%% +%%{ init: { 'themeVariables': { 'lineColor': '#000000' } } }%% +graph TD + subgraph getindex ["getindex"] + style getindex fill:#ffffff,font-family:Courier + + A["x = getindex(varinfo, @varname(x))"]:::boxStyle + B(["if istrans(varinfo, varname)"]):::boxStyle + C["f = from_internal_transform(varinfo, varname)"]:::boxStyle + D["f = from_linked_internal_transform(varinfo, varname)"]:::boxStyle + E["return f(getindex_internal(varinfo, varname))"]:::dashedBox + + A --> B + B -->|false| C + B -->|true| D + C --> E + D --> E + end + + classDef dashedBox fill:#ffffff,stroke:#000000,stroke-dasharray: 5 5,font-family:Courier,color:#000000 + classDef boxStyle fill:#ffffff,stroke:#000000,font-family:Courier,color:#000000 + + linkStyle default stroke:#000000,stroke-width:1px,color:#000000 ``` Notice that `dist` is not present here, but otherwise the diagrams are the same.