Customizing the behaviour of the @model with a custom backend

When creating the graphical model, GraphPPL package uses several functions to decide what to do in specific situations, for example

  • Is x ~ SomeType(y, z) a stochastic or deterministic relationship? For example SomeType can be a Gaussian, in which case the answer

is obvious, but what is SomeType is a Matrix? Or what if a user specified const Matrix = Gaussian?

  • Should x ~ Normal(a, b) be interpreted as x ~ Normal(mean = a, variance = b) or Normal(mean = a, standard_deviation = b)?
  • Should x_next ~ HierarchicalGaussianFilter(x_prev, tau) create an Atomic or a Composite node for HierarchicalGaussianFilter?
  • Should x := x1 + x2 + x3 + x4 be replaced with x := sum(x1, x2, x3, x4) or x := sum(sum(sum(x1, x2), x3), x4). Or left untouched?
  • What extra syntax transformations are allowed? For example should not_x ~ ¬x be interpreted as a boolean random variable x with the ¬ as a stochastic node

or it is just a function call?

It is not possible to resolve these issues on a syntax level, thus GraphPPL requires a specific backend to resolve this information at run-time.

Default backend

For interactive purposes (plotting or testing) GraphPPL implements a DefaultBackend, which properly handles objects from Distributions.jl. The @model macro by itself is not exported by default. To use it explicitly simply call:

import GraphPPL: @model
GraphPPL.DefaultBackendType
DefaultBackend

A default backend that is used in the GraphPPL.@model macro when no backend is specified explicitly.

source

A backend-specific inference package should implement its own backend structure together with its own @model macro (or a different name) that would call the @model macro from GraphPPL with a specific package. Below is the list of backend-specific functions, each of which should be implemented in order for backend to be fully specified.

GraphPPL.model_macro_interior_pipelinesFunction
model_macro_interior_pipelines(backend)

Returns a collection of syntax transformation functions for the apply_pipeline function based on a specific backend. The functions are being applied to the model in the model_macro_interior macro body in the exact same order they are returned.

source
GraphPPL.NodeBehaviourType
NodeBehaviour

Abstract type representing either Deterministic or Stochastic for a given object. By default is Deterministic unless specified otherwise.

source
GraphPPL.NodeTypeType
NodeType

Abstract type representing either Composite or Atomic trait for a given object. By default is Atomic unless specified otherwise.

source
GraphPPL.aliasesFunction
aliases(backend, fform)

Returns a collection of aliases for fform depending on the backend.

source
GraphPPL.interfacesFunction
interfaces(backend, fform, ::StaticInt{N}) where N

Returns the interfaces for a given fform and backend with a given amount of interfaces N.

source
GraphPPL.factor_aliasFunction
factor_alias(backend, fform, interfaces)

Returns the alias for a given fform and interfaces with a given backend.

source
GraphPPL.instantiateFunction
instantiate(::Type{Backend})

Instantiates a default backend object of the specified type. Should be implemented for all backends.

source
Note

The GraphPPL.model_macro_interior automatically creates a method for GraphPPL.default_backend.

For inference backends, we recommend to implement the @model macro using the following pattern:

GraphPPL.@modelMacro
@model function model_name(model_arguments)
    ...
end

Note that the @model macro is not exported by default and the recommended way of using it is in the combination with some inference backend. The GraphPPL package provides the DefaultGraphPPLBackend structure for plotting and test purposes, but some backends may specify different behaviour for different structures. For example, the interface names of a node Normal or its behaviour may (and should) depend on the specified backend.

The recommended way of using the GraphPPL.@model macro from other backend-based packages is to define their own @model macro, which will call the GraphPPL.model_macro_interior function with the specified backend. For example

module SamplingBasedInference

struct SamplingBasedBackend end

macro model(model_specification)
    return esc(GraphPPL.model_macro_interior(SamplingBasedBackend(), model_specification))
end

end

Read more about the backend inteface in the corresponding section of the documentation.

To use GraphPPL package as a standalone package for plotting and testing, use the import GraphPPL: @model explicitly to add the @model macro to the current scope.

source
GraphPPL.model_macro_interiorFunction
model_macro_interior(backend, model_specification)

The function that translates the model_specification code into a Julia compatible code block given some backend. This function must be used within the @model macro.

source