Skip to article frontmatterSkip to article content
Contents
and

30. Inflation Rate Laffer Curves

30.1Overview

We study stationary and dynamic Laffer curves in the inflation tax rate in a non-linear version of the model studied in Money Financed Government Deficits and Price Levels.

We use the log-linear version of the demand function for money that Cagan (1956) used in his classic paper in place of the linear demand function used in Money Financed Government Deficits and Price Levels.

That change requires that we modify parts of our analysis.

In particular, our dynamic system is no longer linear in state variables.

Nevertheless, the economic logic underlying an analysis based on what we called ‘‘method 2’’ remains unchanged.

We shall discover qualitatively similar outcomes to those that we studied in Money Financed Government Deficits and Price Levels.

That lecture presented a linear version of the model in this lecture.

As in that lecture, we discussed these topics:

  • an inflation tax that a government gathers by printing paper or electronic money
  • a dynamic Laffer curve in the inflation tax rate that has two stationary equilibria
  • perverse dynamics under rational expectations in which the system converges to the higher stationary inflation tax rate
  • a peculiar comparative stationary-state analysis connected with that stationary inflation rate that asserts that inflation can be reduced by running higher government deficits

These outcomes will set the stage for the analysis of Laffer Curves with Adaptive Expectations that studies a version of the present model that uses a version of “adaptive expectations” instead of rational expectations.

That lecture will show that

  • replacing rational expectations with adaptive expectations leaves the two stationary inflation rates unchanged, but that \ldots
  • it reverses the perverse dynamics by making the lower stationary inflation rate the one to which the system typically converges
  • a more plausible comparative dynamic outcome emerges in which now inflation can be reduced by running lower government deficits

30.2The Model

Let

  • mtm_t be the log of the money supply at the beginning of time tt
  • ptp_t be the log of the price level at time tt

The demand function for money is

mt+1pt=α(pt+1pt)m_{t+1} - p_t = -\alpha (p_{t+1} - p_t)

where α0\alpha \geq 0.

The law of motion of the money supply is

exp(mt+1)exp(mt)=gexp(pt)\exp(m_{t+1}) - \exp(m_t) = g \exp(p_t)

where gg is the part of government expenditures financed by printing money.

30.3Limiting Values of Inflation Rate

We can compute the two prospective limiting values for π\overline \pi by studying the steady-state Laffer curve.

Thus, in a steady state

mt+1mt=pt+1pt=xt,m_{t+1} - m_t = p_{t+1} - p_t = x \quad \forall t ,

where x>0x > 0 is a common rate of growth of logarithms of the money supply and price level.

A few lines of algebra yields the following equation that xx satisfies

exp(αx)exp((1+α)x)=g\exp(-\alpha x) - \exp(-(1 + \alpha) x) = g

where we require that

gmaxx0{exp(αx)exp((1+α)x)},g \leq \max_{x \geq 0} \{\exp(-\alpha x) - \exp(-(1 + \alpha) x) \},

so that it is feasible to finance gg by printing money.

The left side of (4) is steady state revenue raised by printing money.

The right side of (4) is the quantity of time tt goods that the government raises by printing money.

Soon we’ll plot the left and right sides of equation (4).

But first we’ll write code that computes a steady-state π\overline \pi.

Let’s start by importing some libraries

from collections import namedtuple
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
from scipy.optimize import fsolve

Let’s create a namedtuple to store the parameters of the model

CaganLaffer = namedtuple('CaganLaffer', 
                        ["m0",  # log of the money supply at t=0
                         "α",   # sensitivity of money demand
                         "λ",
                         "g" ])

# Create a Cagan Laffer model
def create_model(α=0.5, m0=np.log(100), g=0.35):
    return CaganLaffer(α=α, m0=m0, λ=α/(1+α), g=g)

model = create_model()

Now we write code that computes steady-state π\overline \pis.

# Define formula for π_bar
def solve_π(x, α, g):
    return np.exp(-α * x) - np.exp(-(1 + α) * x) - g

