How to read this lecture...

Code should execute sequentially if run in a Jupyter notebook

Additive Functionals

Co-authors: Chase Coleman and Balint Szoke

Overview

Some time series are nonstationary

For example, output, prices, and dividends are typically nonstationary, due to irregular but persistent growth

Which kinds of models are useful for studying such time series?

Hansen and Scheinkman [HS09] analyze two classes of time series models that accommodate growth

They are:

  1. additive functionals that display random “arithmetic growth”
  2. multiplicative functionals that display random “geometric growth”

These two classes of processes are closely connected

For example, if a process \(\{y_t\}\) is an additive functional and \(\phi_t = \exp(y_t)\), then \(\{\phi_t\}\) is a multiplicative functional

Hansen and Sargent [HS17] (chs. 5 and 6) describe discrete time versions of additive and multiplicative functionals

In this lecture we discuss the former (i.e., additive functionals)

In the next lecture we discuss multiplicative functionals

We also consider fruitful decompositions of additive and multiplicative processes, a more in depth discussion of which can be found in Hansen and Sargent [HS17]

A Particular Additive Functional

This lecture focuses on a particular type of additive functional: a scalar process \(\{y_t\}_{t=0}^\infty\) whose increments are driven by a Gaussian vector autoregression

It is simple to construct, simulate, and analyze

This additive functional consists of two components, the first of which is a first-order vector autoregression (VAR)

(1)\[x_{t+1} = A x_t + B z_{t+1}\]

Here

  • \(x_t\) is an \(n \times 1\) vector,
  • \(A\) is an \(n \times n\) stable matrix (all eigenvalues lie within the open unit circle),
  • \(z_{t+1} \sim {\cal N}(0,I)\) is an \(m \times 1\) i.i.d. shock,
  • \(B\) is an \(n \times m\) matrix, and
  • \(x_0 \sim {\cal N}(\mu_0, \Sigma_0)\) is a random initial condition for \(x\)

The second component is an equation that expresses increments of \(\{y_t\}_{t=0}^\infty\) as linear functions of

  • a scalar constant \(\nu\),
  • the vector \(x_t\), and
  • the same Gaussian vector \(z_{t+1}\) that appears in the VAR (1)

In particular,

(2)\[y_{t+1} - y_{t} = \nu + D x_{t} + F z_{t+1}\]

Here \(y_0 \sim {\cal N}(\mu_{y0}, \Sigma_{y0})\) is a random initial condition

The nonstationary random process \(\{y_t\}_{t=0}^\infty\) displays systematic but random arithmetic growth

A linear state space representation

One way to represent the overall dynamics is to use a linear state space system

To do this, we set up state and observation vectors

\[\begin{split}\hat{x}_t = \begin{bmatrix} 1 \\ x_t \\ y_t \end{bmatrix} \quad \text{and} \quad \hat{y}_t = \begin{bmatrix} x_t \\ y_t \end{bmatrix}\end{split}\]

Now we construct the state space system

\[\begin{split} \begin{bmatrix} 1 \\ x_{t+1} \\ y_{t+1} \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 \\ 0 & A & 0 \\ \nu & D' & 1 \\ \end{bmatrix} \begin{bmatrix} 1 \\ x_t \\ y_t \end{bmatrix} + \begin{bmatrix} 0 \\ B \\ F' \end{bmatrix} z_{t+1}\end{split}\]
\[\begin{split}\begin{bmatrix} x_t \\ y_t \end{bmatrix} = \begin{bmatrix} 0 & I & 0 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 \\ x_t \\ y_t \end{bmatrix}\end{split}\]

This can be written as

\[\begin{split}\begin{aligned} \hat{x}_{t+1} &= \hat{A} \hat{x}_t + \hat{B} z_{t+1} \\ \hat{y}_{t} &= \hat{D} \hat{x}_t \end{aligned}\end{split}\]

which is a standard linear state space system

To study it, we could map it into an instance of LSS from QuantEcon.jl

We will in fact use a different set of code for simulation, for reasons described below

Dynamics

Let’s run some simulations to build intuition

