23. Dynamics in One Dimension#

23.1. Overview#

In economics many variables depend on their past values

For example, it seems reasonable to believe that inflation last year with affects inflation this year.

(Perhaps high inflation last year will lead people to demand higher wages to compensate, which will feed into higher prices this year.)

Letting \(\pi_t\) be inflation this year and \(\pi_{t-1}\) be inflation last year, we can write this relationship in a general form as

\[ \pi_t = f(\pi_{t-1}) \]

where \(f\) is some function describing the relationship between the variables.

This equation is an example of one-dimensional discrete time dynamic system.

In this lecture we cover the foundations of one-dimensional discrete time dynamics.

(While most quantitative models have two or more state variables, the one-dimensional setting is a good place to learn foundations and understand key concepts.)

Let’s start with some standard imports:

import matplotlib.pyplot as plt
import numpy as np

23.2. Some definitions#

This section sets out the objects of interest and the kinds of properties we study.

23.2.1. Composition of functions#

For this lecture you should know the following.

If

  • \(g\) is a function from \(A\) to \(B\) and

  • \(f\) is a function from \(B\) to \(C\),

then the composition \(f \circ g\) of \(f\) and \(g\) is defined by

\[ (f \circ g)(x) = f(g(x)) \]

For example, if

  • \(A=B=C=\mathbb R\), the set of real numbers,

  • \(g(x)=x^2\) and \(f(x)=\sqrt{x}\), then \((f \circ g)(x) = \sqrt{x^2} = |x|\).

If \(f\) is a function from \(A\) to itself, then \(f^2\) is the composition of \(f\) with itself.

For example, if \(A = (0, \infty)\), the set of positive numbers, and \(f(x) = \sqrt{x}\), then

\[ f^2(x) = \sqrt{\sqrt{x}} = x^{1/4} \]

Similarly, if \(n\) is a positive integer, then \(f^n\) is \(n\) compositions of \(f\) with itself.

In the example above, \(f^n(x) = x^{1/(2^n)}\).

23.2.2. Dynamic systems#

A (discrete time) dynamic system is a set \(S\) and a function \(g\) that sends set \(S\) back into to itself.

Examples of dynamic systems include

  • \(S = (0, 1)\) and \(g(x) = \sqrt{x}\)

  • \(S = (0, 1)\) and \(g(x) = x^2\)

  • \(S = \mathbb Z\) (the integers) and \(g(x) = 2 x\)

On the other hand, if \(S = (-1, 1)\) and \(g(x) = x+1\), then \(S\) and \(g\) do not form a dynamic system, since \(g(1) = 2\).

  • \(g\) does not always send points in \(S\) back into \(S\).

We care about dynamic systems because we can use them to study dynamics!

Given a dynamic system consisting of set \(S\) and function \(g\), we can create a sequence \(\{x_t\}\) of points in \(S\) by setting

(23.1)#\[ x_{t+1} = g(x_t) \quad \text{ with } x_0 \text{ given}.\]

This means that we choose some number \(x_0\) in \(S\) and then take

(23.2)#\[ x_0, \quad x_1 = g(x_0), \quad x_2 = g(x_1) = g(g(x_0)), \quad \text{etc.}\]

This sequence \(\{x_t\}\) is called the trajectory of \(x_0\) under \(g\).

In this setting, \(S\) is called the state space and \(x_t\) is called the state variable.

Recalling that \(g^n\) is the \(n\) compositions of \(g\) with itself, we can write the trajectory more simply as

\[ x_t = g^t(x_0) \quad \text{ for } t = 0, 1, 2, \ldots \]

In all of what follows, we are going to assume that \(S\) is a subset of \(\mathbb R\), the real numbers.

Equation (23.1) is sometimes called a first order difference equation

  • first order means dependence on only one lag (i.e., earlier states such as \(x_{t-1}\) do not enter into (23.1)).

23.2.3. Example: a linear model#

One simple example of a dynamic system is when \(S=\mathbb R\) and \(g(x)=ax + b\), where \(a, b\) are constants (sometimes called ``parameters’’).

