AR

Overview

AR is the autoregressive process of order p, whose current value is a linear combination of its p previous values plus Gaussian noise. It is the building block of latent autoregressive models, in which the states, the coefficients θ and the noise precision γ are all inferred, each with a prior of its own: a normal on θ, a gamma on γ. Chained over time, x[t] ~ AR(x[t - 1], θ, γ) in an RxInfer model, it is a state-space model whose transition is learnt.

The node is a stochastic node, a density over its variables. Its rules are variational: they compute messages from the marginals of the other variables, as variational message passing does.

Definition

For the state xₜ = (yₜ₋₁, …, yₜ₋ₚ):

\[p(y_t \mid x_t, \theta, \gamma) = \mathcal{N}\big(y_t \mid \theta^\top x_t, \, \gamma^{-1}\big).\]

For p > 1 the edges carry whole states: y = (yₜ, …, yₜ₋ₚ₊₁), related to x by the companion matrix A(θ), whose first row is θᵀ and whose sub-diagonal is ones, with noise on the first component only:

\[y = A(\theta)\, x + \varepsilon, \qquad A(\theta) = \begin{pmatrix} \theta_1 & \theta_2 & \cdots & \theta_{p-1} & \theta_p \\ 1 & 0 & \cdots & 0 & 0 \\ & \ddots & & & \vdots \\ 0 & 0 & \cdots & 1 & 0 \end{pmatrix}, \qquad \varepsilon \sim \mathcal{N}\big(0, \operatorname{diag}(\gamma^{-1}, 0, \dots, 0)\big).\]

The other components of y are copies of those of x, so the node's density is degenerate in them; the rules and the average energy account for that.

Interfaces

using AutoregressiveMessagePassingRules, MessagePassingRulesBase, BayesBase, ExponentialFamily
MessagePassingRulesBase.nodespec(AR)
NodeSpec: AR
xθγy (out)ARstochastic
interfacealiases
yout
x
θ
γ
default algorithmMessagePassingRulesBase.DefaultAlgorithm()
static inputsnone
definedsrc/autoregressive.jl:136

The node has four interfaces; y also answers to out.

namealiasesmeaningmessages and marginals its rules take
youtthe current statea normal message; q(y) of any type with a mean and covariance
xthe previous statea normal message; q(x) of any type with a mean and covariance
θthe coefficients, of dimension pq(θ) with a mean and covariance, a normal in practice
γthe precision of the noiseq(γ) with mean and mean(log, ·), a gamma in practice

Under ARVMP(Univariate, 1, …) every edge is a scalar; under ARVMP(Multivariate, p, …) y, x and θ are vectors of length p, even for p = 1. Messages of the other form raise a MethodError. The joint marginal q(y, x) is a multivariate normal of dimension 2p, y first.

Algorithm

The node's rules run under the algorithm ARVMP(form, order, stype), which the model must name: the node declares no algorithm of its own, and under DefaultAlgorithm it has no rule. All three arguments are required, without defaults:

  • form: Univariate for an AR(1) with scalar edges, or Multivariate;
  • order: the order p; Univariate forces it to 1, with a warning for any other value;
  • stype: ARsafe(), which forms the joint q(y, x) from its precision, regularising the noiseless components with a large finite precision, or ARunsafe(), which forms it from its covariance, exactly, through the Kalman gain. The two agree up to that regularisation, and exactly for a univariate AR(1).

ARVMP declares no dependencies: dependencies_spec returns nothing, and each rule takes the inputs of the default scheme.

Supported rules

MessagePassingRulesBase.rule_coverage(AR)
Rule coverage for AR
DefaultAlgorithmARVMP{<:VariateForm, _}
→ y✓×2
→ x✓×2
→ θ✓×2
→ γ✓×2
q(y, x)✓
average energy✓×2

Every rule is under ARVMP, none under the default algorithm. Each target has two rules, one for each factorisation:

  • the structured q(y, x) q(θ) q(γ), in which y and x exchange messages by belief propagation and the rules towards θ and γ read the joint q(y, x);
  • the mean field q(y) q(x) q(θ) q(γ), in which every rule reads marginals only.

The joint marginal q(y, x) has a rule from the messages on y and x. Both factorisations have an average energy, so the node contributes to the Bethe free energy.

Example

The message towards γ of an AR(2), from the joint marginal of the states and the marginal of the coefficients: a gamma of shape 3/2 whose rate is half the expected squared residual.

