Skip to content

Commit

Permalink
Merge c439885 into a7902a3
Browse files Browse the repository at this point in the history
  • Loading branch information
phipsgabler committed Nov 8, 2021
2 parents a7902a3 + c439885 commit bffed08
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 20 deletions.
4 changes: 3 additions & 1 deletion Project.toml
Expand Up @@ -3,13 +3,15 @@ uuid = "7a57a42e-76ec-4ea3-a279-07e840d6d9cf"
keywords = ["probablistic programming"]
license = "MIT"
desc = "Common interfaces for probabilistic programming"
version = "0.3.1"
version = "0.4"

[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"
43 changes: 29 additions & 14 deletions interface.md
Expand Up @@ -24,12 +24,14 @@ There are three interrelating aspects that this interface intends to standardize
- Sampling
- “Conversions” between different conditionings of models

Therefore, the interface consists of:
Therefore, the interface consists of an `AbstractProbabilisticProgram` supertype, together with
functions

- `condition(::Model, ::Trace) -> ConditionedModel`
- `decondition(::ConditionedModel) -> GenerativeModel`
- `sample(::Model, ::Sampler = Exact(), [Int])` (from `AbstractMCMC.sample`)
- `logdensity(::Model, ::Trace)`
- `logdensityof(::Model, ::Trace)` and `density(::Model, ::Trace)` (from
[DensityInterface.jl](https://github.com/JuliaMath/DensityInterface.jl))


### Traces & probability expressions
Expand Down Expand Up @@ -198,32 +200,45 @@ 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 main 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.
DensityInterface.jl also requires the trait function `hasdensity`, which is set to `true` for the
`AbstractProbabilisticProgram` type. Additional functions

The evaluation will usually work with the internal, concrete trace type, like `VarInfo` in Turing.jl:
```
DensityInterface.densityof(d, x) = exp(logdensityof(d, x))
DensityInterface.logdensity(d) = Base.Fix1(logdensity, d)
```

are provided automatically.

Note that `logdensityof` strictly generalizes `logpdf`, since the posterior density will of course
in general be 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
Expand All @@ -232,15 +247,15 @@ 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
distinguished? This could be done by dispatch as well, e.g., if the caller wants to make sure
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
Expand Down
2 changes: 1 addition & 1 deletion src/AbstractPPL.jl
Expand Up @@ -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, densityof


# Abstract traces
Expand Down
11 changes: 7 additions & 4 deletions src/abstractprobprog.jl
@@ -1,4 +1,5 @@
using AbstractMCMC
using DensityInterface


"""
Expand All @@ -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


"""
Expand Down

0 comments on commit bffed08

Please sign in to comment.