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
StandardMessagePassingRulesThe 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,MvNormalWishartandHalfNormal; - arithmetic:
+,-,*anddot, the functions themselves being the nodes; - logic:
AND,OR,NOTandIMPLY, over Bernoulli variables; - mixtures:
NormalMixture,GammaMixtureandMixture; - expectation propagation:
Probit, a binary output through the probit link, under its own algorithmProbitEP, an example of how an expectation propagation node is written; - helpers:
StandaloneDistribution, a node for a fixed distribution,Uninformative, a factor of one, anddiageye, 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
trueReactiveMP 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)),
)Result
| value | ExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=3.0) |
|---|---|
| type | ExponentialFamily.NormalMeanVariance{Float64} |
| log scale | 0 (declared) |
Inputs
| edge | value |
|---|
Rule
| declared inputs | m[:μ]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T, m[:v]::BayesBase.PointMass |
|---|---|
| algorithm | DefaultAlgorithm() |
| log scale | 0 |
| defined | normal_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
trueWith 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)))
trueWhich 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:
| factorisation | a rule takes | inference |
|---|---|---|
| one cluster for the whole node | messages only | belief propagation |
| a cluster per interface | marginals only | mean-field variational message passing |
| anything in between | messages and marginals | structured variational message passing |
All of them run under the one DefaultAlgorithm. rule_coverage tabulates a node's rules:
MessagePassingRulesBase.rule_coverage(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 covarianceE[Σ⁻¹]⁻¹, as in the nodes' average energies. - Matrix corrections.
*,dotand the rule towardsMvNormalMeanPrecision'sΛread the servicematrix_correction. The precision matrices that*anddotbuild may be singular. These rules correct them with MatrixCorrectionTools'ReplaceZeroDiagonalEntries(tiny)unless the context sets another correction, andNoCorrection()applies none.MvNormalMeanPrecisioncorrects nothing unless the context sets a correction. - Sampling. The
*rules between two general univariate distributions draw samples from the context'srng.MultiplicationSamplingsets 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
undefinedwhen the rule declares none.
The site
| page | contents |
|---|---|
| Normal distributions | NormalMeanVariance, NormalMeanPrecision, the five multivariate normals and HalfNormal |
| Gamma, Beta and discrete distributions | GammaShapeRate, Gamma, GammaInverse, Beta, Bernoulli, Categorical, Dirichlet, DirichletCollection, Poisson, Uniform |
| Matrix and joint distributions | Wishart, InverseWishart, MatrixNormal, MatrixNormalWishart, MvNormalGamma, MvNormalWishart |
| Arithmetic | +, -, *, dot and MultiplicationSampling |
| Logic | AND, OR, NOT, IMPLY |
| Mixtures | NormalMixture, GammaMixture, Mixture and their algorithms |
| Expectation propagation: Probit | Probit and its algorithm ProbitEP |
| Helper nodes and message types | StandaloneDistribution, Uninformative, GammaShapeLikelihood, diageye |
| Internals | the helpers the rules and the node packages share |