In doing so we’ll assume that \(z_{t+1}\) is scalar and that \(\tilde x_t\) follows a 4th-order scalar autoregession

(3)\[\tilde x_{t+1} = \phi_1 \tilde x_{t} + \phi_2 \tilde x_{t-1} + \phi_3 \tilde x_{t-2} + \phi_4 \tilde x_{t-3} + \sigma z_{t+1}\]

Let the increment in \(\{y_t\}\) obey

\[y_{t+1} - y_t = \nu + \tilde x_t + \sigma z_{t+1}\]

with an initial condition for \(y_0\)

While (3) is not a first order system like (1), we know that it can be mapped into a first order system

In fact this whole model can be mapped into the additive functional system definition in (1)(2) by appropriate selection of the matrices \(A, B, D, F\)

You can try writing these matrices down now as an exercise — the correct expressions will appear in the code below

Simulation

When simulating we embed our variables into a bigger system

This system also constructs the components of the decompositions of \(y_t\) and of \(\exp(y_t)\) proposed by Hansen and Scheinkman [HS09]

All of these objects are computed using the class AMF_LSS_VAR

The code is repeated here for convenience

#=

Author: Shunsuke Hori

=#
using QuantEcon
using PyPlot
using Distributions

"""
This type transforms an additive (multipilcative)
functional into a QuantEcon linear state space system.
"""
struct AMF_LSS_VAR{TF<:AbstractFloat, TI<:Integer}
    A::Array{TF, 2}
    B::Array{TF, 2}
    D::Array{TF, 2}
    F::Array{TF, 2}
    ν::Array{TF, 2}
    nx::TI
    nk::TI
    nm::TI
    lss::LSS
end

function AMF_LSS_VAR(A::Array, B::Array,
                D::Union{RowVector, Array},
                F::Union{Void, Array}=nothing;
                ν::Union{Void, Array}=nothing)
    
    if typeof(B) <: Vector
        B = reshape(B, length(B), 1)
    end
    # Unpack required elements
    nx, nk = size(B)

    # checking the dimension of D (extended from the scalar case)
    if ndims(D) > 1
        nm = size(D, 1)
        if typeof(D) <: RowVector
            D = convert(Matrix, D)
        end
    else
        nm = 1
        D = reshape(D, 1, length(D))
    end

    # Set F
    if F==nothing
        F = zeros(nk, 1)
    elseif ndims(F) == 1
        F = reshape(F, length(F), 1)
    end

    # Set ν
    if ν==nothing
        ν = zeros(nm, 1)
    elseif ndims(ν) == 1
        ν = reshape(ν, length(ν), 1)
    else
        throw(ArgumentError("ν must be column vector!"))
    end

    if size(ν, 1) != size(D, 1)
        error("The size of ν is inconsistent with D!")
    end

    # Construct BIG state space representation
    lss = construct_ss(A, B, D, F, ν, nx, nk, nm)

    return AMF_LSS_VAR(A, B, D, F, ν, nx, nk, nm, lss)
end

AMF_LSS_VAR(A::Array, B::Array, D::Union{RowVector, Array}) = 
    AMF_LSS_VAR(A, B, D, nothing, ν=nothing)
AMF_LSS_VAR(A::Array, B::Array, D::Union{RowVector, Array}, F::Real, ν::Real) = 
    AMF_LSS_VAR(A, B, D, [F], ν=[ν])