def solve_π_bar(model, x0):
    π_bar = fsolve(solve_π, x0=x0, xtol=1e-10, args=(model.α, model.g))[0]
    return π_bar

# Solve for the two steady state of π
π_l = solve_π_bar(model, x0=0.6)
π_u = solve_π_bar(model, x0=3.0)
print(f'The two steady state of π are: {π_l, π_u}')
The two steady state of π are: (np.float64(0.6737147075333034), np.float64(1.6930797322614815))

We find two steady state π\overline \pi values.

30.4Steady State Laffer curve

The following figure plots the steady state Laffer curve together with the two stationary inflation rates.

def compute_seign(x, α):
    return np.exp(-α * x) - np.exp(-(1 + α) * x) 

def plot_laffer(model, πs):
    α, g = model.α, model.g
    
    # Generate π values
    x_values = np.linspace(0, 5, 1000)

    # Compute corresponding seigniorage values for the function
    y_values = compute_seign(x_values, α)

    # Plot the function
    plt.plot(x_values, y_values, 
            label=f'Laffer curve')
    for π, label in zip(πs, [r'$\pi_l$', r'$\pi_u$']):
        plt.text(π, plt.gca().get_ylim()[0]*2, 
                 label, horizontalalignment='center',
                 color='brown', size=10)
        plt.axvline(π, color='brown', linestyle='--')
    plt.axhline(g, color='red', linewidth=0.5, 
                linestyle='--', label='g')
    plt.xlabel(r'$\pi$')
    plt.ylabel('seigniorage')
    plt.legend()
    plt.show()

# Steady state Laffer curve
plot_laffer(model, (π_l, π_u))
<Figure size 640x480 with 1 Axes>

Figure 1:Seigniorage as function of steady state inflation. The dashed brown lines indicate πl\pi_l and πu\pi_u.

30.5Initial Price Levels

Now that we have our hands on the two possible steady states, we can compute two functions p(m0)\underline p(m_0) and p(m0)\overline p(m_0), which as initial conditions for ptp_t at time tt, imply that πt=π\pi_t = \overline \pi for all t0t \geq 0.

The function p(m0)\underline p(m_0) will be associated with πl\pi_l the lower steady-state inflation rate.

The function p(m0)\overline p(m_0) will be associated with πu\pi_u the lower steady-state inflation rate.

def solve_p0(p0, m0, α, g, π):
    return np.log(np.exp(m0) + g * np.exp(p0)) + α * π - p0

def solve_p0_bar(model, x0, π_bar):
    p0_bar = fsolve(solve_p0, x0=x0, xtol=1e-20, args=(model.m0, 
                                                       model.α, 
                                                       model.g, 
                                                       π_bar))[0]
    return p0_bar

# Compute two initial price levels associated with π_l and π_u
p0_l = solve_p0_bar(model, 
                    x0=np.log(220), 
                    π_bar=π_l)
p0_u = solve_p0_bar(model, 
                    x0=np.log(220), 
                    π_bar=π_u)
print(f'Associated initial  p_0s  are: {p0_l, p0_u}')
Associated initial  p_0s  are: (np.float64(5.615742247288046), np.float64(7.14478978438031))

30.5.1Verification

To start, let’s write some code to verify that if the initial log price level p0p_0 takes one of the two values we just calculated, the inflation rate πt\pi_t will be constant for all t0t \geq 0.

The following code verifies this.

# Implement pseudo-code above
def simulate_seq(p0, model, num_steps):
    λ, g = model.λ, model.g
    π_seq, μ_seq, m_seq, p_seq = [], [], [model.m0], [p0]

    for t in range(num_steps):
        
        m_seq.append(np.log(np.exp(m_seq[t]) + g * np.exp(p_seq[t])))
        p_seq.append(1/λ * p_seq[t] + (1 - 1/λ) * m_seq[t+1])

        μ_seq.append(m_seq[t+1]-m_seq[t])
        π_seq.append(p_seq[t+1]-p_seq[t])

    return π_seq, μ_seq, m_seq, p_seq