This leads to the linear difference equation

\[ x_{t+1} = a x_t + b \quad \text{ with } x_0 \text{ given}. \]

The trajectory of \(x_0\) is

(23.3)#\[x_0, \quad a x_0 + b, \quad a^2 x_0 + a b + b, \quad \text{etc.}\]

Continuing in this way, and using our knowledge of geometric series, we find that, for any \(t = 0, 1, 2, \ldots\),

(23.4)#\[ x_t = a^t x_0 + b \frac{1 - a^t}{1 - a}\]

We have an exact expression for \(x_t\) for all non-negative integer \(t\) and hence a full understanding of the dynamics.

Notice in particular that \(|a| < 1\), then, by (23.4), we have

(23.5)#\[x_t \to \frac{b}{1 - a} \text{ as } t \to \infty\]

regardless of \(x_0\).

This is an example of what is called global stability, a topic we return to below.

23.2.4. Example: a nonlinear model#

In the linear example above, we obtained an exact analytical expression for \(x_t\) in terms of arbitrary non-negative integer \(t\) and \(x_0\).

This made analysis of dynamics very easy.

When models are nonlinear, however, the situation can be quite different.

For example, in a later lecture The Solow-Swan Growth Model, we will study the Solow-Swan growth model, which has dynamics

(23.6)#\[k_{t+1} = s A k_t^{\alpha} + (1 - \delta) k_t\]

Here \(k=K/L\) is the per capita capital stock, \(s\) is the saving rate, \(A\) is the total factor productivity, \(\alpha\) is the capital share, and \(\delta\) is the depreciation rate.

All these parameter are positive and \(0 < \alpha, \delta < 1\).

If you try to iterate like we did in (23.3), you will find that the algebra gets messy quickly.

Analyzing the dynamics of this model requires a different method (see below).

23.3. Stability#

Consider a dynamic system consisting of set \(S \subset \mathbb R\) and \(g\) mapping \(S\) to \(S\).

23.3.1. Steady states#

A steady state of this system is a point \(x^*\) in \(S\) such that \(x^* = g(x^*)\).

In other words, \(x^*\) is a fixed point of the function \(g\) in \(S\).

For example, for the linear model \(x_{t+1} = a x_t + b\), you can use the definition to check that

  • \(x^* := b/(1-a)\) is a steady state whenever \(a \not= 1\),

  • if \(a = 1\) and \(b=0\), then every \(x \in \mathbb R\) is a steady state,

  • if \(a = 1\) and \(b \not= 0\), then the linear model has no steady state in \(\mathbb R\).

23.3.2. Global stability#

A steady state \(x^*\) of the dynamic system is called globally stable if, for all \(x_0 \in S\),

\[ x_t = g^t(x_0) \to x^* \text{ as } t \to \infty \]

For example, in the linear model \(x_{t+1} = a x_t + b\) with \(a \not= 1\), the steady state \(x^*\)

  • is globally stable if \(|a| < 1\) and

  • fails to be globally stable otherwise.

This follows directly from (23.4).

23.3.3. Local stability#

A steady state \(x^*\) of the dynamic system is called locally stable if there exists an \(\epsilon > 0\) such that

\[ | x_0 - x^* | < \epsilon \; \implies \; x_t = g^t(x_0) \to x^* \text{ as } t \to \infty \]

Obviously every globally stable steady state is also locally stable.

Here is an example where the converse is not true.

Example 23.1

Consider the self-map \(g\) on \(\mathbb{R}\) defined by \(g(x)=x^2\). The fixed point \(1\) is not stable.

For example, \(g^t (x)\to\infty\) for any \(x>1\).

However, \(0\) is locally stable, because \(-1<x<1\) implies that \(g^t (x)\to 0\) as \(t\to\infty\).

Since we have more than one fixed point, \(0\) is not globally stable.

23.4. Graphical analysis#

As we saw above, analyzing the dynamics for nonlinear models is nontrivial.

There is no single way to tackle all nonlinear models.

However, there is one technique for one-dimensional models that provides a great deal of intuition.

This is a graphical approach based on 45-degree diagrams.

