Math helpers

The math helpers are the linear algebra and the Gaussian algebra that the rules of many nodes compute. They live here so that every rule package computes them the same way.

They are public but not exported. Call them qualified, as MessagePassingRulesBase.add_outer(V, m), or import them by name.

Each helper takes numbers as well as arrays, so a rule written once serves univariate and multivariate inputs. Each keeps the float type of its inputs.

Linear algebra

The functions ending in !! overwrite their argument when it is a dense Array, and return a new value otherwise. Give them only a value you own, such as a fresh product.

MessagePassingRulesBase.add_outer — Function
add_outer(A, x)
add_outer(A, x, y)

Return A + x * y', with y = x when omitted, in a new matrix; A is not modified. Dense arguments of one BLAS float type go through BLAS ger!; any other element types, dual numbers say, through a loop in their promoted type. For numbers it is A + x * y.

Examples

julia> MessagePassingRulesBase.add_outer([1.0 0.0; 0.0 1.0], [1.0, 2.0])
2×2 Matrix{Float64}:
 2.0  2.0
 2.0  5.0

julia> MessagePassingRulesBase.add_outer(1.0, 2.0, 3.0)
7.0

See also gaussian_second_moment, gaussian_cross_moment.

source
MessagePassingRulesBase.trace_product — Function
trace_product(A, B)

The trace tr(A * B), computed without forming the product; for numbers, A * B.

Throws

  • DimensionMismatch when A is not square or B has another size.

Examples

julia> MessagePassingRulesBase.trace_product([1.0 2.0; 3.0 4.0], [1.0 0.0; 0.0 1.0])
5.0
source
MessagePassingRulesBase.negate!! — Function
negate!!(A)

Return -A, overwriting A when it is a dense Array; any other array, a view say, and a number are left as they are, and a new value is returned. The !! says it mutates where it can, so it is given a value the caller owns, such as a fresh product: negate!!(W * A).

See also scale!!.

source
MessagePassingRulesBase.scale!! — Function
scale!!(α, A)

Return α * A, overwriting A when it is a dense Array whose element type is α's real type; any other array and a number are left as they are, and a new value is returned. As for negate!!, A is a value the caller owns.

source
MessagePassingRulesBase.scaled_outer — Function
scaled_outer(v, a)

The product v a vᵀ. For a vector v and a real a it is computed as (v vᵀ) a, which is exactly symmetric where (v a) vᵀ is not always; for anything else, as v * a * v'.

A package with a structured vector adds a method for it: the autoregressive package gives its standard basis vector e the diagonal e a eᵀ, which the rules of dot then build.

Examples

julia> MessagePassingRulesBase.scaled_outer([1.0, 2.0], 3.0)
2×2 Matrix{Float64}:
 3.0   6.0
 6.0  12.0
source
MessagePassingRulesBase.diageye — Function
diageye([T = Float64,] n::Integer) -> Matrix{T}

The n×n identity matrix of element type T, as a dense Matrix, for the covariances and precisions a model writes, MvNormalMeanCovariance(zeros(2), diageye(2)). Unlike LinearAlgebra.I, it has a size and can be inverted, factorised and mutated.

Examples

julia> MessagePassingRulesBase.diageye(2)
2×2 Matrix{Float64}:
 1.0  0.0
 0.0  1.0

julia> MessagePassingRulesBase.diageye(Int, 1)
1×1 Matrix{Int64}:
 1
source
MessagePassingRulesBase.promote_cluster — Function
promote_cluster(cluster::FactorizedCluster, inputs...) -> FactorizedCluster

cluster with every block in the float type of all inputs together, as BayesBase.promote_paramfloattype gives it. A rule's output carries the promoted float type of every input, and that includes a block that passes an input through unchanged.

See also FactorizedCluster.

source

Gaussians

These helpers compute the moments and energies of normal distributions. They also compute what a normal factor sees of its parameters under variational message passing.

MessagePassingRulesBase.gaussian_difference_moment — Function
gaussian_difference_moment(q_out, q_μ)
gaussian_difference_moment(q_joint)

E[(out - μ)(out - μ)ᵀ]: for independent marginals of out and μ, or for their joint, whose first half is out and second half μ. Each marginal needs mean_cov.

source
MessagePassingRulesBase.gaussian_average_energy — Function
gaussian_average_energy(d, rest)

(d log 2π + rest) / 2, the average energy of a d-dimensional normal given rest, the remainder of its expectation, such as E[(x - μ)ᵀ Λ (x - μ)] - E[log det Λ]. It is in rest's float type, a Float64 for an integer rest: d * log2π alone is a Float64 for an integer d, whatever the inputs.

Examples

julia> MessagePassingRulesBase.gaussian_average_energy(1, 0.0f0) isa Float32
true
source
MessagePassingRulesBase.gaussian_coupled_precision — Function
gaussian_coupled_precision(W_out, W_μ, W_bar)

The precision of the joint of out and μ when out is normal around μ with precision W_bar, and out and μ carry messages of precisions W_out and W_μ: [W_out + W_bar -W_bar; -W_bar W_μ + W_bar], for numbers and matrices alike.

Examples

julia> MessagePassingRulesBase.gaussian_coupled_precision(1.0, 2.0, 0.5)
2×2 Matrix{Float64}:
  1.5  -0.5
 -0.5   2.5
source
MessagePassingRulesBase.gaussian_series_precision — Function
gaussian_series_precision(Λ, Λ_f)

The precision of a normal of precision Λ passed through normal noise of precision Λ_f, (Λ⁻¹ + Λ_f⁻¹)⁻¹, computed as Λ - Λ (Λ + Λ_f)⁻¹ Λ with one Cholesky factorisation. The mean is unchanged.

source