The Conquest of American Inflation¶

Overview¶

This lecture is loosely based upon Tom Sargent's The Conquest of American Inflation book and makes heavy of the linear-quadratic machinery developed here. Its purpose is to show an example of how an agent whose actions affect the economy might find complications from trying to learn from data generated by policy informed by past inference on the same system. The concepts of self-reference, adaptation, and omitted variables are centrally featured under an innocent surface.

A simple model¶

The government dislikes inflation $y_t$ and unemployment $U_t$ away from $0$. It seeks to set inflation to minimize

$$L = \sum_{t=0}^\infty \beta^t r_t$$

for

$$r_t = \frac{1}{2}\mathbb{E}\left[ U_t^2 + y_t^2 \right]$$

The only thing it needs is a theory of how inflation and unemployment are linked.

The true economy¶

In the true economy, unemployment is determined by

$$U_t = U^\star -\theta \left( y_t - x_t \right)$$

where $x_t$ is the mean forecast of inflation by the private sector. $U^\star$ is the "natural" rate of unemployment.

Moreover, we will also make the apparently inocent assumption that inflation $y_t$ is the sum of the government choice of inflation $\hat{y}_t$ plus an iid normally distributed shock $v_t$

Expectations¶

The plot thickens because the government holds a misspecified model and instead attempts to fit a distributed-lag Phillips curve of the form

$$U_t = \kappa y_t + \gamma' X_t + \epsilon^C_t$$

For most of this lecture we will set $X_t = [U_{t-1}, \dots, U_{t-M_u}, y_{t-1}, \dots, y_{t-M_y}, 1]'$. This means that the government forecasts unemployment with current inflation as well as lagged unemployment, lagged inflation, and a constant term.

Each period, the government updates its estimate of $\kappa$ and $\gamma$. An implementation of recursive least squares is to set

\begin{aligned} \beta_t &= \beta_{t-1} + g_t R^{-1}_{X,t} X_t (U_t - \beta_{t-1}'X_t) \\ R_{X,t} &= R_{X,t-1} + g_t ( X_tX_t' - R_{X,t-1})\\ \end{aligned}

