diff --git a/Project.toml b/Project.toml index c9166ce..a0fa93b 100644 --- a/Project.toml +++ b/Project.toml @@ -7,9 +7,11 @@ version = "0.3.1" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001" +DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" [compat] AbstractMCMC = "2, 3" +DensityInterface = "0.3" Setfield = "0.7.1, 0.8" julia = "1" diff --git a/interface.md b/interface.md index 239585b..42e9974 100644 --- a/interface.md +++ b/interface.md @@ -29,7 +29,7 @@ Therefore, the interface consists of: - `condition(::Model, ::Trace) -> ConditionedModel` - `decondition(::ConditionedModel) -> GenerativeModel` - `sample(::Model, ::Sampler = Exact(), [Int])` (from `AbstractMCMC.sample`) -- `logdensity(::Model, ::Trace)` +- `DensityInterface.logdensityof(::Model, ::Trace)` ### Traces & probability expressions @@ -198,13 +198,15 @@ Not all variants need to be supported – for example, a posterior model might n model. -### Density Calculation +### Density Evaluation Since the different “versions” of how a model is to be understood as generative or conditioned are to be expressed in the type or dispatch they support, there should be no need for separate functions -`logjoint`, `loglikelihood`, etc., which force these semantic distinctions on the implementor; one -`logdensity` should suffice for all, with the distinction being made by the capabilities of the -concrete model instance. +`logjoint`, `loglikelihood`, etc., which force these semantic distinctions on the implementor; we +therefore adapt the interface of +[DensityInterface.jl](https://github.com/JuliaMath/DensityInterface.jl). Its one function +`logdensityof` should suffice for variants, with the distinction being made by the capabilities of +the concrete model instance. Note that this generalizes `logpdf`, too, since the posterior density will of course in general be unnormalized and hence not a probability density. @@ -212,18 +214,18 @@ unnormalized and hence not a probability density. The evaluation will usually work with the internal, concrete trace type, like `VarInfo` in Turing.jl: ```julia -logdensity(m, vi) +logdensityof(m, vi) ``` But the user will more likely work on the interface using probability expressions: ```julia -logdensity(m, @T(X = ...)) +logdensityof(m, @T(X = ...)) ``` (Note that this would replace the current `prob` string macro in Turing.jl.) -Densities need not be normalized. +Densities need (and usually, will) not be normalized. #### Implementation notes @@ -232,7 +234,7 @@ It should be able to make this fall back on the internal method with the right d implementation of `maketrace`: ```julia -logdensity(m, t::ProbabilityExpression) = logdensity(m, maketrace(m, t)) +logdensityof(m, t::ProbabilityExpression) = logdensityof(m, maketrace(m, t)) ``` There is one open question – should normalized and unnormalized densities be able to be @@ -240,7 +242,7 @@ distinguished? This could be done by dispatch as well, e.g., if the caller want normalization: ``` -logdensity(g, @T(X = ..., Y = ..., Z = ...); normalized=Val{true}) +logdensityof(g, @T(X = ..., Y = ..., Z = ...); normalized=Val{true}) ``` Although there is proably a better way through traits; maybe like for arrays, with diff --git a/src/AbstractPPL.jl b/src/AbstractPPL.jl index 7a79c53..ae50327 100644 --- a/src/AbstractPPL.jl +++ b/src/AbstractPPL.jl @@ -5,7 +5,7 @@ export VarName, getsym, getindexing, getlens, inspace, subsumes, varname, vsym, # Abstract model functions -export AbstractProbabilisticProgram, condition, decondition, logdensity +export AbstractProbabilisticProgram, condition, decondition, logdensityof # Abstract traces diff --git a/src/abstractprobprog.jl b/src/abstractprobprog.jl index c21ec00..f71d437 100644 --- a/src/abstractprobprog.jl +++ b/src/abstractprobprog.jl @@ -1,4 +1,5 @@ using AbstractMCMC +using DensityInterface """ @@ -8,19 +9,21 @@ Common base type for models expressed as probabilistic programs. """ abstract type AbstractProbabilisticProgram <: AbstractMCMC.AbstractModel end +DensityInterface.hasdensity(::AbstractProbabilisticProgram) = true + """ - logdensity(model, trace) + logdensityof(model, trace) Evaluate the (possibly unnormalized) density of the model specified by the probabilistic program in `model`, at specific values for the random variables given through `trace`. `trace` can be of any supported internal trace type, or a fixed probability expression. -`logdensity` should interact with conditioning and deconditioning in the way required by probability -theory. +`logdensityof` should interact with conditioning and deconditioning in the way required by +probability theory. """ -function logdensity end +DensityInterface.logdensityof """