Let’s look at an example: the Solow-Swan model with dynamics given in (23.6).

We begin with some plotting code that you can ignore at first reading.

The function of the code is to produce 45-degree diagrams and time series plots.

Hide code cell source
def subplots():
    "Custom subplots with axes throught the origin"
    fig, ax = plt.subplots()

    # Set the axes through the origin
    for spine in ['left', 'bottom']:
        ax.spines[spine].set_position('zero')
        ax.spines[spine].set_color('green')
    for spine in ['right', 'top']:
        ax.spines[spine].set_color('none')

    return fig, ax


def plot45(g, xmin, xmax, x0, num_arrows=6, var='x'):

    xgrid = np.linspace(xmin, xmax, 200)

    fig, ax = subplots()
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(xmin, xmax)
    ax.set_xlabel(r'${}_t$'.format(var), fontsize=14)
    ax.set_ylabel(r'${}_{}$'.format(var, str('{t+1}')), fontsize=14)

    hw = (xmax - xmin) * 0.01
    hl = 2 * hw
    arrow_args = dict(fc="k", ec="k", head_width=hw,
            length_includes_head=True, lw=1,
            alpha=0.6, head_length=hl)

    ax.plot(xgrid, g(xgrid), 'b-', lw=2, alpha=0.6, label='g')
    ax.plot(xgrid, xgrid, 'k-', lw=1, alpha=0.7, label='45')

    x = x0
    xticks = [xmin]
    xtick_labels = [xmin]

    for i in range(num_arrows):
        if i == 0:
            ax.arrow(x, 0.0, 0.0, g(x), **arrow_args) # x, y, dx, dy
        else:
            ax.arrow(x, x, 0.0, g(x) - x, **arrow_args)
            ax.plot((x, x), (0, x), 'k', ls='dotted')

        ax.arrow(x, g(x), g(x) - x, 0, **arrow_args)
        xticks.append(x)
        xtick_labels.append(r'${}_{}$'.format(var, str(i)))

        x = g(x)
        xticks.append(x)
        xtick_labels.append(r'${}_{}$'.format(var, str(i+1)))
        ax.plot((x, x), (0, x), 'k', ls='dotted')

    xticks.append(xmax)
    xtick_labels.append(xmax)
    ax.set_xticks(xticks)
    ax.set_yticks(xticks)
    ax.set_xticklabels(xtick_labels)
    ax.set_yticklabels(xtick_labels)

    bbox = (0., 1.04, 1., .104)
    legend_args = {'bbox_to_anchor': bbox, 'loc': 'upper right'}

    ax.legend(ncol=2, frameon=False, **legend_args, fontsize=14)
    plt.show()

def ts_plot(g, xmin, xmax, x0, ts_length=6, var='x'):
    fig, ax = subplots()
    ax.set_ylim(xmin, xmax)
    ax.set_xlabel(r'$t$', fontsize=14)
    ax.set_ylabel(r'${}_t$'.format(var), fontsize=14)
    x = np.empty(ts_length)
    x[0] = x0
    for t in range(ts_length-1):
        x[t+1] = g(x[t])
    ax.plot(range(ts_length),
            x,
            'bo-',
            alpha=0.6,
            lw=2,
            label=r'${}_t$'.format(var))
    ax.legend(loc='best', fontsize=14)
    ax.set_xticks(range(ts_length))
    plt.show()

Let’s create a 45-degree diagram for the Solow-Swan model with a fixed set of parameters. Here’s the update function corresponding to the model.

def g(k, A = 2, s = 0.3, alpha = 0.3, delta = 0.4):
    return A * s * k**alpha + (1 - delta) * k

Here is the 45-degree plot.

xmin, xmax = 0, 4  # Suitable plotting region.

plot45(g, xmin, xmax, 0, num_arrows=0)
_images/71f39564576777c73182cf1af7224740805162768dfed838c306b16013dee83d.png

The plot shows the function \(g\) and the 45-degree line.

Think of \(k_t\) as a value on the horizontal axis.

To calculate \(k_{t+1}\), we can use the graph of \(g\) to see its value on the vertical axis.