where $\beta_t = [\kappa_t \; \gamma_t']'$. A key parameter is the "gain" parameter $g_t$, which governs the weight to be placed on newer observations. By setting $g_t = \frac{1}{t}$ one recovers the OLS scheme which weighs all observations the same. Setting the gain to a constant (or in general to a non square-summable sequence) causes the estimation to put more weight on recent observations, which is useful if the analyst believes the data-generating process not to be stationary.

The simulation we will run exhibits coefficients that wander as the government changes its mind about how unemployment is determined.

The private sector's expectations¶

For the private sector, we consider three options.

1. Rational expectations


The simplest case is to make the private sector fully aware of the government's updating scheme and decision process. This amounts to setting $x_t = \hat{y}_t$ at all times.

2. Simple adaptive expectations


This is the 1950's model. Here we make the private sector's new forecast a function of old forecasting errors. That is, $$x_t = x_{t-1} + (1-\lambda) (y_{t-1} - x_{t-1})$$

3. Recursive least squares


Here we endow the private sector with a similar forecasting scheme to the government's. We initialize $g^p_0$ and $R_{X,0}^p$ at (maybe) different points than the government's and may use a different lag structure.

Problems¶

Can the government ever discover the "true" slope parameter $\theta$? What does the government's model say about the relationship between inflation and unemployment in the short run and the long run? What are implications for the government own choice of inflation?

What are implications of the government's choice of inflation for the evolution of the system from which the government attempts to learn how unemployment is affected by inflation?

Is there a Phillips curve in the data?

Code¶

To manage the different expectation-formation schemes, the ConquestEconomy type records three different instances of a PLM type. Each PLM instance holds information about the expectations of a particular agent, including those of Nature, also known as the actual law of motion of the system.

In [48]:
using QuantEcon, LinearAlgebra, Random

using Plots
pyplot()

mutable struct PLM
Îº::Float64          # Weight on current state (unemployment or inflation)
Î³::Vector{Float64}  # Weights on lagged states (unemployment + inflation + constant)

Mu::Int64           # Lags on unemployment
My::Int64           # Lags on inflation

classic::Bool       # TRUE for predicting unemployment with the state, FALSE for predicting inflation

g::Float64          # Gain parameter (only for constant-gain RLS)
R::Matrix{Float64}  # Variance matrix (only for RLS)
end

mutable struct ConquestEconomy
Î´::Float64          # Discount factor

plm_g::PLM          # Government's perceived law of motion
plm_p::PLM          # Private sector's perceived law of motion
alm::PLM            # Actual (Nature's perceived) law of motion

private_expectations::String

Ïƒe::Float64         # Variance of cost-push shock
Ïƒc::Float64         # Variance of inflation control shock
end

lags(plm::PLM) = length(plm.Î³)

function sum_coeff(plm::PLM) # Finds the sum of coefficients on (current and) lagged inflation
if plm.classic
current_term = plm.Îº
else
current_term = 0
end
return sum(plm.Î³[plm.Mu+1:plm.Mu+plm.My]) + current_term
end

get_Ustar(alm::PLM) = alm.Î³[end]
get_Î¸(alm::PLM) = -alm.Îº
get_Ustar(ce::ConquestEconomy) = get_Ustar(ce.alm)
get_Î¸(ce::ConquestEconomy) = get_Î¸(ce.alm)

function make_ALM(plmg::PLM, plmp::PLM, Ustar::Float64, Î¸::Float64)
Mu = max(plmg.Mu, plmp.Mu)
My = max(plmg.My, plmp.My)
Î³ = [zeros(Mu+My); Ustar]
Îº = -Î¸
alm = PLM(Îº, Î³, Mu, My, true, 0.0, plmg.R, plmg.Î») # In the ALM, all the forecasting variables are irrelevant
return alm
end

make_ALM(ce::ConquestEconomy, Ustar=get_Ustar(ce), Î¸=get_Î¸(ce)) = make_ALM(ce.plm_g, ce.plm_p, Ustar, Î¸)
function update_ALM!(ce::ConquestEconomy)
ce.alm = make_ALM(ce)
nothing
end

function ConquestEconomy(;
Î´ = 0.98,
Î¸ = 1.0,
g = 0.05,
Î» = 0.5,  # Î» is the weight on past observations for simple adaptive scheme
Ïƒe = 0.5,
Ïƒc = 0.5,
Ustar = 5.0,
classic = true,
private_expectations = "rational",

Mu = 1,
My = 1,
Mu_p = 2,
My_p = 2
)

# Set arbitrary coefficients on past inflation and past unemployment
Î³U = zeros(Mu)
Î³y = zeros(My)
Î³ = [Î³U; Î³y; 1]
# For the induction hypothesis (weights on y's sum up to zero)
Îº = -sum(Î³y)
R = zeros(Mu+My+1, Mu+My+1)

plm_g = PLM(Îº, Î³, Mu, My, classic, g, R, Î»)

if private_expectations == "RLS"
priv_gain = 0.01
else
Mu_p, My_p, priv_gain = Mu, My, g
end
Rp = zeros(Mu_p+My_p+1, Mu_p+My_p+1)
classic = true # Always use the classical scheme for the private sector
plm_p = PLM(1.0, [zeros(Mu_p+My_p);1], Mu_p, My_p, classic, priv_gain, Rp, Î»)

# True process
alm = make_ALM(plm_g, plm_p, Ustar, Î¸)

return ConquestEconomy(Î´, plm_g, plm_p, alm, private_expectations, Ïƒe, Ïƒc)
end

Out[48]:
ConquestEconomy

Some convenience functions to modify expectations schemes on the fly¶

In [49]:
function set_exp!(ce::ConquestEconomy, s::String=""; Mu=1, My=1, Mu_p=2, My_p=2)
if s != "" && s != "rational" && s != "adaptive" && s != "RLS"
println("WARNING: only 'rational', 'adaptive', and 'RLS' expectations allowed.")
else
if s == ""
s = ce.private_expectations
end
ce2 = ConquestEconomy(private_expectations = s, Mu=Mu, My=My, Mu_p=Mu_p, My_p=My_p)
ce.plm_p = ce2.plm_p
ce.plm_g = ce2.plm_g
ce.private_expectations = s
update_ALM!(ce)
end
nothing
end

function set_exp!(ce::ConquestEconomy, n::Int64=0; Mu=1, My=1, Mu_p=2, My_p=2)
if n == 0
set_exp!(ce, "", Mu=Mu, My=My, Mu_p=Mu_p, My_p=My_p)
else
set_exp!(ce, sv[n], Mu=Mu, My=My, Mu_p=Mu_p, My_p=My_p)
end
nothing
end

Out[49]:
set_exp! (generic function with 3 methods)

Aside¶

If $M_u$ and $M_y$ are large, the government's problem, which contains $X_t$ in its state, can be difficult to manage. This is why we resort to the immense power of a linear-quadratic formulation.

Main building block: LQ problems¶

We want to make our problem have the form of choosing controls $u_t$ in state $x_t$ to minimize

$$V(x) = \mathbb{E}[ x'Rx + u'Qu + 2 u'Nx + \beta V(x') ]$$

