GCVMessagePassingRules

The Gaussian controlled variance node, GCV, and its rules for reactive message passing: a normal whose log-variance is linear in other variables of the model. Use it for a variance that is itself inferred and changes over time, as in hierarchical Gaussian filters, where the state of one layer sets the volatility of the layer below.

GCVMessagePassingRules — Module
GCVMessagePassingRules

The Gaussian controlled variance node, GCV: a normal whose log-variance is linear in other variables of the model,

\[p(y \mid x, z, κ, ω) = \mathcal{N}\bigl(y \mid x, \exp(κ z + ω)\bigr),\]

the building block of hierarchical Gaussian filters, where one layer's state sets the volatility of the layer below.

  • GCV: the node, with interfaces y, x, z, κ and ω. Its rules are variational, under the structured factorisation q(y, x) q(z) q(κ) q(ω) or the mean field; every rule reads the marginals of z, κ and ω.
  • GCVApproximation: its algorithm, which carries the Gauss–Hermite cubature of the messages towards z, κ and ω.
  • ExponentialLinearQuadratic: the density of those messages, which has no closed-form moments.

The package also adds rules to NormalMeanVariance and NormalMeanPrecision (their nodes are in StandardMessagePassingRules) for an ExponentialLinearQuadratic message on out, so that a GCV's z or ω can be the output of a normal node.

Examples

julia> using MessagePassingRulesBase, ExponentialFamily, BayesBase

julia> q_z, q_κ, q_ω = PointMass(0.0), PointMass(1.0), PointMass(0.0);  # a noise variance exp(0) = 1

julia> result = @call_message_update_rule(
           node = GCV, target = :y, m = (x = NormalMeanVariance(1.0, 2.0),), q = (z = q_z, κ = q_κ, ω = q_ω),
       );

julia> mean_var(getresult(result)) .≈ (1.0, 3.0)
(true, true)
source
Where these rules run

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

Overview

A GCV node relates an output y to its mean x with a variance exp(κz + ω). Here z is a latent variable, often a random walk of its own. κ scales the effect of z on the log-variance, and ω is an offset.

The rules are variational: each rule sends the exponentiated expected log-density of the node, the expectation taken under the marginals of the variables outside the target's cluster. Every rule reads the marginals of z, κ and ω. The messages towards z, κ and ω are ExponentialLinearQuadratic densities, whose moments a Gauss–Hermite cubature computes.

The package also adds rules to the NormalMeanVariance and NormalMeanPrecision nodes of StandardMessagePassingRules. These rules accept an ExponentialLinearQuadratic message on the normal's out. With them, z or ω can itself be the output of a normal node, such as a step of a random walk.

Definition

\[p(y \mid x, z, κ, ω) = \mathcal{N}\bigl(y \mid x, \exp(κ z + ω)\bigr) = \frac{1}{\sqrt{2π \exp(κ z + ω)}} \exp\Bigl(-\frac{(y - x)^2}{2 \exp(κ z + ω)}\Bigr).\]

The rules need the expected noise precision ⟨exp(-(κz + ω))⟩ = ⟨exp(-ω)⟩ ⟨exp(-κz)⟩. For a normal q(ω) the first factor is the mean of a lognormal, exp(-⟨ω⟩ + Var(ω)/2), which is exact. The second treats κz as normal, with Var(κz) = ⟨κ⟩² Var(z) + ⟨z⟩² Var(κ) + Var(κ) Var(z), which is exact only when κ or z is a point mass.

Interfaces

using GCVMessagePassingRules, MessagePassingRulesBase, ExponentialFamily, BayesBase
MessagePassingRulesBase.nodespec(GCV)
NodeSpec: GCV
xzκωyGCVstochastic
interfacealiases
y
x
z
κ
ω
default algorithmGCVApproximation{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}}(GaussHermiteCubature(20))
static inputsnone
definedsrc/node.jl:93
namemeaningmessages its rules takemarginals its rules take
ythe output, normal about xunivariate normal or ExponentialLinearQuadratic (structured)univariate normal
xthe mean of yunivariate normal or ExponentialLinearQuadratic (structured)univariate normal
zthe variable controlling the log-variancenonea normal
κthe coupling of z to the log-variancenoneanything with a mean and a variance
ωthe offset of the log-variancenoneanything with a mean and a variance

No interface of GCV has an alias. Under the structured factorisation y and x share one cluster, and so a joint marginal q(y, x), a bivariate normal.

Algorithm