Clearly,

  • If \(g\) lies above the 45-degree line at this point, then we have \(k_{t+1} > k_t\).

  • If \(g\) lies below the 45-degree line at this point, then we have \(k_{t+1} < k_t\).

  • If \(g\) hits the 45-degree line at this point, then we have \(k_{t+1} = k_t\), so \(k_t\) is a steady state.

For the Solow-Swan model, there are two steady states when \(S = \mathbb R_+ = [0, \infty)\).

  • the origin \(k=0\)

  • the unique positive number such that \(k = s z k^{\alpha} + (1 - \delta) k\).

By using some algebra, we can show that in the second case, the steady state is

\[ k^* = \left( \frac{sz}{\delta} \right)^{1/(1-\alpha)} \]

23.4.1. Trajectories#

By the preceding discussion, in regions where \(g\) lies above the 45-degree line, we know that the trajectory is increasing.

The next figure traces out a trajectory in such a region so we can see this more clearly.

The initial condition is \(k_0 = 0.25\).

k0 = 0.25

plot45(g, xmin, xmax, k0, num_arrows=5, var='k')
_images/6c826502d0f49a7339770b72603eaafa51d81d462fe7e127291729879f0930b7.png

We can plot the time series of per capita capital corresponding to the figure above as follows:

ts_plot(g, xmin, xmax, k0, var='k')
_images/812058b0fd1e411dd60244ff1439e449c5381c02983348c39fc206624d36399f.png

Here’s a somewhat longer view:

ts_plot(g, xmin, xmax, k0, ts_length=20, var='k')
_images/9c237f2e74c3c66260bf37cc0dd131b30a36407326bee18ebe51df81f40b0ec8.png

When per capita capital stock is higher than the unique positive steady state, we see that it declines:

k0 = 2.95

plot45(g, xmin, xmax, k0, num_arrows=5, var='k')
_images/05b5f6510c490ff5b9b8976a29ed6a1c9e2058aafc02e8a0f9c961f6abb5e6da.png

Here is the time series:

ts_plot(g, xmin, xmax, k0, var='k')
_images/e0cf3bc07b3a1c055fc5652bb1e0ecfa186adf677226197fe9839e0081a514e7.png

23.4.2. Complex dynamics#

The Solow-Swan model is nonlinear but still generates very regular dynamics.

One model that generates irregular dynamics is the quadratic map

\[ g(x) = 4 x (1 - x), \qquad x \in [0, 1] \]

Let’s have a look at the 45-degree diagram.

xmin, xmax = 0, 1
g = lambda x: 4 * x * (1 - x)

x0 = 0.3
plot45(g, xmin, xmax, x0, num_arrows=0)
_images/f74ea5b38323c9ec5ed7d8a97242d586502009ad3640c9bd99844d30911939f2.png

Now let’s look at a typical trajectory.

plot45(g, xmin, xmax, x0, num_arrows=6)
_images/c9416655f6d6c0cd5591e64b63f42ed40232f83071f23c41937acb2cbbf1f820.png

Notice how irregular it is.

Here is the corresponding time series plot.

ts_plot(g, xmin, xmax, x0, ts_length=6)
_images/f824e31421f7d43e3cef727368f5bea698d28dbd0df8f229c56bc66958ba3818.png

The irregularity is even clearer over a longer time horizon:

ts_plot(g, xmin, xmax, x0, ts_length=20)
_images/52530bed49cd4dad408d99ffe92c23cd3ec8b44fe74fb041c31b1bd5f54ca1d8.png

23.5. Exercises#

Exercise 23.1

Consider again the linear model \(x_{t+1} = a x_t + b\) with \(a \not=1\).

The unique steady state is \(b / (1 - a)\).

The steady state is globally stable if \(|a| < 1\).

Try to illustrate this graphically by looking at a range of initial conditions.

What differences do you notice in the cases \(a \in (-1, 0)\) and \(a \in (0, 1)\)?

Use \(a=0.5\) and then \(a=-0.5\) and study the trajectories.

Set \(b=1\) throughout.