"""
This creates the state space representation that can be passed
into the quantecon LSS class.
"""
function construct_ss(A::Array, B::Array, D::Union{RowVector, Array}, F::Array,
                      ν, nx::TI, nk::TI, nm::TI) where TI <: Integer

    H, g = additive_decomp(A, B, D, F, nx)

    # Auxiliary blocks with 0's and 1's to fill out the lss matrices
    nx0c = zeros(nx, 1)
    nx0r = zeros(1, nx)
    nx1 = ones(1, nx)
    nk0 = zeros(1, nk)
    ny0c = zeros(nm, 1)
    ny0r = zeros(1, nm)
    ny1m = eye(nm)
    ny0m = zeros(nm, nm)
    nyx0m = zeros(D)

    # Build A matrix for LSS
    # Order of states is: [1, t, xt, yt, mt]
    A1 = hcat(1, 0, nx0r, ny0r, ny0r)          # Transition for 1
    A2 = hcat(1, 1, nx0r, ny0r, ny0r)          # Transition for t
    A3 = hcat(nx0c, nx0c, A, nyx0m', nyx0m')   # Transition for x_{t+1}
    A4 = hcat(ν, ny0c, D, ny1m, ny0m)          # Transition for y_{t+1}
    A5 = hcat(ny0c, ny0c, nyx0m, ny0m, ny1m)   # Transition for m_{t+1}
    Abar = vcat(A1, A2, A3, A4, A5)

    # Build B matrix for LSS
    Bbar = vcat(nk0, nk0, B, F, H)

    # Build G matrix for LSS
    # Order of observation is: [xt, yt, mt, st, tt]
    G1 = hcat(nx0c, nx0c, eye(nx), nyx0m', nyx0m')    # Selector for x_{t}
    G2 = hcat(ny0c, ny0c, nyx0m, ny1m, ny0m)          # Selector for y_{t}
    G3 = hcat(ny0c, ny0c, nyx0m, ny0m, ny1m)          # Selector for martingale
    G4 = hcat(ny0c, ny0c, -g, ny0m, ny0m)             # Selector for stationary
    G5 = hcat(ny0c, ν, nyx0m, ny0m, ny0m)             # Selector for trend
    Gbar = vcat(G1, G2, G3, G4, G5)

    # Build LSS type
    x0 = hcat(1, 0, nx0r, ny0r, ny0r)
    S0 = zeros(length(x0), length(x0))
    lss = LSS(Abar, Bbar, Gbar, zeros(nx+4nm, 1), x0, S0)

    return lss
end

"""
Return values for the martingale decomposition
    - ν         : unconditional mean difference in Y
    - H         : coefficient for the (linear) martingale component (kappa_a)
    - g         : coefficient for the stationary component g(x)
    - Y_0       : it should be the function of X_0 (for now set it to 0.0)
"""
function additive_decomp(A::Array, B::Array, D::Array, F::Union{Array, Real},
                          nx::Integer)
    I = eye(nx)
    A_res = \(I-A, I)
    g = D * A_res
    H = F + D * A_res * B

    return H, g
end


