Custom Functional Form Specification
In a nutshell, functional form constraints defines a function that approximates the product of colliding messages and computes posterior marginal that can be used later on during the inference procedure. An important part of the functional forms constraint implementation is the prod
function in the BayesBase
package. For example, if we refer to our CustomFunctionalForm
as to f
we can see the whole functional form constraints pipeline as:
\[q(x) = f\left(\frac{\overrightarrow{\mu}(x)\overleftarrow{\mu}(x)}{\int \overrightarrow{\mu}(x)\overleftarrow{\mu}(x) \mathrm{d}x}\right)\]
Interface
ReactiveMP.jl
, however, uses some extra utility functions to define functional form constraint behaviour. Here we briefly describe all utility function. If you are only interested in the concrete example, you may directly head to the Custom Functional Form example at the end of this section.
Abstract super type
ReactiveMP.AbstractFormConstraint
— TypeAbstractFormConstraint
Every functional form constraint is a subtype of AbstractFormConstraint
abstract type.
Note: this is not strictly necessary, but it makes automatic dispatch easier and compatible with the CompositeFormConstraint
.
ReactiveMP.UnspecifiedFormConstraint
— TypeUnspecifiedFormConstraint
One of the form constraint objects. Does not imply any form constraints and simply returns the same object as receives. However it does not allow DistProduct
to be a valid functional form in the inference backend.
ReactiveMP.CompositeFormConstraint
— TypeCompositeFormConstraint
Creates a composite form constraint that applies form constraints in order. The composed form constraints must be compatible and have the exact same form_check_strategy
.
Form check strategy
Every custom functional form must implement a new method for the default_form_check_strategy
function that returns either FormConstraintCheckEach
or FormConstraintCheckLast
.
FormConstraintCheckLast
:q(x) = f(μ1(x) * μ2(x) * μ3(x))
FormConstraintCheckEach
:q(x) = f(f(μ1(x) * μ2(x)) * μ3(x))
ReactiveMP.default_form_check_strategy
— Functiondefault_form_check_strategy(form_constraint)
Returns a default check strategy (e.g. FormConstraintCheckEach
or FormConstraintCheckEach
) for a given form constraint object.
ReactiveMP.FormConstraintCheckEach
— TypeFormConstraintCheckEach
This form constraint check strategy checks functional form of the messages product after each product in an equality chain. Usually if a variable has been connected to multiple nodes we want to perform multiple prod
to obtain a posterior marginal. With this form check strategy constrain_form
function will be executed after each subsequent prod
function.
ReactiveMP.FormConstraintCheckLast
— TypeFormConstraintCheckEach
This form constraint check strategy checks functional form of the last messages product in the equality chain. Usually if a variable has been connected to multiple nodes we want to perform multiple prod
to obtain a posterior marginal. With this form check strategy constrain_form
function will be executed only once after all subsequenct prod
functions have been executed.
ReactiveMP.FormConstraintCheckPickDefault
— TypeFormConstraintCheckPickDefault
This form constraint check strategy simply fallbacks to a default check strategy for a given form constraint.
Prod constraint
Every custom functional form must implement a new method for the default_prod_constraint
function that returns a proper prod_constraint
object.
ReactiveMP.default_prod_constraint
— Functiondefault_prod_constraint(form_constraint)
Returns a default prod constraint needed to apply a given form_constraint
. For most form constraints this function returns ProdGeneric
.
Constrain form, a.k.a f
The main function that a custom functional form must implement, which we referred to as f
in the beginning of this section, is the constrain_form
function.
ReactiveMP.constrain_form
— Functionconstrain_form(form_constraint, distribution)
This function must approximate distribution
object in a form that satisfies form_constraint
.
Custom Functional Form Example
In this demo we show how to build a custom functional form constraint that is compatible with the ReactiveMP.jl
inference backend. An important part of the functional forms constraint implementation is the prod
function in the BayesBase
package. We show a relatively simple use-case, which might not be very useful in practice, but serves as a simple step-by-step guide. Assume that we want a specific posterior marginal of some random variable in our model to have a specific Gaussian parametrisation, for example mean-precision. We can use built-in NormalMeanPrecision
distribution, but we still need to define our custom functional form constraint:
using ReactiveMP, BayesBase
# First we define our functional form structure with no fields
struct MeanPrecisionFormConstraint <: AbstractFormConstraint end
Next we define the behaviour of our functional form constraint:
ReactiveMP.default_form_check_strategy(::MeanPrecisionFormConstraint) = FormConstraintCheckLast()
ReactiveMP.default_prod_constraint(::MeanPrecisionFormConstraint) = GenericProd()
function ReactiveMP.constrain_form(::MeanPrecisionFormConstraint, distribution)
# This is quite a naive assumption, that a given `dsitribution` object has `mean` and `precision` defined
# However this quantities might be approximated with some other external method, e.g. Laplace approximation
m = mean(distribution) # or approximate with some other method
p = precision(distribution) # or approximate with some other method
return NormalMeanPrecision(m, p)
end
function ReactiveMP.constrain_form(::MeanPrecisionFormConstraint, distribution::BayesBase.ProductOf)
# ProductOf is the special case, read about this type more in the corresponding documentation section
# of the `BayesBase` package
# ...
end