StandardMessagePassingRules

StandardMessagePassingRules holds the rules of the standard factor nodes: the distributions a model uses most, the arithmetic functions, Boolean logic, the mixtures and the probit link, an expectation propagation node. Load it next to an engine, such as ReactiveMP, and every rule is available. A model written with RxInfer uses the nodes by their usual names, x ~ NormalMeanVariance(μ, v) or y ~ x + z. Nodes outside this set, such as Delta or AR, have packages of their own, which build on this one.

StandardMessagePassingRules — Module
StandardMessagePassingRules

The message passing rules of the standard nodes, written with MessagePassingRulesBase:

  • distributions: the normals (NormalMeanVariance, MvNormalMeanPrecision, …), GammaShapeRate, Gamma, GammaInverse, Beta, Bernoulli, Categorical, Dirichlet, DirichletCollection, Poisson, Uniform, Wishart, InverseWishart, MatrixNormal, MatrixNormalWishart, MvNormalGamma, MvNormalWishart and HalfNormal;
  • arithmetic: +, -, * and dot, the functions themselves being the nodes;
  • logic: AND, OR, NOT and IMPLY, over Bernoulli variables;
  • mixtures: NormalMixture, GammaMixture and Mixture;
  • expectation propagation: Probit, a binary output through the probit link, under its own algorithm ProbitEP, an example of how an expectation propagation node is written;
  • helpers: StandaloneDistribution, a node for a fixed distribution, Uninformative, a factor of one, and diageye, re-exported from MessagePassingRulesBase.

Most nodes are types other packages own, ExponentialFamily's and Distributions' distributions and Base's functions; the package exports only the node types it defines. Loading it is enough: the rules are methods, and rule lookup finds them by the node, the target and the inputs' types. MessagePassingRulesBase.rule_coverage(node) shows which rules a node has, and @which_message_update_rule which one a call would run.

Every distribution node runs under DefaultAlgorithm, and its rules name no algorithm: whether a rule computes a belief propagation, variational or structured update follows from the factorisation, through the engine's default dependency scheme, which gives each rule the messages inside its own cluster and the marginals of the other clusters. A node whose rules ignore the factorisation declares an algorithm of its own, as NormalMixture does with NormalMixtureVMP and Mixture with MixtureBP; * runs under MultiplicationSampling, an extension of the default that carries a sample count.

Examples

The message towards out of a NormalMeanVariance node, from a normal message on its mean and a known variance:

julia> result = @call_message_update_rule(
           node = NormalMeanVariance, target = :out,
           m = (μ = NormalMeanVariance(0.0, 1.0), v = PointMass(2.0)),
       );

julia> message = getresult(result);

julia> message isa NormalMeanVariance && mean(message) ≈ 0.0 && var(message) ≈ 3.0
true
source
Where these rules run

ReactiveMP runs these rules on a factor graph, which RxInfer builds from a GraphPPL model. The examples here call the rules directly, as a test does.

A first rule call

A rule is an ordinary Julia method. @call_message_update_rule runs one by hand, as an engine would. Here it computes the message towards out of a NormalMeanVariance node, from a normal message on the mean and a known variance, a point mass:

using StandardMessagePassingRules, MessagePassingRulesBase, ExponentialFamily, BayesBase

@call_message_update_rule(
    node = NormalMeanVariance, target = :out,
    m = (μ = NormalMeanVariance(1.0, 1.0), v = PointMass(2.0)),
)
RuleResult: message of NormalMeanVariance towards :outbelief propagation
μvoutNormalMeanVariance
Result
valueExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=3.0)
typeExponentialFamily.NormalMeanVariance{Float64}
log scale0 (declared)
Inputs
edgevalue
μmExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=1.0)
vmPointMass{Float64}(2.0)
Rule
declared inputsm[:μ]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T, m[:v]::BayesBase.PointMass
algorithmDefaultAlgorithm()
log scale0
definednormal_mean_variance/out.jl:8
body
args->begin
        (μ_mean, μ_var) = mean_var(args.m[:μ])
        NormalMeanVariance(μ_mean, μ_var + mean(args.m[:v]))
    end
Other rules for this target (6)
normal_mean_variance/out.jl:1
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:μ]::BayesBase.PointMass got ExponentialFamily.NormalMeanVariance{Float64}
✓m[:v]::BayesBase.PointMass got BayesBase.PointMass{Float64}
normal_mean_variance/out.jl:18
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗q[:μ]::BayesBase.PointMass not provided
✗q[:v]::BayesBase.PointMass not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
✗m[:μ]::ExponentialFamily.NormalMeanVariance{Float64} provided but not consumed
normal_mean_variance/out.jl:25
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗q[:μ]::Any not provided
✗q[:v]::Any not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
✗m[:μ]::ExponentialFamily.NormalMeanVariance{Float64} provided but not consumed
normal_mean_variance/out.jl:31
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:μ]::BayesBase.PointMass got ExponentialFamily.NormalMeanVariance{Float64}
✗q[:v]::Any not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/out.jl:37
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✓m[:μ]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T got ExponentialFamily.NormalMeanVariance{Float64}
✗q[:v]::Any not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/out.jl:46
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✓m[:μ]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T got ExponentialFamily.NormalMeanVariance{Float64}
✗q[:v]::BayesBase.PointMass not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed

The call returns a RuleResult, drawn as a card: the node, the inputs it read as arrows in, and the target as the arrow out. The variances add, so the message is NormalMeanVariance(1.0, 3.0). getresult returns the message itself:

julia> using StandardMessagePassingRules, MessagePassingRulesBase, ExponentialFamily, BayesBase

julia> result = @call_message_update_rule(
           node = NormalMeanVariance, target = :out,
           m = (μ = NormalMeanVariance(1.0, 1.0), v = PointMass(2.0)),
       );

julia> message = getresult(result);

julia> message isa NormalMeanVariance && mean(message) ≈ 1.0 && var(message) ≈ 3.0
true

With marginals instead of messages, the same call selects the variational rule. That rule replaces the variance with 1/E[1/v] under the variance's marginal:

julia> message = getresult(@call_message_update_rule(
           node = NormalMeanVariance, target = :out,
           q = (μ = PointMass(1.0), v = GammaShapeRate(3.0, 4.0)),
       ));

julia> mean(message) ≈ 1.0 && var(message) ≈ inv(mean(inv, GammaShapeRate(3.0, 4.0)))
true

Which rules a node has

The engine selects a rule by the node, the target interface and the types of the inputs. An input is a message m or a marginal q. The factorisation of the approximate posterior decides which one a rule receives. It splits a node's interfaces into clusters, and under the default scheme a rule takes messages from its target's own cluster and marginals from the other clusters. One set of rules therefore serves three kinds of inference:

factorisationa rule takesinference
one cluster for the whole nodemessages onlybelief propagation
a cluster per interfacemarginals onlymean-field variational message passing
anything in betweenmessages and marginalsstructured variational message passing

All of them run under the one DefaultAlgorithm. rule_coverage tabulates a node's rules:

MessagePassingRulesBase.rule_coverage(NormalMeanVariance)
Rule coverage for ExponentialFamily.NormalMeanVariance
DefaultAlgorithm
→ out✓×7
→ μ✓×7
→ v✓×5
average energy✓×2
q(out, μ)✓×3
q(out, μ, v)✓×3

The table has a row per message target (→ μ), per joint marginal (q(out, μ)) and one for the average energy. It has a column per algorithm, and each cell counts the rules. An empty row is a target that no rule reaches. Every node section on this site shows this table, generated from the loaded rules.

@which_message_update_rule shows the rule a call would run, with its source. list_rules lists all the rules of a node.

Conventions

  • Variational expectations. A variational rule uses the expectations that naive variational message passing gives. A variance contributes 1/E[1/v] and a covariance E[Σ⁻¹]⁻¹, as in the nodes' average energies.
  • Matrix corrections. *, dot and the rule towards MvNormalMeanPrecision's Λ read the service matrix_correction. The precision matrices that * and dot build may be singular. These rules correct them with MatrixCorrectionTools' ReplaceZeroDiagonalEntries(tiny) unless the context sets another correction, and NoCorrection() applies none. MvNormalMeanPrecision corrects nothing unless the context sets a correction.
  • Sampling. The * rules between two general univariate distributions draw samples from the context's rng. MultiplicationSampling sets how many.
  • Log scales. Most belief propagation rules declare the log scale of their message. Most variational rules declare none, since the free energy does not need it. A rule's card shows the log scale as undefined when the rule declares none.

The site

pagecontents
Normal distributionsNormalMeanVariance, NormalMeanPrecision, the five multivariate normals and HalfNormal
Gamma, Beta and discrete distributionsGammaShapeRate, Gamma, GammaInverse, Beta, Bernoulli, Categorical, Dirichlet, DirichletCollection, Poisson, Uniform
Matrix and joint distributionsWishart, InverseWishart, MatrixNormal, MatrixNormalWishart, MvNormalGamma, MvNormalWishart
Arithmetic+, -, *, dot and MultiplicationSampling
LogicAND, OR, NOT, IMPLY
MixturesNormalMixture, GammaMixture, Mixture and their algorithms
Expectation propagation: ProbitProbit and its algorithm ProbitEP
Helper nodes and message typesStandaloneDistribution, Uninformative, GammaShapeLikelihood, diageye
Internalsthe helpers the rules and the node packages share