"""
Return values for the multiplicative decomposition (Example 5.4.4.)
    - ν_tilde  : eigenvalue
    - H         : vector for the Jensen term
"""
function multiplicative_decomp(A::Array, B::Array, D::Array, F::Union{Array, Real},
                                ν::Union{Array, Real}, nx::Integer)
    H, g = additive_decomp(A, B, D, F, nx)
    ν_tilde = ν + 0.5*diag(H*H')

    return H, g, ν_tilde
end

function loglikelihood_path(amf::AMF_LSS_VAR, x::Array, y::Array)
    A, B, D, F = amf.A, amf.B, amf.D, amf.F
    k, T = size(y)
    FF = F*F'
    FFinv = inv(FF)
    temp = y[:, 2:end]-y[:, 1:end-1] - D*x[:, 1:end-1]
    obs =  temp .* FFinv .* temp
    obssum = cumsum(obs)
    scalar = (log(det(FF)) + k*log(2*pi))*collect(1:T)

    return -0.5*(obssum + scalar)
end

function loglikelihood(amf::AMF_LSS_VAR, x::Array, y::Array)
    llh = loglikelihood_path(amf, x, y)

    return llh[end]
end

"""
Plots for the additive decomposition
"""
function plot_additive(amf::AMF_LSS_VAR, T::Integer;
                       npaths::Integer=25, show_trend::Bool=true)

    # Pull out right sizes so we know how to increment
    nx, nk, nm = amf.nx, amf.nk, amf.nm

    # Allocate space (nm is the number of additive functionals - we want npaths for each)
    mpath = Array{Real}(nm*npaths, T)
    mbounds = Array{Real}(nm*2, T)
    spath = Array{Real}(nm*npaths, T)
    sbounds = Array{Real}(nm*2, T)
    tpath = Array{Real}(nm*npaths, T)
    ypath = Array{Real}(nm*npaths, T)

    # Simulate for as long as we wanted
    moment_generator = moment_sequence(amf.lss)
    state = start(moment_generator)
    # Pull out population moments
    for t in 1:T
        tmoms, state = next(moment_generator, state)
        ymeans = tmoms[2]
        yvar = tmoms[4]

        # Lower and upper bounds - for each additive functional
        for ii in 1:nm
            li, ui = (ii-1)*2+1, ii*2
            if sqrt(yvar[nx+nm+ii, nx+nm+ii]) != 0.0
                madd_dist = Normal(ymeans[nx+nm+ii], sqrt(yvar[nx+nm+ii, nx+nm+ii]))
                mbounds[li, t] = quantile(madd_dist, 0.01)
                mbounds[ui, t] = quantile(madd_dist, 0.99)
            elseif sqrt(yvar[nx+nm+ii, nx+nm+ii]) == 0.0
                mbounds[li, t] = ymeans[nx+nm+ii]
                mbounds[ui, t] = ymeans[nx+nm+ii]
            else
                error("standard error is negative")
            end

            if sqrt(yvar[nx+2*nm+ii, nx+2*nm+ii]) != 0.0
                sadd_dist = Normal(ymeans[nx+2*nm+ii], sqrt(yvar[nx+2*nm+ii, nx+2*nm+ii]))
                sbounds[li, t] = quantile(sadd_dist, 0.01)
                sbounds[ui, t] = quantile(sadd_dist, 0.99)
            elseif sqrt(yvar[nx+2*nm+ii, nx+2*nm+ii]) == 0.0
                sbounds[li, t] = ymeans[nx+2*nm+ii]
                sbounds[ui, t] = ymeans[nx+2*nm+ii]
            else
                error("standard error is negative")
            end
                
        end
    end

    # Pull out paths
    for n in 1:npaths
        x, y = simulate(amf.lss,T)
        for ii in 0:nm-1
            ypath[npaths*ii+n, :] = y[nx+ii+1, :]
            mpath[npaths*ii+n, :] = y[nx+nm + ii+1, :]
            spath[npaths*ii+n, :] = y[nx+2*nm + ii+1, :]
            tpath[npaths*ii+n, :] = y[nx+3*nm + ii+1, :]
        end
    end

    add_figs = Array{Any}(nm)
    
    for ii in 0:nm-1
        li, ui = npaths*(ii), npaths*(ii+1)
        LI, UI = 2*(ii), 2*(ii+1)
        add_figs[ii+1] = 
            plot_given_paths(T, ypath[li+1:ui, :], mpath[li+1:ui, :], spath[li+1:ui, :],
                             tpath[li+1:ui, :], mbounds[LI+1:UI, :], sbounds[LI+1:UI, :],
                             show_trend=show_trend)

        add_figs[ii+1][:suptitle]( L"Additive decomposition of $y_{$(ii+1)}$", fontsize=14 )
    end

    return add_figs
end

"""
Plots for the multiplicative decomposition
"""
function plot_multiplicative(amf::AMF_LSS_VAR, T::Integer,
                            npaths::Integer=25, show_trend::Bool=true)
    # Pull out right sizes so we know how to increment
    nx, nk, nm = amf.nx, amf.nk, amf.nm
    # Matrices for the multiplicative decomposition
    H, g, ν_tilde = multiplicative_decomp(A, B, D, F, ν, nx)

    # Allocate space (nm is the number of functionals - we want npaths for each)
    mpath_mult = Array{Real}(nm*npaths, T)
    mbounds_mult = Array{Real}(nm*2, T)
    spath_mult = Array{Real}(nm*npaths, T)
    sbounds_mult = Array{Real}(nm*2, T)
    tpath_mult = Array{Real}(nm*npaths, T)
    ypath_mult = Array{Real}(nm*npaths, T)

    # Simulate for as long as we wanted
    moment_generator = moment_sequence(amf.lss)
    state = start(moment_generator)
    # Pull out population moments
    for t in 1:T
        tmoms, state = next(moment_generator, state)
        ymeans = tmoms[2]
        yvar = tmoms[4]

        # Lower and upper bounds - for each multiplicative functional
        for ii in 1:nm
            li, ui = (ii-1)*2+1, ii*2
            if yvar[nx+nm+ii, nx+nm+ii] != 0.0
                Mdist = LogNormal(ymeans[nx+nm+ii]- t*0.5*diag(H * H')[ii], 
                                sqrt(yvar[nx+nm+ii, nx+nm+ii]))
                mbounds_mult[li, t] = quantile(Mdist, 0.01)
                mbounds_mult[ui, t] = quantile(Mdist, 0.99)
            elseif yvar[nx+nm+ii, nx+nm+ii] == 0.0
                mbounds_mult[li, t] = exp.(ymeans[nx+nm+ii]- t*0.5*diag(H * H')[ii])
                mbounds_mult[ui, t] = exp.(ymeans[nx+nm+ii]- t*0.5*diag(H * H')[ii])
            else
                error("standard error is negative")
            end
            if yvar[nx+2*nm+ii, nx+2*nm+ii] != 0.0
                Sdist = LogNormal(-ymeans[nx+2*nm+ii],
                                sqrt(yvar[nx+2*nm+ii, nx+2*nm+ii]))
                sbounds_mult[li, t] = quantile(Sdist, 0.01)
                sbounds_mult[ui, t] = quantile(Sdist, 0.99)
            elseif yvar[nx+2*nm+ii, nx+2*nm+ii] == 0.0
                sbounds_mult[li, t] = exp.(-ymeans[nx+2*nm+ii])
                sbounds_mult[ui, t] = exp.(-ymeans[nx+2*nm+ii])
            else
                error("standard error is negative")
            end
        end
    end

    # Pull out paths
    for n in 1:npaths
        x, y = simulate(amf.lss,T)
        for ii in 0:nm-1
            ypath_mult[npaths*ii+n, :] = exp.(y[nx+ii+1, :])
            mpath_mult[npaths*ii+n, :] = 
                exp.(y[nx+nm + ii+1, :] - collect(1:T)*0.5*diag(H * H')[ii+1])
            spath_mult[npaths*ii+n, :] = 1./exp.(-y[nx+2*nm + ii+1, :])
            tpath_mult[npaths*ii+n, :] = 
                exp.(y[nx+3*nm + ii+1, :] + collect(1:T)*0.5*diag(H * H')[ii+1])
        end
    end

    mult_figs = Array{Any}(nm)
    
    for ii in 0:nm-1
        li, ui = npaths*(ii), npaths*(ii+1)
        LI, UI = 2*(ii), 2*(ii+1)
        mult_figs[ii+1] = 
            plot_given_paths(T, ypath_mult[li+1:ui, :], mpath_mult[li+1:ui, :],
                             spath_mult[li+1:ui, :], tpath_mult[li+1:ui, :],
                             mbounds_mult[LI+1:UI, :], sbounds_mult[LI+1:UI, :],
                             horline = 1.0, show_trend=show_trend)
        mult_figs[ii+1][:suptitle]( L"Multiplicative decomposition of $y_{$(ii+1)}$", 
                                    fontsize=14)
    end

    return mult_figs
end

function plot_martingales(amf::AMF_LSS_VAR, T::Integer, npaths::Integer=25)

    # Pull out right sizes so we know how to increment
    nx, nk, nm = amf.nx, amf.nk, amf.nm
    # Matrices for the multiplicative decomposition
    H, g, ν_tilde = multiplicative_decomp(amf.A, amf.B, amf.D, amf.F, amf.ν, amf.nx)

    # Allocate space (nm is the number of functionals - we want npaths for each)
    mpath_mult = Array{Real}(nm*npaths, T)
    mbounds_mult = Array{Real}(nm*2, T)

    # Simulate for as long as we wanted
    moment_generator = moment_sequence(amf.lss)
    state = start(moment_generator)
    # Pull out population moments
    for t in 1:T
        tmoms, state = next(moment_generator, state)
        ymeans = tmoms[2]
        yvar = tmoms[4]

        # Lower and upper bounds - for each functional
        for ii in 1:nm
            li, ui = (ii-1)*2+1, ii*2
            if yvar[nx+nm+ii, nx+nm+ii] != 0.0
                Mdist = LogNormal(ymeans[nx+nm+ii]-t*(.5)*diag(H*H')[ii],
                            sqrt(yvar[nx+nm+ii, nx+nm+ii]))
                mbounds_mult[li, t] = quantile(Mdist, 0.01)
                mbounds_mult[ui, t] = quantile(Mdist, 0.99)
            elseif yvar[nx+nm+ii, nx+nm+ii] == 0.0
                mbounds_mult[li, t] = ymeans[nx+nm+ii]-t*(.5)*diag(H*H')[ii]
                mbounds_mult[ui, t] = ymeans[nx+nm+ii]-t*(.5)*diag(H*H')[ii]
            else
                error("standard error is negative")
            end
        end
    end

    # Pull out paths
    for n in 1:npaths
        x, y = simulate(amf.lss, T)
        for ii in 0:nm-1
            mpath_mult[npaths*ii+n, :] = 
                exp.(y[nx+nm + ii+1, :] - (1:T)*0.5*diag(H*H')[ii+1])
        end
    end

    mart_figs = Array{Any}(nm)

    for ii in 0:nm-1
        li, ui = npaths*(ii), npaths*(ii+1)
        LI, UI = 2*(ii), 2*(ii+1)
        mart_figs[ii+1] = plot_martingale_paths(T, mpath_mult[li+1:ui, :],
                                                    mbounds_mult[LI+1:UI, :], horline=1)
        mart_figs[ii+1][:suptitle](L"Martingale components for many paths of $y_{ii+1}$",
                                   fontsize=14)
    end

    return mart_figs
end

function plot_given_paths(T::Integer,
                        ypath::Array, mpath::Array, spath::Array, tpath::Array,
                        mbounds::Array, sbounds::Array; horline::Real=0.0,
                        show_trend::Bool = true)

    # Allocate space
    trange = 1:T

    # Create figure
    fig, ax = subplots(2, 2, sharey=true, figsize=(15, 8))

    # Plot all paths together
    ax[1, 1][:plot](trange, ypath[1, :], label=L"$y_t$", color="k")
    ax[1, 1][:plot](trange, mpath[1, :], label=L"$m_t$", color="m")
    ax[1, 1][:plot](trange, spath[1, :], label=L"$s_t$", color="g")
    if show_trend == true
        ax[1, 1][:plot](trange, tpath[1, :], label=L"t_t", color="r")
    end
    ax[1, 1][:axhline](horline, color="k", linestyle = "-.")
    ax[1, 1][:set_title]("One Path of All Variables")
    ax[1, 1][:legend](loc="top left")

    # Plot Martingale Component
    ax[1, 2][:plot](trange, mpath[1, :], "m")
    ax[1, 2][:plot](trange, mpath', alpha=0.45, color="m")
    ub = mbounds[2, :]
    lb = mbounds[1, :]
    ax[1, 2][:fill_between](trange, lb, ub, alpha=0.25, color="m")
    ax[1, 2][:set_title]("Martingale Components for Many Paths")
    ax[1, 2][:axhline](horline, color="k", linestyle = "-.")

    # Plot Stationary Component
    ax[2, 1][:plot](spath[1, :], color="g")
    ax[2, 1][:plot](spath', alpha=0.25, color="g")
    ub = sbounds[2, :]
    lb = sbounds[1, :]
    ax[2, 1][:fill_between](trange, lb, ub, alpha=0.25, color="g")
    ax[2, 1][:axhline](horline, color="k", linestyle = "-.")
    ax[2, 1][:set_title]("Stationary Components for Many Paths")

    # Plot Trend Component
    if show_trend == true
        ax[2, 2][:plot](tpath', color="r")
    end
    ax[2, 2][:set_title]("Trend Components for Many Paths")
    ax[2, 2][:axhline](horline, color="k", linestyle = "-.")

    return fig
end

function plot_martingale_paths(T::Integer,
                        mpath::Array, mbounds::Array;
                        horline::Real=1,
                        show_trend::Bool = false)
    # Allocate space
    trange = 1:T

    # Create figure
    fig, ax = subplots(1, 1, figsize=(10, 6))

    # Plot Martingale Component
    ub = mbounds[2, :]
    lb = mbounds[1, :]
    ax[:fill_between](trange, lb, ub, color="#ffccff")
    ax[:axhline](horline, color="k", linestyle = "-.")
    ax[:plot](trange, mpath', linewidth=0.25, color="#4c4c4c")

    return fig
end

For now, we just plot \(y_t\) and \(x_t\), postponing until later a desciption of exactly how we compute them

ϕ_1, ϕ_2, ϕ_3, ϕ_4 = 0.5, -0.2, 0, 0.5
σ = 0.01
ν = 0.01 # Growth rate

# A matrix should be n x n
A = [ϕ_1 ϕ_2 ϕ_3 ϕ_4;
       1   0   0   0;
       0   1   0   0;
       0   0   1   0]

# B matrix should be n x k
B = [σ, 0, 0, 0]

D = [1 0 0 0] * A
F = dot([1, 0, 0, 0], vec(B))

amf = AMF_LSS_VAR(A, B, D, F, ν)

T = 150
x, y = simulate(amf.lss, T)

fig, ax = subplots(2, 1, figsize = (10, 9))

ax[1][:plot](1:T, y[amf.nx+1, :], color="k")
ax[1][:set_title]("A particular path of "*L"$y_t$")
ax[2][:plot](1:T, y[1, :], color="g")
ax[2][:axhline](0, color="k", linestyle="-.")
ax[2][:set_title]("Associated path of "*L"x_t")
../_images/output_6_1.png

Notice the irregular but persistent growth in \(y_t\)

Decomposition

Hansen and Sargent [HS17] describe how to construct a decomposition of an additive functional into four parts:

  • a constant inherited from initial values \(x_0\) and \(y_0\)
  • a linear trend
  • a martingale
  • an (asymptotically) stationary component

To attain this decomposition for the particular class of additive functionals defined by (1) and (2), we first construct the matrices

\[\begin{split}\begin{aligned} H & := F + B'(I - A')^{-1} D \\ g & := D' (I - A)^{-1} \end{aligned}\end{split}\]

Then the Hansen-Scheinkman [HS09] decomposition is

\[\begin{aligned} y_t &= \underbrace{t \nu}_{\text{trend component}} + \overbrace{\sum_{j=1}^t H z_j}^{\text{Martingale component}} - \underbrace{g x_t}_{\text{stationary component}} + \overbrace{g x_0 + y_0}^{\text{initial conditions}} \end{aligned}\]

At this stage you should pause and verify that \(y_{t+1} - y_t\) satisfies (2)

It is convenient for us to introduce the following notation:

  • \(\tau_t = \nu t\) , a linear, deterministic trend
  • \(m_t = \sum_{j=1}^t H z_j\), a martingale with time \(t+1\) increment \(H z_{t+1}\)
  • \(s_t = g x_t\), an (asymptotically) stationary component

We want to characterize and simulate components \(\tau_t, m_t, s_t\) of the decomposition.

A convenient way to do this is to construct an appropriate instance of a linear state space system by using LSS from QuantEcon.jl

This will allow us to use the routines in LSS to study dynamics

To start, observe that, under the dynamics in (1) and (2) and with the definitions just given,

\[\begin{split}\begin{bmatrix} 1 \\ t+1 \\ x_{t+1} \\ y_{t+1} \\ m_{t+1} \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & A & 0 & 0 \\ \nu & 0 & D' & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 \\ t \\ x_t \\ y_t \\ m_t \end{bmatrix} + \begin{bmatrix} 0 \\ 0 \\ B \\ F' \\ H' \end{bmatrix} z_{t+1}\end{split}\]

and

\[\begin{split}\begin{bmatrix} x_t \\ y_t \\ \tau_t \\ m_t \\ s_t \end{bmatrix} = \begin{bmatrix} 0 & 0 & I & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & \nu & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 \\ 0 & 0 & -g & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 \\ t \\ x_t \\ y_t \\ m_t \end{bmatrix}\end{split}\]

With

\[\begin{split}\tilde{x} := \begin{bmatrix} 1 \\ t \\ x_t \\ y_t \\ m_t \end{bmatrix} \quad \text{and} \quad \tilde{y} := \begin{bmatrix} x_t \\ y_t \\ \tau_t \\ m_t \\ s_t \end{bmatrix}\end{split}\]

we can write this as the linear state space system

\[\begin{split}\begin{aligned} \tilde{x}_{t+1} &= \tilde{A} \tilde{x}_t + \tilde{B} z_{t+1} \\ \tilde{y}_{t} &= \tilde{D} \tilde{x}_t \end{aligned}\end{split}\]

By picking out components of \(\tilde y_t\), we can track all variables of interest

Code

The class AMF_LSS_VAR mentioned above does all that we want to study our additive functional

In fact AMF_LSS_VAR does more, as we shall explain below

(A hint that it does more is the name of the class – here AMF stands for “additive and multiplicative functional” – the code will do things for multiplicative functionals too)

Let’s use this code (embedded above) to explore the example process described above

If you run the code that first simulated that example again and then the method call

plot_additive(amf, T)

you will generate (modulo randomness) the plot

../_images/output_12_1.png

When we plot multiple realizations of a component in the 2nd, 3rd, and 4th panels, we also plot population 95% probability coverage sets computed using the LSS class

We have chosen to simulate many paths, all starting from the same nonrandom initial conditions \(x_0, y_0\) (you can tell this from the shape of the 95% probability coverage shaded areas)

Notice tell-tale signs of these probability coverage shaded areas

  • the purple one for the martingale component \(m_t\) grows with \(\sqrt{t}\)
  • the green one for the stationary component \(s_t\) converges to a constant band

An associated multiplicative functional

Where \(\{y_t\}\) is our additive functional, let \(M_t = \exp(y_t)\)

As mentioned above, the process \(\{M_t\}\) is called a multiplicative functional

Corresponding to the additive decomposition described above we have the multiplicative decomposition of the \(M_t\)

\[\frac{M_t}{M_0} = \exp (t \nu) \exp \Bigl(\sum_{j=1}^t H \cdot Z_j \Bigr) \exp \biggl( D'(I-A)^{-1} x_0 - D'(I-A)^{-1} x_t \biggr)\]

or

\[\frac{M_t}{M_0} = \exp\left( \tilde \nu t \right) \Biggl( \frac{\widetilde M_t}{\widetilde M_0}\Biggr) \left( \frac{\tilde e (X_0)} {\tilde e(x_t)} \right)\]

where

\[\tilde \nu = \nu + \frac{H \cdot H}{2} , \quad \widetilde M_t = \exp \biggl( \sum_{j=1}^t \biggl(H \cdot z_j -\frac{ H \cdot H }{2} \biggr) \biggr), \quad \widetilde M_0 =1\]

and

\[\tilde e(x) = \exp[g(x)] = \exp \bigl[ D' (I - A)^{-1} x \bigr]\]

An instance of class AMF_LSS_VAR includes this associated multiplicative functional as an attribute

Let’s plot this multiplicative functional for our example

If you run the code that first simulated that example again and then the method call

plot_multiplicative(amf, T)
../_images/output_14_1.png

As before, when we plotted multiple realizations of a component in the 2nd, 3rd, and 4th panels, we also plotted population 95% confidence bands computed using the LSS class

Comparing this figure and the last also helps show how geometric growth differs from arithmetic growth

A peculiar large sample property

Hansen and Sargent [HS17] (ch. 6) note that the martingale component \(\widetilde M_t\) of the multplicative decomposition has a peculiar property

  • While \(E_0 \widetilde M_t = 1\) for all \(t \geq 0\), nevertheless \(\ldots\)
  • As \(t \rightarrow +\infty\), \(\widetilde M_t\) converges to zero almost surely

The following simulation of many paths of \(\widetilde M_t\) illustrates this property

srand(10021987)
plot_martingales(amf, 12000)

Here’s the resulting figure:

../_images/output_16_1.png