Trait-based interface for mathematical/statistical densities and objects associated with a density.

This package defines an interface for mathematical/statistical densities and objects associated with a density in Julia. The interface comprises the type DensityKind and the functions logdensityof/densityof[1] and logfuncdensity/funcdensity.

The following methods must be provided to make a type (e.g. SomeDensity) compatible with the interface:

import DensityInterface

@inline DensityInterface.DensityKind(::SomeDensity) = IsDensity()
DensityInterface.logdensityof(object::SomeDensity, x) = log_of_d_at(x)

object = SomeDensity()
DensityInterface.logdensityof(object, x) isa Real

# output


object may be/represent a density itself (DensityKind(object) === IsDensity()) or it may be something that can be said to have a density (DensityKind(object) === HasDensity())[2].

In statistical inference applications, for example, object might be a likelihood, prior or posterior.

DensityInterface automatically provides logdensityof(object), equivalent to x -> logdensityof(object, x). This constitutes a convenient way of passing a (log-)density function to algorithms like optimizers, samplers, etc.:

using DensityInterface

object = SomeDensity()
log_f = logdensityof(object)
log_f(x) == logdensityof(object, x)

# output

SomeOptimizerPackage.maximize(logdensityof(object), x_init)

Reversely, a given log-density function log_f can be converted to a DensityInterface-compatible density object using logfuncdensity:

object = logfuncdensity(log_f)
DensityKind(object) === IsDensity() && logdensityof(object, x) == log_f(x)

# output

  • 1The function names logdensityof and densityof were chosen to convey that the target object may either be a density or something that can be said to have a density. They also have less naming conflict potential than logdensity and esp. density (the latter already being exported by Plots.jl).
  • 2The package Distributions supports DensityInterface for Distributions.Distribution.