π_seq, μ_seq, m_seq, p_seq = simulate_seq(p0_l, model, 150)

# Check π and μ at steady state
print('π_bar == μ_bar:', π_seq[-1] == μ_seq[-1])

# Check steady state m_{t+1} - m_t and p_{t+1} - p_t 
print('m_{t+1} - m_t:', m_seq[-1] - m_seq[-2])
print('p_{t+1} - p_t:', p_seq[-1] - p_seq[-2])

# Check if exp(-αx) - exp(-(1 + α)x) = g
eq_g = lambda x: np.exp(-model.α * x) - np.exp(-(1 + model.α) * x)

print('eq_g == g:', np.isclose(eq_g(m_seq[-1] - m_seq[-2]), model.g))
π_bar == μ_bar: False
m_{t+1} - m_t: 1.6930797322614524
p_{t+1} - p_t: 1.693079732261424
eq_g == g: True

30.6Computing an Equilibrium Sequence

We’ll deploy a method similar to Method 2 used in Money Financed Government Deficits and Price Levels.

We’ll take the time tt state vector to be the pair (mt,pt)(m_t, p_t).

We’ll treat mtm_t as a natural state variable and ptp_t as a jump variable.

Let

λα1+α\lambda \equiv \frac{\alpha}{1+ \alpha}

Let’s rewrite equation (1) as

pt=(1λ)mt+1+λpt+1p_t = (1-\lambda) m_{t+1} + \lambda p_{t+1}

We’ll summarize our algorithm with the following pseudo-code.

Pseudo-code

The heart of the pseudo-code iterates on the following mapping from state vector (mt,pt)(m_t, p_t) at time tt to state vector (mt+1,pt+1)(m_{t+1}, p_{t+1}) at time t+1t+1.

  • starting from a given pair (mt,pt)(m_t, p_t) at time t0t \geq 0

    • solve (2) for mt+1m_{t+1}

    • solve (7) for pt+1=λ1pt+(1λ1)mt+1p_{t+1} = \lambda^{-1} p_t + (1 - \lambda^{-1}) m_{t+1}

    • compute the inflation rate πt=pt+1pt\pi_t = p_{t+1} - p_t and growth of money supply μt=mt+1mt\mu_t = m_{t+1} - m_t

Next, compute the two functions p(m0)\underline p(m_0) and p(m0)\overline p(m_0) described above

Now initiate the algorithm as follows.

  • set m0>0m_0 >0
  • set a value of p0[p(m0),p(m0)]p_0 \in [\underline p(m_0), \overline p(m_0)] and form the pair (m0,p0)(m_0, p_0) at time t=0t =0

Starting from (m0,p0)(m_0, p_0) iterate on tt to convergence of πtπ\pi_t \rightarrow \overline \pi and μtμ\mu_t \rightarrow \overline \mu

It will turn out that

  • if they exist, limiting values π\overline \pi and μ\overline \mu will be equal

  • if limiting values exist, there are two possible limiting values, one high, one low

  • for almost all initial log price levels p0p_0, the limiting π=μ\overline \pi = \overline \mu is the higher value

  • for each of the two possible limiting values π\overline \pi ,there is a unique initial log price level p0p_0 that implies that πt=μt=μ\pi_t = \mu_t = \overline \mu for all t0t \geq 0

    • this unique initial log price level solves log(exp(m0)+gexp(p0))p0=απ\log(\exp(m_0) + g \exp(p_0)) - p_0 = - \alpha \overline \pi

    • the preceding equation for p0p_0 comes from m1p0=απm_1 - p_0 = - \alpha \overline \pi

30.7Slippery Side of Laffer Curve Dynamics

We are now equipped to compute time series starting from different p0p_0 settings, like those in Money Financed Government Deficits and Price Levels.