@call_message_update_rule(
    node = AR, target = :γ, algorithm = ARVMP(Multivariate, 2, ARsafe()),
    clusters = ((:y, :x) => MvNormalMeanCovariance(ones(4), [1.0 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]),),
    q = (θ = MvNormalMeanCovariance([0.5, 0.25], [1.0 0.0; 0.0 1.0]),),
)
RuleResult: message of AR towards :γmarginals
yxθγAR
Result
valueExponentialFamily.GammaShapeRate{Float64}(a=1.5, b=2.6875)
typeExponentialFamily.GammaShapeRate{Float64}
log scaleundefined: the message rule for AR towards :γ under ARVMP declares no `logscale`
Inputs
edgevalue
yqMvNormalMeanCovariance( μ: [1.0, 1.0, 1.0, 1.0] Σ: [1.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0; 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 1.0]… q[:y, :x]
xq q[:y, :x]
θqMvNormalMeanCovariance( μ: [0.5, 0.25] Σ: [1.0 0.0; 0.0 1.0] )
Rule
declared inputsq[:y, :x]::Union{ExponentialFamily.MultivariateNormalDistributionsFamily{T}, ExponentialFamily.MultivariateGaussianDistributionsFamily{T}} where T, q[:θ]::Any
algorithmARVMP{Multivariate, ARsafe}(2, ARsafe())
log scalenone
definedsrc/autoregressive.jl:380
body
(algo, args)->begin
        order = getorder(algo)
        F = getvform(algo)
        (y_x_mean, y_x_cov) = mean_cov(args.q[:y, :x])
        (mθ, Vθ) = mean_cov(args.q[:θ])
        mA = as_companion_matrix(mθ)
        (my, Vy) = (ar_slice(F, y_x_mean, 1:order), ar_slice(F, y_x_cov, 1:order, 1:order))
        (mx, Vx) = (ar_slice(F, y_x_mean, order + 1:2order), ar_slice(F, y_x_cov, order + 1:2order, order + 1:2order))
        Vxy = ar_slice(F, y_x_cov, order + 1:2order, 1:order)
        C = add_outer(Vx, mx)
        R = add_outer(Vy, my)
        L = gaussian_cross_moment(Vxy, mx, my)
        B = (first(R) - 2 * first(mA * L)) + first(mA * C * mA') + trace_product(Vθ, C)
        GammaShapeRate(convert(eltype(B), 3 // 2), B / 2)
    end
Other rules for this target (1)
src/autoregressive.jl:405
✓algorithm ARVMP
✗q[:y]::Any not provided
✗q[:x]::Any not provided
✓q[:θ]::Any got ExponentialFamily.MvNormalMeanCovariance{Float64, Vector{Float64}, Matrix{Float64}}
✗q[:y, :x]::ExponentialFamily.MvNormalMeanCovariance{Float64, Vector{Float64}, Matrix{Float64}} provided but not consumed

@call_message_update_rule runs the rule and draws the marginals it read, the joint q(y, x) among them. getresult extracts the message:

julia> result = @call_message_update_rule(
           node = AR, target = :γ, algorithm = ARVMP(Multivariate, 2, ARsafe()),
           clusters = ((:y, :x) => MvNormalMeanCovariance(ones(4), [1.0 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]),),
           q = (θ = MvNormalMeanCovariance([0.5, 0.25], [1.0 0.0; 0.0 1.0]),),
       );

julia> shape(getresult(result)) ≈ 1.5 && rate(getresult(result)) ≈ 2.6875
true

Limitations

  • A model must give ARVMP; without it the node has no rule.
  • The rules are variational only: there is no belief propagation towards θ or γ, so both need an initial marginal, as does any edge a mean-field schedule reads first.
  • The messages on y and x must be normals of the algorithm's variate form.

API

The node and its alias:

AutoregressiveMessagePassingRules.AR — Type
AR

The autoregressive node of order p, a Bayesian autoregressive process with the coefficients θ and the precision γ on edges of their own:

\[p(y \mid x, \theta, \gamma) = \mathcal{N}\big(y_1 \mid \theta^\top x, \, \gamma^{-1}\big).\]

For p > 1 the edges y and x carry the whole state: x = (yₜ₋₁, …, yₜ₋ₚ) and y = (yₜ, …, yₜ₋ₚ₊₁), related by the companion matrix A(θ), whose first row is θᵀ and whose sub-diagonal is ones, under noise on the first component only:

\[y = A(\theta)\, x + \varepsilon, \qquad \varepsilon \sim \mathcal{N}(0, \operatorname{diag}(\gamma^{-1}, 0, \dots, 0)).\]

For p = 1 under ARVMP(Univariate, …) every edge is a scalar.

Interfaces

  • y (alias out): the current state, a normal, univariate or multivariate by the algorithm's form;
  • x: the previous state, a normal of the same form and dimension;
  • θ: the coefficients, a normal of dimension p (univariate for an AR(1));
  • γ: the precision of the noise on the first component, a gamma.

Its rules run under ARVMP, which the model must give, since the variate form and the order are properties of the model rather than of the node. The node declares no algorithm of its own: under DefaultAlgorithm no rule exists, and a model that names none gets a "no message rule" error.

The rules follow the factorisation: the structured q(y, x) q(θ) q(γ), with belief propagation between y and x and the joint marginal q(y, x), or the mean field q(y) q(x) q(θ) q(γ). Both have an average energy. ConjugateAR keeps (θ, γ) joint on one edge. Also available as Autoregressive.

Examples

julia> algorithm = ARVMP(Univariate, 1, ARsafe());

julia> result = @call_message_update_rule(
           node = AR, target = :y, algorithm = algorithm,
           m = (x = NormalMeanVariance(1.0, 1.0),),
           q = (θ = NormalMeanVariance(1.0, 1.0), γ = GammaShapeRate(1.0, 1.0)),
       );

julia> mean_var(getresult(result)) .≈ (0.5, 1.5)
(true, true)

See also ConjugateAR, ARVMP.

source

Its algorithm, and the two ways it forms the joint q(y, x):

AutoregressiveMessagePassingRules.ARVMP — Type
ARVMP(form, order, stype)

The algorithm of AR and ConjugateAR: variational message passing for a state of the given form and order. Every argument is required, and neither node has a default algorithm, so the model must give one.

Arguments

  • form: Univariate or Multivariate, the variate form of y and x. Univariate is an AR(1) with scalar edges, and forces order to 1, with a warning for any other value;
  • order: the order p, the dimension of the state and of θ;
  • stype: ARsafe() or ARunsafe(), how the joint q(y, x) is formed.

Examples

julia> ARVMP(Multivariate, 3, ARsafe()) isa ARVMP
true
source
AutoregressiveMessagePassingRules.ARsafe — Type
ARsafe()

The numerically safe mode of ARVMP: the joint q(y, x) is formed from its precision matrix, the noiseless components of the state regularised by a large finite precision (huge from BayesBase). The result is exact up to that regularisation. Use it by default.

source
AutoregressiveMessagePassingRules.ARunsafe — Type
ARunsafe()

The unregularised mode of ARVMP: the joint q(y, x) is formed from its covariance, by conditioning the prior joint of (y, x) on the message on y through the Kalman gain. It needs no precision of the noise, so it regularises nothing, and agrees with ARsafe up to that one's regularisation; it may be numerically fragile when the joint covariance is close to singular. For a univariate AR(1) the two modes give the same result.

source

The vector that picks one component, which the rules use for the first component of the state:

AutoregressiveMessagePassingRules.StandardBasisVector — Type
AutoregressiveMessagePassingRules.StandardBasisVector(length::Int, index::Int, scale = 1)

The vector of length entries that is zero everywhere except for scale at index, the standard basis vector scale ⋅ eᵢ, held as those three numbers. The AR rules use e₁ to pick the first component of the state; a model can use one to pick an entry of a vector, as in softdot(x, StandardBasisVector(n, j), γ) with the SoftDot node, in place of a dense one-hot vector, which gives the same messages more slowly: the products the rules form read one entry instead of length.

It is an AbstractVector, so it works wherever a vector does. The products written out without building the dense vector are those with a number, dot with a dense Vector or another basis vector, dot(e₁, A, e₂) and A * e with a dense Matrix, v * eᵀ, and scaled_outer(e, a). Any other operation reads its entries.

Throws

  • ArgumentError when length < 1 or index is not in 1:length.

Examples

julia> e = AutoregressiveMessagePassingRules.StandardBasisVector(3, 2)
3-element AutoregressiveMessagePassingRules.StandardBasisVector{Int64}:
 0
 1
 0

julia> using LinearAlgebra: dot

julia> dot(e, [10.0, 20.0, 30.0])
20.0
source