# 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. More information about prod function is present in the Prod Implementation section. 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.

### 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_strategyFunction
default_form_check_strategy(form_constraint)

Returns a default check strategy (e.g. FormConstraintCheckEach or FormConstraintCheckEach) for a given form constraint object.

source
ReactiveMP.FormConstraintCheckEachType
FormConstraintCheckEach

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.

source
ReactiveMP.FormConstraintCheckLastType
FormConstraintCheckEach

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.

source

### 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_constraintFunction
default_prod_constraint(form_constraint)

Returns a default prod constraint needed to apply a given form_constraint. For most form constraints this function returns ProdGeneric.

source

### 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_formFunction
constrain_form(form_constraint, distribution)

This function must approximate distribution object in a form that satisfies form_constraint.

source

### Is point mass form constraint (optional)

Every custom functional form may implement a new method for the is_point_mass_form_constraint function that returns either true or false. This is an utility function that simplifes computation of the Bethe Free Energy and is not strictly necessary.

ReactiveMP.is_point_mass_form_constraintFunction
is_point_mass_form_constraint(form_constraint)

Specifies whether form constraint always returns PointMass estimates or not. For a given form_constraint returns either true or false.

source

### Compatibility with @constraints macro (optional)

To make custom functional form constraint compatible with the @constraints macro, it must implement a new method for the make_form_constraint function.

ReactiveMP.make_form_constraintFunction
make_form_constraint(::Type, args...; kwargs...)

Creates form constraint object based on passed type with given args and kwargs. Used to simplify form constraint specification.

As an example:

make_form_constraint(PointMass)

creates an instance of PointMassFormConstraint and

make_form_constraint(SampleList, 5000, LeftProposal())

should create an instance of SampleListFormConstraint.

See also: AbstractFormConstraint

source

## 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. More information about prod function is present in the Prod Implementation section. 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, GraphPPL

# 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.is_point_mass_form_constraint(::MeanPrecisionFormConstraint) = false
ReactiveMP.default_form_check_strategy(::MeanPrecisionFormConstraint)   = FormConstraintCheckLast()
ReactiveMP.default_prod_constraint(::MeanPrecisionFormConstraint)       = ProdGeneric()

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::DistProduct)
# ...
end

At this point we already can use our functional form constraint in the inference backend, however, lets also make our functional form constraint compatible with the @constraints macro from GraphPPL.jl package.

ReactiveMP.make_form_constraint(::Type{ NormalMeanPrecision }, args...; kwargs...) = MeanPrecisionFormConstraint()
@constraints begin
q(x) :: NormalMeanPrecision
end
Constraints:
marginals form:
q(x) :: Main.var"Main".MeanPrecisionFormConstraint() [ prod_constraint = ProdGeneric(fallback = ProdAnalytical()) ]
messages form:
factorisation:
Options:
warn = true