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)| interface | aliases | |
|---|---|---|
y | out | |
x | ||
θ | ||
γ |
| default algorithm | MessagePassingRulesBase.DefaultAlgorithm() |
|---|---|
| static inputs | none |
| defined | src/autoregressive.jl:136 |
The node has four interfaces; y also answers to out.
| name | aliases | meaning | messages and marginals its rules take |
|---|---|---|---|
y | out | the current state | a normal message; q(y) of any type with a mean and covariance |
x | the previous state | a normal message; q(x) of any type with a mean and covariance | |
θ | the coefficients, of dimension p | q(θ) with a mean and covariance, a normal in practice | |
γ | the precision of the noise | q(γ) 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:Univariatefor an AR(1) with scalar edges, orMultivariate;order: the orderp;Univariateforces it to1, with a warning for any other value;stype:ARsafe(), which forms the jointq(y, x)from its precision, regularising the noiseless components with a large finite precision, orARunsafe(), 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)| DefaultAlgorithm | ARVMP{<: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 whichyandxexchange messages by belief propagation and the rules towardsθandγread the jointq(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]),),
)Result
| value | ExponentialFamily.GammaShapeRate{Float64}(a=1.5, b=2.6875) |
|---|---|
| type | ExponentialFamily.GammaShapeRate{Float64} |
| log scale | undefined: the message rule for AR towards :γ under ARVMP declares no `logscale` |
Inputs
| edge | value | |
|---|---|---|
| y | q | MvNormalMeanCovariance( μ: [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] |
| x | q | q[:y, :x] |
| θ | q | MvNormalMeanCovariance( μ: [0.5, 0.25] Σ: [1.0 0.0; 0.0 1.0] ) |
Rule
| declared inputs | q[:y, :x]::Union{ExponentialFamily.MultivariateNormalDistributionsFamily{T}, ExponentialFamily.MultivariateGaussianDistributionsFamily{T}} where T, q[:θ]::Any |
|---|---|
| algorithm | ARVMP{Multivariate, ARsafe}(2, ARsafe()) |
| log scale | none |
| defined | src/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
trueLimitations
- 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
yandxmust be normals of the algorithm's variate form.
API
The node and its alias:
AutoregressiveMessagePassingRules.AR — Type
ARThe 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(aliasout): 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 dimensionp(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.
AutoregressiveMessagePassingRules.Autoregressive — Type
AutoregressiveAn alias for AR, the autoregressive node.
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:UnivariateorMultivariate, the variate form ofyandx.Univariateis an AR(1) with scalar edges, and forcesorderto1, with a warning for any other value;order: the orderp, the dimension of the state and ofθ;stype:ARsafe()orARunsafe(), how the jointq(y, x)is formed.
Examples
julia> ARVMP(Multivariate, 3, ARsafe()) isa ARVMP
trueAutoregressiveMessagePassingRules.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.
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.
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
ArgumentErrorwhenlength < 1orindexis not in1: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