subject to

$$x' = Ax + Bu + Cw$$

where $w$ are unit-variance iid normal shocks.

Setting up our problem¶

The first step is to make $r_t = X_t'RX_t + \hat{y}_t'Q\hat{y}_t + 2 \hat{y}_t'NX_t$. For this, notice that

$$r_t = -\frac{1}{2} \left[ U_t^2 + y_t^2 \right] = -\frac{1}{2} \left[ \left( \kappa y_t + \gamma' X_t + \epsilon^C_t \right)^2 + y_t^2 \right] = -\frac{1}{2} \left[ \kappa^2 y_t^2 + X_t'\gamma\gamma'X_t + 2 X_t'\gamma\kappa y_t + y_t^2 \right] + k$$

where $k$ is a sum of terms that either have zero mean (like those coming from products between endogenous variables and $\epsilon_t^C$) or are independent of policy (like the square term in $\epsilon_t^C$).

This means that we can set $R = \gamma\gamma'$, $Q = [1+\kappa^2]$, and $N = \gamma\kappa$.

Turning to the law of motion, we want to write $X_{t+1} = [U_t,\dots, U_{t-M_u+1}, y_t, \dots, y_{t-M_y+1},1]'$ as $X_{t+1} = AX_t + B \hat{y}_t + C w_{t+1}$. There are three parts: first, we will use the matrix $A$ to transfer lags of endogenous variables from $X_t$ to $X_{t+1}$. Second, we need to record $y_t$ (or equivalently, $\hat{y}_t$) and, finally, the value of $U_t$ that the government expects.

Since the government expects $\mathbb{E}^g[U_t] = \kappa y_t + \gamma'X_t$, we can set the first row of $A$ to coincide with $\gamma'$. We also set the first row of the (one-by-one) matrix $B$ to $\kappa$.

The matrix $A$ is then formed by

\begin{aligned} A = \left( \begin{array}{cccc} [ && \gamma & ] \\ A_1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & A_2 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) \end{aligned}

where $A_1$ is $M_u-1 \times M_u-1$ and $A_2$ is $M_y-1\times M_y-1$ and just shift the vectors by sending $U_{t-j}$ from the $j$th place to the $j+1$th place (and accordingly with $y$'s). The $1$ at the end takes care of the constant term (in the last element of $X$). The row of $0$'s (corresponding to $y_t$ in $X_{t+1}$) appears because we will fill the $y_t$ entry using the $B$ matrix.

Because $y_t = \hat{y}_t + v_t$, we can set $B = [\kappa,\dots, 0, 1, 0, \dots, 0]'$ with the $1$ in the $M_u+1$ place. Similarly for matrix $C$, only taking care with the variances

\begin{aligned} C = \left( \begin{array}{cc} \sqrt{\sigma_e} & \kappa \sqrt{\sigma_c} \\ 0 & 0 \\ \dots & \dots \\ 0 & \sqrt{\sigma_c} \\ 0 & 0 \\ \dots & \dots \\ 0& 0 \end{array}\right) \end{aligned}

In [50]:
function make_LQ(plm::PLM, Î´, Ïƒc, Ïƒe)
# Law of motion x_{t+1} = A x_t + B u_t + C w_{t+1}
# u = mean inflation, y = u + Ïƒc Ïµ

if plm.classic
Îº, Î³ = plm.Îº, plm.Î³
else
# Invert the Phillips curve in the Keynesian formulation
Îº, Î³ = 1/plm.Îº, -plm.Î³ / plm.Îº
end

k = lags(plm)

# Law of motion
A = zeros(k, k)
A[1,:] = Î³[:]
for jj in 1:plm.Mu-1
A[jj+1, jj] = 1
end
for jj in 1:plm.My-1
A[plm.Mu+jj+1, plm.Mu+jj] = 1
end
A[end,end] = 1

B = zeros(k,1)
B[1,1] = Îº
B[plm.Mu+1,1] = 1

# Shocks: unemployment is affected directly by the cost-push shock and indirectly by the inflation control shock (Îº-to-1), inflation affected directly by the control shock
C = zeros(k,2)
C[1,:] = [sqrt(Ïƒe) Îº*sqrt(Ïƒc)]
C[plm.Mu+1, 2] = sqrt(Ïƒc)

# Set up objective function
# r = x'Rx + u'Qu + 2 u'Nx

Q = [1+Îº^2 for ji in 1:1, jj in 1:1]
R = Î³ * Î³'
N = [Îº * Î³[jj] for jy in 1:1, jj in 1:k]

lq = QuantEcon.LQ(Q, R, A, B, C, N, bet = Î´)
return lq
end

function solve_Phelps!(lq::QuantEcon.LQ)
try
# Use QuantEcon's LQ solver
P, F, d = stationary_values!(lq)

# Bind states
lq.P, lq.F, lq.d = P, F, d

catch
println("Default solver exited. Increasing maxiter.")
# Increase number of iterations by hand
Q, R, A, B, N, C = lq.Q, lq.R, lq.A, lq.B, lq.N, lq.C

# solve Riccati equation, obtain P
A0, B0 = sqrt(lq.bet) * A, sqrt(lq.bet) * B
P = solve_discrete_riccati(A0, B0, R, Q, N, max_it=100)

# Compute F
s1 = Q .+ lq.bet * (B' * P * B)
s2 = lq.bet * (B' * P * A) .+ N
F = s1 \ s2

# Compute d
d = lq.bet * tr(P * C * C') / (1 - lq.bet)

# Bind states
lq.P, lq.F, lq.d = P, F, d
end

nothing
end

Out[50]:
solve_Phelps! (generic function with 1 method)

Handling different state spaces for government and private agents¶

A challenge is to keep track of who knows which state. This is where the functions expand_index and expand_matrix come in handy

In [51]:
function expand_index(plm::PLM, alm::PLM, jj::Int64)
new_j = jj
if jj > plm.Mu && jj <= plm.Mu+plm.My
new_j = alm.Mu - plm.Mu + jj
elseif jj == plm.Mu + plm.My + 1
new_j = alm.Mu + alm.My + 1
end
new_j
end

function expand_matrix(plm::PLM, alm::PLM, M::Matrix)
A = zeros(expand_index(plm, alm, size(M,1)), expand_index(plm, alm, size(M,2)))

for ji in 1:size(M,1)
for jj in 1:size(M,2)
A[expand_index(plm, alm, ji), expand_index(plm, alm, jj)] = M[ji,jj]
end
end
A
end

Out[51]:
expand_matrix (generic function with 1 method)

Updating expectations¶

The functions update_PC_OLS! and update_PC_RLS! run or update the regression in the government's (or the private sector's) expectation scheme. If the government is following the "classical" approach, then the Phillips curve is estimated as unemployment as a function of inflation and lagged variables. Otherwise we estimate the inverted curve as inflation as a function of unemployment and lagged variables.

In [52]:
function simul_PLM(ce::ConquestEconomy, plm::PLM)
lq = make_LQ(plm, ce.Î´, ce.Ïƒc, ce.Ïƒe)

xpath, upath, wpath = compute_sequence(lq, ones(lags(plm)))
end

function update_PC_OLS!(plm::PLM, alm::PLM, Ut, yt, Xt)

if plm.classic
predicted_var = Ut
predictor_var = yt
else
predicted_var = yt
predictor_var = Ut
end

# States has lags on unemployment, lags on inflation, and the constant
States = [Xt[1:plm.Mu]; Xt[alm.Mu+1:alm.Mu+plm.My]; Xt[end]]

# OLS formula U_t = Îº y_t + Î³'X_t + Ïµ_t
X = [predictor_var States']'

# Implement OLS inv(x'x)x'y with x \ y
new_Î³ = X' \ predicted_var

# Bind coefficients
plm.Îº = new_Î³[1]
plm.Î³ = new_Î³[2:end]

new_Î³
end

function update_PC_RLS!(plm::PLM, alm::PLM, Ut, yt, Xt)

if plm.classic
predicted_var = Ut
predictor_var = yt
else
predicted_var = yt
predictor_var = Ut
end

# States has lags on unemployment, lags on inflation, and the constant
States = [Xt[1:plm.Mu]; Xt[alm.Mu+1:alm.Mu+plm.My]; Xt[end]]

X = [predictor_var States']'

old_Î³ = [plm.Îº; plm.Î³[1:end]]

# Use RLS updating formulas
new_R = plm.R + plm.g * (X*X' - plm.R)
new_Î³ = old_Î³ + plm.g * (new_R \ (X*(predicted_var - old_Î³'*X)))

# Bind new coefficients
plm.Îº = new_Î³[1]
plm.Î³ = new_Î³[2:end]
plm.R = new_R

new_Î³
end

Out[52]:
update_PC_RLS! (generic function with 1 method)

Simulation¶

The main function in this code is simul_reest. After initializing the system, it simulates the economy.

Each period, the government chooses inflation $\hat{y}_t$ assuming its current model is the true model of the economy today and in the future. Realized inflation is $\hat{y}_t+\epsilon_t^C$. The private sector simultaneously sets expectations of inflation $x_t$ according to its own forecasting model of the government's choice. Finally, Nature chooses the adjusted natural rate $U^\star + \theta x_t$. Realized unemployment is $U^\star + \theta x_t - \theta y_t + \epsilon_t$.

After these choices have taken place, everyone updates their expectations using the new data they have just seen.

In [61]:
function simul_reest(ce::ConquestEconomy, T=50; OLS::Bool=false)
Random.seed!(1)

# Unpack and prepare
plm_g, plm_p, alm = ce.plm_g, ce.plm_p, ce.alm
expectations = ce.private_expectations
alm_lq = make_LQ(alm, ce.Î´, ce.Ïƒc, ce.Ïƒe)
solve_Phelps!(alm_lq)

# Initial state
xv, uv, wv = simul_PLM(ce, plm_p)
initial_T = 50
xv, uv, wv = xv[:,end-initial_T:end], uv[:,end-initial_T+1:end], wv[:,end-initial_T:end]
xnew = xv[:,end]

# Ensure the constant is a constant (mostly redundant)
xv[end,end] = 1

# Initial variance matrix
yvec = xv[alm.Mu+1, 2:end]
States_vec = vcat(xv[1:plm_g.Mu,1:end-1], xv[alm.Mu+1:alm.Mu+plm_g.My, 1:end-1], xv[end:end, 1:end-1])
X = [yvec States_vec']'
plm_g.Î³ = zeros(size(plm_g.Î³))
plm_g.Îº = 0.0
plm_g.R = X*X'

# Initialize private sector
States_vec = vcat(xv[1:plm_p.Mu,1:end-1], xv[alm.Mu+1:alm.Mu+plm_p.My, 1:end-1], xv[end:end, 1:end-1])
X = [yvec States_vec']'
plm_p.R = X*X'
x_priv = 0.0

# Initialize vectors to store results
svec = ones(size(xv,2)-1) * sum_coeff(plm_g)
Îºvec = ones(size(xv,2)-1) * plm_g.Îº
Î³vec = [plm_g.Î³[jj] for jy in 1:1, jj in 1:lags(plm_g)]
Ï€v = vcat(yvec, zeros(T))
Uv = vcat(xv[1, 2:end], zeros(T))

for jj in initial_T+1:initial_T+T
if OLS
plm_g.g = min(plm_g.g, 1/jj)
end

Xt = xnew

# Gov't chooses its action
lq = make_LQ(plm_g, ce.Î´, ce.Ïƒc, ce.Ïƒe)
solve_Phelps!(lq)

# Private sector sets expectations
Fp = zeros(1, lags(plm_p))
if expectations == "adaptive" || expectations == "RLS"
Fp[1,end] = x_priv # Add expected inflation in the constant term
elseif expectations == "rational"
Fp = expand_matrix(plm_g, plm_p, lq.F)
end

# Nature determines the natural rate given current private expectations
Î¸ = get_Î¸(alm)
Ustar = get_Ustar(alm) + (Î¸ * expand_matrix(plm_p, alm, -Fp) * Xt)[1]
alm_lq.A[1,end] = Ustar

# Gov't implements choice of action

unew = expand_matrix(plm_g, alm, -lq.F) * Xt

# Nature sets the state with the real model
shocks = randn(2)
wnew = alm_lq.C * (shocks .* [sqrt(ce.Ïƒe), sqrt(ce.Ïƒc)])
xnew = alm_lq.A*xnew + alm_lq.B*unew + wnew

# Save output and unemployment
Ut = xnew[1]
yt = xnew[alm.Mu+1]

# Private sector updates expectations for tomorrow
x_priv = x_priv + (1-plm_p.Î») * ((unew[1] + shocks[2]) - x_priv)
end
if expectations == "RLS"
update_PC_RLS!(plm_p, alm, Ut, yt, xnew)
lq_p = make_LQ(plm_g, ce.Î´, ce.Ïƒc, ce.Ïƒe)
solve_Phelps!(lq_p)

x_priv = (expand_matrix(plm_g, alm, -lq_p.F) * Xt)[1]
end

new_Î³ = update_PC_RLS!(plm_g, alm, Ut, yt, Xt)
Îºvec = [Îºvec; plm_g.Îº]
svec = [svec; sum_coeff(plm_g)]
Î³vec = [Î³vec; plm_g.Î³']

Uv[jj] = Ut
Ï€v[jj] = yt
end

print("Finished simulation with \$expectations expectations")
labels = ["Unemployment" "Inflation" "PC slope coefficient" "Sum of lagged coefficients"]
pl = plot([Uv Ï€v Îºvec svec], layout=4, title=labels, size = (900,450), color=[2 3 5 8], palette=:heat, bg="#fafafa", ticks=:auto, leg=false)
return pl
end

Out[61]:
simul_reest (generic function with 2 methods)
In [62]:
ce = ConquestEconomy(); set_exp!(ce, 1)
simul_reest(ce, 1500)

Finished simulation with rational expectations
Out[62]:
In [63]:
ce = ConquestEconomy(Mu=5,My=7) # With more lags in the government's specification, similar dynamics emerge but the pattern becomes more complicated
simul_reest(ce, 2500)

Finished simulation with rational expectations
Out[63]:
In [64]:
ce = ConquestEconomy(); set_exp!(ce, 2)
simul_reest(ce, 2500)

Finished simulation with adaptive expectations
Out[64]:
In [65]:
ce = ConquestEconomy(); set_exp!(ce, 3)
simul_reest(ce, 500)

Finished simulation with RLS expectations
Out[65]:
In [ ]:


In [ ]: