Usage with distributions

Bijectors provides many utilities for working with probability distributions.

using Bijectors

dist = LogNormal()
x = rand(dist)
b = bijector(dist)  # bijection (0, ∞) → ℝ

y = b(x)
1.0911565677233277

Here, bijector(d::Distribution) returns the corresponding constrained-to-unconstrained bijection for Beta, which is a log function. The resulting bijector can be called, just like any other function, to transform samples from the distribution to the unconstrained space.

The function link provides a short way of doing the above:

link(dist, x) ≈ b(x)
true

See the Turing.jl docs for more information about how this is used in probabilistic programming.

Transforming distributions

We can also couple a distribution together with its bijector to create a transformed Distribution, i.e. a Distribution defined by sampling from a given Distribution and then transforming using a given transformation:

dist = LogNormal()          # support on (0, ∞)
tdist = transformed(dist)   # support on ℝ
UnivariateTransformed{LogNormal{Float64}, Base.Fix1{typeof(broadcast), typeof(log)}}(
dist: LogNormal{Float64}(μ=0.0, σ=1.0)
transform: Base.Fix1{typeof(broadcast), typeof(log)}(broadcast, log)
)

We can then sample from, and compute the logpdf for, the resulting distribution:

y = rand(tdist)
1.7542258572904934
logpdf(tdist, y)
-2.4575927123979557

We should expect here that

logpdf(tdist, y) ≈ logpdf(dist, x) - logabsdetjac(b, x)

where b = bijector(dist) and y = b(x).

To verify this, we can calculate the value of x using the inverse bijector:

b = bijector(dist)
binv = inverse(b)

x = binv(y)
5.778972260605668

(Because b is just a log function, binv is an exponential function, i.e. x = exp(y).)

Then we can check the equality:

logpdf(tdist, y) ≈ logpdf(dist, x) - logabsdetjac(b, x)
true

You can also use Bijectors.logpdf_with_trans with the original distribution:

logpdf_with_trans(dist, x, false) ≈ logpdf(dist, x)
true
logpdf_with_trans(dist, x, true) ≈ logpdf(tdist, y)
true