Notebook Cell
def draw_iterations(p0s, model, line_params, p0_bars, num_steps):

    fig, axes = plt.subplots(4, 1, figsize=(8, 10), sharex=True)
    
    # Pre-compute time steps
    time_steps = np.arange(num_steps) 
    
    # Plot the first two y-axes in log scale
    for ax in axes[:2]:
        ax.set_yscale('log')

    # Iterate over p_0s and calculate a series of y_t
    for p0 in p0s:
        π_seq, μ_seq, m_seq, p_seq = simulate_seq(p0, model, num_steps)

        # Plot m_t
        axes[0].plot(time_steps, m_seq[1:], **line_params)

        # Plot p_t
        axes[1].plot(time_steps, p_seq[1:], **line_params)
        
        # Plot π_t
        axes[2].plot(time_steps, π_seq, **line_params)
        
        # Plot μ_t
        axes[3].plot(time_steps, μ_seq, **line_params)
    
    # Draw labels
    axes[0].set_ylabel('$m_t$')
    axes[1].set_ylabel('$p_t$')
    axes[2].set_ylabel(r'$\pi_t$')
    axes[3].set_ylabel(r'$\mu_t$')
    axes[3].set_xlabel('timestep')
    
    for p_0, label in [(p0_bars[0], '$p_0=p_l$'), (p0_bars[1], '$p_0=p_u$')]:
        y = simulate_seq(p_0, model, 1)[0]
        for ax in axes[2:]:
            ax.axhline(y=y[0], color='grey', linestyle='--', lw=1.5, alpha=0.6)
            ax.text(num_steps * 1.02, y[0], label, verticalalignment='center', 
                         color='grey', size=10)
    
    # Enforce integar axis label
    axes[3].xaxis.set_major_locator(MaxNLocator(integer=True))

    plt.tight_layout()
    plt.show()
# Generate a sequence from p0_l to p0_u
p0s = np.arange(p0_l, p0_u, 0.1) 

line_params = {'lw': 1.5, 
              'marker': 'o',
              'markersize': 3}

p0_bars = (p0_l, p0_u)
              
draw_iterations(p0s, model, line_params, p0_bars, num_steps=20)
<Figure size 800x1000 with 4 Axes>

Figure 2:Starting from different initial values of p0p_0, paths of mtm_t (top panel, log scale for mm), ptp_t (second panel, log scale for pp), πt\pi_t (third panel), and μt\mu_t (bottom panel)

Staring at the paths of price levels in Fig. 2 reveals that almost all paths converge to the higher inflation tax rate displayed in the stationary state Laffer curve. displayed in figure Fig. 1.

Thus, we have reconfirmed what we have called the “perverse” dynamics under rational expectations in which the system converges to the higher of two possible stationary inflation tax rates.

Those dynamics are “perverse” not only in the sense that they imply that the monetary and fiscal authorities that have chosen to finance government expenditures eventually impose a higher inflation tax than required to finance government expenditures, but because of the following “counterintuitive” situation that we can deduce by staring at the stationary state Laffer curve displayed in figure Fig. 1:

  • the figure indicates that inflation can be reduced by running higher government deficits, i.e., by raising more resources through printing money.

We discovered that

  • all but one of the equilibrium paths converge to limits in which the higher of two possible stationary inflation tax prevails
  • there is a unique equilibrium path associated with “plausible” statements about how reductions in government deficits affect a stationary inflation rate

As in Money Financed Government Deficits and Price Levels, on grounds of plausibility, we again recommend selecting the unique equilibrium that converges to the lower stationary inflation tax rate.

As we shall see, we accepting this recommendation is a key ingredient of outcomes of the “unpleasant arithmetic” that we describe in Some Unpleasant Monetarist Arithmetic.

In Laffer Curves with Adaptive Expectations, we shall explore how Bruno & Fischer (1990) and others justified our equilibrium selection in other ways.

References
  1. Cagan, P. (1956). The Monetary Dynamics of Hyperinflation. In M. Friedman (Ed.), Studies in the Quantity Theory of Money (pp. 25–117). University of Chicago Press.
  2. Bruno, M., & Fischer, S. (1990). Seigniorage, operating rules, and the high inflation trap. The Quarterly Journal of Economics, 105(2), 353–374.
CC-BY-SA-4.0

Creative Commons License – This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International.