GCVApproximation(; method = GaussHermiteCubature(20)) is the node's algorithm. It carries the GaussHermiteCubature that computes the moments of the messages towards z, κ and ω. The node declares its default instance, so a model does not need to name it, and names it only to change the number of points. The rules are declared for the default instance's type, so another approximation method finds no rule.

The algorithm declares no dependencies of its own. The rules take what the default scheme delivers: messages from the target's cluster and marginals of the other clusters.

Supported rules

MessagePassingRulesBase.rule_coverage(GCV)
Rule coverage for GCV
GCVApproximation{GaussHermiteCubature}
→ y✓×2
→ x✓×2
→ z✓×2
→ κ✓×2
→ ω✓×2
average energy✓×2
q(y, x)✓

Each target of GCV has two rules. One is for the structured factorisation q(y, x) q(z) q(κ) q(ω), and one is for the mean field, which puts every variable in a cluster of its own. Under the structured factorisation:

  • the rules towards y and x take the message on the other one and the marginals of z, κ and ω;
  • the rules towards z, κ and ω take the joint q(y, x);
  • the row q(y, x) is the marginal rule of the joint.

There are no belief propagation rules. The average energy is defined for both factorisations.

The rules that the package adds to the normal nodes of StandardMessagePassingRules take an ExponentialLinearQuadratic message on out, which they reduce to a normal with its moments:

nodetargetinputs
NormalMeanVarianceμm(out), and m(v) a point mass or q(v)
NormalMeanVarianceq(out, μ, v)m(out), a univariate normal m(μ), a point-mass m(v)
NormalMeanVarianceq(out, μ)m(out), a univariate normal m(μ), q(v)
NormalMeanPrecisionμm(out), and m(τ) a point mass or q(τ)
NormalMeanPrecisionq(out, μ, τ)m(out), a univariate normal m(μ), a point-mass m(τ)
NormalMeanPrecisionq(out, μ)m(out), a univariate normal m(μ), q(τ)

Example

The message towards y from a normal message on x, with point-mass marginals that make the noise variance exp(1 ⋅ 0 + 0) = 1:

@call_message_update_rule(
    node = GCV, target = :y,
    m = (x = NormalMeanVariance(1.0, 2.0),),
    q = (z = PointMass(0.0), κ = PointMass(1.0), ω = PointMass(0.0)),
)
RuleResult: message of GCV towards :ymessages and marginals
xzκωyGCV
Result
valueExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=3.0)
typeExponentialFamily.NormalMeanVariance{Float64}
log scaleundefined: the message rule for GCV towards :y under GCVApproximation{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}} declares no `logscale`
Inputs
edgevalue
xmExponentialFamily.NormalMeanVariance{Float64}(μ=1.0, v=2.0)
zqPointMass{Float64}(0.0)
κqPointMass{Float64}(1.0)
ωqPointMass{Float64}(0.0)
Rule
declared inputsm[:x]::Union{ExponentialLinearQuadratic, ExponentialFamily.UnivariateNormalDistributionsFamily, ExponentialFamily.UnivariateGaussianDistributionsFamily}, q[:z]::Any, q[:κ]::Any, q[:ω]::Any
algorithmGCVApproximation{GaussHermiteCubature{Vector{Float64}, Vector{Float64}}}(GaussHermiteCubature(20))
log scalenone
definedsrc/rules.jl:12
body
args->through_noise(args.m[:x], args.q[:z], args.q[:κ], args.q[:ω])
Other rules for this target (1)
src/rules.jl:17
✓algorithm GCVApproximation{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}}
✗q[:x]::Any not provided
✓q[:z]::Any got BayesBase.PointMass{Float64}
✓q[:κ]::Any got BayesBase.PointMass{Float64}
✓q[:ω]::Any got BayesBase.PointMass{Float64}
✗m[:x]::ExponentialFamily.NormalMeanVariance{Float64} provided but not consumed

The card draws the message on x as a solid input and the marginals of z, κ and ω as dashed ones. The result adds the noise variance to the variance of x, 2 + 1 = 3:

julia> using MessagePassingRulesBase, GCVMessagePassingRules, ExponentialFamily, BayesBase

julia> result = @call_message_update_rule(
           node = GCV, target = :y,
           m = (x = NormalMeanVariance(1.0, 2.0),),
           q = (z = PointMass(0.0), κ = PointMass(1.0), ω = PointMass(0.0)),
       );

julia> mean_var(getresult(result)) .≈ (1.0, 3.0)
(true, true)

The message towards ω under the mean field is an ExponentialLinearQuadratic, whose moments the cubature of the default algorithm computes. Its coefficient b is ⟨(y - x)²⟩ = (1 - 0)² + 0.5 + 0.5 = 2:

julia> using MessagePassingRulesBase, GCVMessagePassingRules, ExponentialFamily, BayesBase

julia> result = @call_message_update_rule(
           node = GCV, target = :ω,
           q = (y = NormalMeanVariance(1.0, 0.5), x = NormalMeanVariance(0.0, 0.5), z = PointMass(0.0), κ = PointMass(1.0)),
       );

julia> message = getresult(result);

julia> message isa ExponentialLinearQuadratic
true

julia> params(message) == (1.0, 2.0, -1.0, 0.0)
true

A step of a hierarchical Gaussian filter

In a two-layer hierarchical Gaussian filter, the upper layer z is a random walk, zₜ ~ N(zₜ₋₁, 1), and it sets the volatility of the lower random walk, xₜ ~ GCV(xₜ₋₁, zₜ, κ, ω). The update of the upper layer passes through two nodes. First the GCV node sends its message towards zₜ, from the marginals of the lower layer:

towards_z = @call_message_update_rule(
    node = GCV, target = :z,
    q = (y = NormalMeanVariance(1.0, 0.5), x = NormalMeanVariance(0.0, 0.5), κ = PointMass(1.0), ω = PointMass(0.0)),
)
m_z = getresult(towards_z)
mean_var(m_z)
(1.814142762171816, 3.673218039648464)

The message is an ExponentialLinearQuadratic, and its moments come from the cubature. Then the random walk's NormalMeanVariance node carries it back towards zₜ₋₁. This is one of the rules the package adds to that node:

@call_message_update_rule(node = NormalMeanVariance, target = :μ, m = (out = m_z, v = PointMass(1.0)))
RuleResult: message of NormalMeanVariance towards :μbelief propagation
outvμNormalMeanVariance
Result
valueExponentialFamily.NormalMeanVariance{Float64}(μ=1.81414, v=4.67322)
typeExponentialFamily.NormalMeanVariance{Float64}
log scaleundefined: the message rule for NormalMeanVariance towards :μ under MessagePassingRulesBase.DefaultAlgorithm declares no `logscale`
Inputs
edgevalue
outmExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Fl…
vmPointMass{Float64}(1.0)
Rule
declared inputsm[:out]::ExponentialLinearQuadratic, m[:v]::BayesBase.PointMass
algorithmDefaultAlgorithm()
log scalenone
definedsrc/gaussian_extension.jl:8
body
args->begin
        (m, v) = mean_var(args.m[:out])
        NormalMeanVariance(m, v + mean(args.m[:v]))
    end
Other rules for this target (8)
src/gaussian_extension.jl:13
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✓m[:out]::ExponentialLinearQuadratic got ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64}
✗q[:v]::Any not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/mean.jl:1
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:out]::BayesBase.PointMass got ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64}
✓m[:v]::BayesBase.PointMass got BayesBase.PointMass{Float64}
normal_mean_variance/mean.jl:8
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:out]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T got ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64}
✓m[:v]::BayesBase.PointMass got BayesBase.PointMass{Float64}
normal_mean_variance/mean.jl:18
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗q[:out]::BayesBase.PointMass not provided
✗q[:v]::BayesBase.PointMass not provided
✗m[:out]::ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64} provided but not consumed
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/mean.jl:25
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗q[:out]::Any not provided
✗q[:v]::Any not provided
✗m[:out]::ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64} provided but not consumed
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/mean.jl:31
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:out]::BayesBase.PointMass got ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64}
✗q[:v]::Any not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/mean.jl:38
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:out]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T got ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64}
✗q[:v]::Any not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed
normal_mean_variance/mean.jl:49
✓algorithm MessagePassingRulesBase.DefaultAlgorithm
✗m[:out]::Union{ExponentialFamily.UnivariateNormalDistributionsFamily{T}, ExponentialFamily.UnivariateGaussianDistributionsFamily{T}} where T got ExponentialLinearQuadratic{MessagePassingRulesApproximations.GaussHermiteCubature{Vector{Float64}, Vector{Float64}}, Float64}
✗q[:v]::BayesBase.PointMass not provided
✗m[:v]::BayesBase.PointMass{Float64} provided but not consumed

The rule reduces the message on out to a normal with its moments and adds the random walk's variance, 1.

Limitations

  • There are no belief-propagation rules: every rule needs the marginals of z, κ and ω, so a model must initialise them.
  • The node is univariate; the messages on y and x must be univariate normals or ExponentialLinearQuadratics.
  • ⟨exp(-κz)⟩ treats κz as normal, which is an approximation unless κ or z is a point mass.
  • The approximation method must be a Gauss–Hermite cubature.
  • The average energy needs a normal q(z), and a multivariate normal q(y, x) or normal q(y) and q(x).
  • The rules declare no log scale.

API

The node and its algorithm:

GCVMessagePassingRules.GCV — Type
GCV

The Gaussian controlled variance node, a normal whose log-variance is linear in its inputs:

\[p(y \mid x, z, κ, ω) = \mathcal{N}\bigl(y \mid x, \exp(κ z + ω)\bigr).\]

The variance of y about x is exp(κz + ω), so its precision is exp(-(κz + ω)). It is stochastic, with the interfaces, in order:

  • y: the output, normal about x;
  • x: the mean of y;
  • z: the variable that controls the log-variance, scaled by κ;
  • κ: the coupling of z to the log-variance;
  • ω: the offset of the log-variance.

Its rules run under its own algorithm, GCVApproximation, whose default instance the node declares, so a model need not name it. They are variational and read q(z), q(κ) and q(ω) always, under one of two factorisations:

  • structured, q(y, x) q(z) q(κ) q(ω): the rules towards y and x take the message on the other one, the rules towards z, κ and ω the joint q(y, x), and there is a marginal rule for q(y, x);
  • mean field, q(y) q(x) q(z) q(κ) q(ω): every rule takes marginals.

Towards y and x a rule returns a NormalMeanVariance; towards z, κ and ω an ExponentialLinearQuadratic. The expectation ⟨exp(-κz)⟩ treats κz as normal, which is exact only when κ or z is a point mass; ⟨exp(-ω)⟩ is exact for a normal q(ω).

The average energy,

\[\tfrac12\bigl[\log 2π + ⟨κ⟩⟨z⟩ + ⟨ω⟩ + ⟨(y - x)^2⟩ ⟨e^{-(κz + ω)}⟩\bigr],\]

is defined for both factorisations, with a multivariate normal q(y, x) or normal q(y) and q(x), and a normal q(z); q(κ) and q(ω) need only a mean and a variance.

Limitations

  • There are no belief-propagation rules: every rule needs the marginals of z, κ and ω.
  • The messages on y and x must be univariate normals or ExponentialLinearQuadratics; the node is univariate.
  • The rules declare no log scale.

See also GCVApproximation, ExponentialLinearQuadratic.

source
GCVMessagePassingRules.GCVApproximation — Type
GCVApproximation(; method = GaussHermiteCubature(20))
GCVApproximation(method)

The algorithm of GCV's rules: it carries the cubature that computes the moments of the ExponentialLinearQuadratic messages towards z, κ and ω. The rules towards y and x do not use it.

Keywords

  • method: a GaussHermiteCubature, of any number of points. Default GaussHermiteCubature(20). More points give more accurate moments at a higher cost.

A model names this algorithm only to change the number of points.

Throws

An ArgumentError for a method other than a GaussHermiteCubature: the rules take the moments by cubature, through its points and weights.

Examples

julia> using MessagePassingRulesApproximations: GaussHermiteCubature

julia> GCVApproximation(method = GaussHermiteCubature(32)) isa GCVApproximation
true
source

The density of the messages towards z, κ and ω:

GCVMessagePassingRules.ExponentialLinearQuadratic — Type
ExponentialLinearQuadratic(approximation, a, b, c, d)

The univariate density

\[p(x) ∝ \exp\Bigl(-\tfrac12\bigl(a x + b \exp(c x + d x^2 / 2)\bigr)\Bigr),\]

the form of GCV's messages towards z, κ and ω. It has no closed-form normalisation or moments: approximation, a GaussHermiteCubature, computes mean, var and the other moments by weighting a standard normal.

Arguments

  • approximation: the cubature of the moments;
  • a, b, c, d: real coefficients, promoted to a common floating-point type.

logpdf and pdf are unnormalised. Its product with a univariate normal is a NormalMeanVariance with the moments of the product, computed by the same cubature around the normal's mean and variance.

Examples

julia> using MessagePassingRulesApproximations: GaussHermiteCubature

julia> using ExponentialFamily, BayesBase

julia> d = ExponentialLinearQuadratic(GaussHermiteCubature(20), 1.0, 2.0, -1.0, 0.0);

julia> logpdf(d, 0.0) ≈ -1.0
true

julia> prod(GenericProd(), NormalMeanVariance(0.0, 1.0), d) isa NormalMeanVariance
true
source