From 52fc94d12c3abbb8739436860ceff408bc11f2e2 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Wed, 24 Jan 2024 11:28:29 +1100 Subject: [PATCH 1/9] remove migrated lectures --- lectures/_toc.yml | 2 - lectures/ar1_processes.md | 604 -------------------------------------- lectures/scalar_dynam.md | 518 -------------------------------- 3 files changed, 1124 deletions(-) delete mode 100644 lectures/ar1_processes.md delete mode 100644 lectures/scalar_dynam.md diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 860aed18a..6067e898c 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -38,8 +38,6 @@ parts: - caption: Introduction to Dynamics numbered: true chapters: - - file: scalar_dynam - - file: ar1_processes - file: finite_markov - file: inventory_dynamics - file: linear_models diff --git a/lectures/ar1_processes.md b/lectures/ar1_processes.md deleted file mode 100644 index e29e0df39..000000000 --- a/lectures/ar1_processes.md +++ /dev/null @@ -1,604 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst -kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - -(ar1)= -```{raw} html -
- - QuantEcon - -
-``` - -# AR1 Processes - -```{index} single: Autoregressive processes -``` - -```{contents} Contents -:depth: 2 -``` - -## Overview - -In this lecture we are going to study a very simple class of stochastic -models called AR(1) processes. - -These simple models are used again and again in economic research to represent the dynamics of series such as - -* labor income -* dividends -* productivity, etc. - -AR(1) processes can take negative values but are easily converted into positive processes when necessary by a transformation such as exponentiation. - -We are going to study AR(1) processes partly because they are useful and -partly because they help us understand important concepts. - -Let's start with some imports: - -```{code-cell} ipython -import numpy as np -import matplotlib.pyplot as plt -plt.rcParams["figure.figsize"] = (11, 5) #set default figure size -``` - -## The AR(1) Model - -The **AR(1) model** (autoregressive model of order 1) takes the form - -```{math} -:label: can_ar1 - -X_{t+1} = a X_t + b + c W_{t+1} -``` - -where $a, b, c$ are scalar-valued parameters. - -This law of motion generates a time series $\{ X_t\}$ as soon as we -specify an initial condition $X_0$. - -This is called the **state process** and the state space is $\mathbb R$. - -To make things even simpler, we will assume that - -* the process $\{ W_t \}$ is IID and standard normal, -* the initial condition $X_0$ is drawn from the normal distribution $N(\mu_0, v_0)$ and -* the initial condition $X_0$ is independent of $\{ W_t \}$. - -### Moving Average Representation - -Iterating backwards from time $t$, we obtain - -$$ -X_t = a X_{t-1} + b + c W_t - = a^2 X_{t-2} + a b + a c W_{t-1} + b + c W_t - = \cdots -$$ - -If we work all the way back to time zero, we get - -```{math} -:label: ar1_ma - -X_t = a^t X_0 + b \sum_{j=0}^{t-1} a^j + - c \sum_{j=0}^{t-1} a^j W_{t-j} -``` - -Equation {eq}`ar1_ma` shows that $X_t$ is a well defined random variable, the value of which depends on - -* the parameters, -* the initial condition $X_0$ and -* the shocks $W_1, \ldots W_t$ from time $t=1$ to the present. - -Throughout, the symbol $\psi_t$ will be used to refer to the -density of this random variable $X_t$. - -### Distribution Dynamics - -One of the nice things about this model is that it's so easy to trace out the sequence of distributions $\{ \psi_t \}$ corresponding to the time -series $\{ X_t\}$. - -To see this, we first note that $X_t$ is normally distributed for each $t$. - -This is immediate from {eq}`ar1_ma`, since linear combinations of independent -normal random variables are normal. - -Given that $X_t$ is normally distributed, we will know the full distribution -$\psi_t$ if we can pin down its first two moments. - -Let $\mu_t$ and $v_t$ denote the mean and variance -of $X_t$ respectively. - -We can pin down these values from {eq}`ar1_ma` or we can use the following -recursive expressions: - -```{math} -:label: dyn_tm - -\mu_{t+1} = a \mu_t + b -\quad \text{and} \quad -v_{t+1} = a^2 v_t + c^2 -``` - -These expressions are obtained from {eq}`can_ar1` by taking, respectively, the expectation and variance of both sides of the equality. - -In calculating the second expression, we are using the fact that $X_t$ -and $W_{t+1}$ are independent. - -(This follows from our assumptions and {eq}`ar1_ma`.) - -Given the dynamics in {eq}`ar1_ma` and initial conditions $\mu_0, -v_0$, we obtain $\mu_t, v_t$ and hence - -$$ -\psi_t = N(\mu_t, v_t) -$$ - -The following code uses these facts to track the sequence of marginal -distributions $\{ \psi_t \}$. - -The parameters are - -```{code-cell} python3 -a, b, c = 0.9, 0.1, 0.5 - -mu, v = -3.0, 0.6 # initial conditions mu_0, v_0 -``` - -Here's the sequence of distributions: - -```{code-cell} python3 -from scipy.stats import norm - -sim_length = 10 -grid = np.linspace(-5, 7, 120) - -fig, ax = plt.subplots() - -for t in range(sim_length): - mu = a * mu + b - v = a**2 * v + c**2 - ax.plot(grid, norm.pdf(grid, loc=mu, scale=np.sqrt(v)), - label=f"$\psi_{t}$", - alpha=0.7) - -ax.legend(bbox_to_anchor=[1.05,1],loc=2,borderaxespad=1) - -plt.show() -``` - -## Stationarity and Asymptotic Stability - -Notice that, in the figure above, the sequence $\{ \psi_t \}$ seems to be converging to a limiting distribution. - -This is even clearer if we project forward further into the future: - -```{code-cell} python3 -def plot_density_seq(ax, mu_0=-3.0, v_0=0.6, sim_length=60): - mu, v = mu_0, v_0 - for t in range(sim_length): - mu = a * mu + b - v = a**2 * v + c**2 - ax.plot(grid, - norm.pdf(grid, loc=mu, scale=np.sqrt(v)), - alpha=0.5) - -fig, ax = plt.subplots() -plot_density_seq(ax) -plt.show() -``` - -Moreover, the limit does not depend on the initial condition. - -For example, this alternative density sequence also converges to the same limit. - -```{code-cell} python3 -fig, ax = plt.subplots() -plot_density_seq(ax, mu_0=3.0) -plt.show() -``` - -In fact it's easy to show that such convergence will occur, regardless of the initial condition, whenever $|a| < 1$. - -To see this, we just have to look at the dynamics of the first two moments, as -given in {eq}`dyn_tm`. - -When $|a| < 1$, these sequences converge to the respective limits - -```{math} -:label: mu_sig_star - -\mu^* := \frac{b}{1-a} -\quad \text{and} \quad -v^* = \frac{c^2}{1 - a^2} -``` - -(See our {doc}`lecture on one dimensional dynamics ` for background on deterministic convergence.) - -Hence - -```{math} -:label: ar1_psi_star - -\psi_t \to \psi^* = N(\mu^*, v^*) -\quad \text{as } -t \to \infty -``` - -We can confirm this is valid for the sequence above using the following code. - -```{code-cell} python3 -fig, ax = plt.subplots() -plot_density_seq(ax, mu_0=3.0) - -mu_star = b / (1 - a) -std_star = np.sqrt(c**2 / (1 - a**2)) # square root of v_star -psi_star = norm.pdf(grid, loc=mu_star, scale=std_star) -ax.plot(grid, psi_star, 'k-', lw=2, label="$\psi^*$") -ax.legend() - -plt.show() -``` - -As claimed, the sequence $\{ \psi_t \}$ converges to $\psi^*$. - -### Stationary Distributions - -A stationary distribution is a distribution that is a fixed -point of the update rule for distributions. - -In other words, if $\psi_t$ is stationary, then $\psi_{t+j} = -\psi_t$ for all $j$ in $\mathbb N$. - -A different way to put this, specialized to the current setting, is as follows: a -density $\psi$ on $\mathbb R$ is **stationary** for the AR(1) process if - -$$ -X_t \sim \psi -\quad \implies \quad -a X_t + b + c W_{t+1} \sim \psi -$$ - -The distribution $\psi^*$ in {eq}`ar1_psi_star` has this property --- -checking this is an exercise. - -(Of course, we are assuming that $|a| < 1$ so that $\psi^*$ is -well defined.) - -In fact, it can be shown that no other distribution on $\mathbb R$ has this property. - -Thus, when $|a| < 1$, the AR(1) model has exactly one stationary density and that density is given by $\psi^*$. - -## Ergodicity - -The concept of ergodicity is used in different ways by different authors. - -One way to understand it in the present setting is that a version of the Law -of Large Numbers is valid for $\{X_t\}$, even though it is not IID. - -In particular, averages over time series converge to expectations under the -stationary distribution. - -Indeed, it can be proved that, whenever $|a| < 1$, we have - -```{math} -:label: ar1_ergo - -\frac{1}{m} \sum_{t = 1}^m h(X_t) \to -\int h(x) \psi^*(x) dx - \quad \text{as } m \to \infty -``` - -whenever the integral on the right hand side is finite and well defined. - -Notes: - -* In {eq}`ar1_ergo`, convergence holds with probability one. -* The textbook by {cite}`MeynTweedie2009` is a classic reference on ergodicity. - -For example, if we consider the identity function $h(x) = x$, we get - -$$ -\frac{1}{m} \sum_{t = 1}^m X_t \to -\int x \psi^*(x) dx - \quad \text{as } m \to \infty -$$ - -In other words, the time series sample mean converges to the mean of the -stationary distribution. - -As will become clear over the next few lectures, ergodicity is a very -important concept for statistics and simulation. - -## Exercises - -```{exercise} -:label: ar1p_ex1 - -Let $k$ be a natural number. - -The $k$-th central moment of a random variable is defined as - -$$ -M_k := \mathbb E [ (X - \mathbb E X )^k ] -$$ - -When that random variable is $N(\mu, \sigma^2)$, it is known that - -$$ -M_k = -\begin{cases} - 0 & \text{ if } k \text{ is odd} \\ - \sigma^k (k-1)!! & \text{ if } k \text{ is even} -\end{cases} -$$ - -Here $n!!$ is the double factorial. - -According to {eq}`ar1_ergo`, we should have, for any $k \in \mathbb N$, - -$$ -\frac{1}{m} \sum_{t = 1}^m - (X_t - \mu^* )^k - \approx M_k -$$ - -when $m$ is large. - -Confirm this by simulation at a range of $k$ using the default parameters from the lecture. -``` - - -```{solution-start} ar1p_ex1 -:class: dropdown -``` - -Here is one solution: - -```{code-cell} python3 -from numba import njit -from scipy.special import factorial2 - -@njit -def sample_moments_ar1(k, m=100_000, mu_0=0.0, sigma_0=1.0, seed=1234): - np.random.seed(seed) - sample_sum = 0.0 - x = mu_0 + sigma_0 * np.random.randn() - for t in range(m): - sample_sum += (x - mu_star)**k - x = a * x + b + c * np.random.randn() - return sample_sum / m - -def true_moments_ar1(k): - if k % 2 == 0: - return std_star**k * factorial2(k - 1) - else: - return 0 - -k_vals = np.arange(6) + 1 -sample_moments = np.empty_like(k_vals) -true_moments = np.empty_like(k_vals) - -for k_idx, k in enumerate(k_vals): - sample_moments[k_idx] = sample_moments_ar1(k) - true_moments[k_idx] = true_moments_ar1(k) - -fig, ax = plt.subplots() -ax.plot(k_vals, true_moments, label="true moments") -ax.plot(k_vals, sample_moments, label="sample moments") -ax.legend() - -plt.show() -``` - -```{solution-end} -``` - - -```{exercise} -:label: ar1p_ex2 - -Write your own version of a one dimensional [kernel density -estimator](https://en.wikipedia.org/wiki/Kernel_density_estimation), -which estimates a density from a sample. - -Write it as a class that takes the data $X$ and bandwidth -$h$ when initialized and provides a method $f$ such that - -$$ -f(x) = \frac{1}{hn} \sum_{i=1}^n -K \left( \frac{x-X_i}{h} \right) -$$ - -For $K$ use the Gaussian kernel ($K$ is the standard normal -density). - -Write the class so that the bandwidth defaults to Silverman’s rule (see -the “rule of thumb” discussion on [this -page](https://en.wikipedia.org/wiki/Kernel_density_estimation)). Test -the class you have written by going through the steps - -1. simulate data $X_1, \ldots, X_n$ from distribution $\phi$ -1. plot the kernel density estimate over a suitable range -1. plot the density of $\phi$ on the same figure - -for distributions $\phi$ of the following types - -- [beta - distribution](https://en.wikipedia.org/wiki/Beta_distribution) - with $\alpha = \beta = 2$ -- [beta - distribution](https://en.wikipedia.org/wiki/Beta_distribution) - with $\alpha = 2$ and $\beta = 5$ -- [beta - distribution](https://en.wikipedia.org/wiki/Beta_distribution) - with $\alpha = \beta = 0.5$ - -Use $n=500$. - -Make a comment on your results. (Do you think this is a good estimator -of these distributions?) -``` - - -```{solution-start} ar1p_ex2 -:class: dropdown -``` - -Here is one solution: - -```{code-cell} ipython3 -K = norm.pdf - -class KDE: - - def __init__(self, x_data, h=None): - - if h is None: - c = x_data.std() - n = len(x_data) - h = 1.06 * c * n**(-1/5) - self.h = h - self.x_data = x_data - - def f(self, x): - if np.isscalar(x): - return K((x - self.x_data) / self.h).mean() * (1/self.h) - else: - y = np.empty_like(x) - for i, x_val in enumerate(x): - y[i] = K((x_val - self.x_data) / self.h).mean() * (1/self.h) - return y -``` - -```{code-cell} ipython3 -def plot_kde(ϕ, x_min=-0.2, x_max=1.2): - x_data = ϕ.rvs(n) - kde = KDE(x_data) - - x_grid = np.linspace(-0.2, 1.2, 100) - fig, ax = plt.subplots() - ax.plot(x_grid, kde.f(x_grid), label="estimate") - ax.plot(x_grid, ϕ.pdf(x_grid), label="true density") - ax.legend() - plt.show() -``` - -```{code-cell} ipython3 -from scipy.stats import beta - -n = 500 -parameter_pairs= (2, 2), (2, 5), (0.5, 0.5) -for α, β in parameter_pairs: - plot_kde(beta(α, β)) -``` - -We see that the kernel density estimator is effective when the underlying -distribution is smooth but less so otherwise. - -```{solution-end} -``` - - -```{exercise} -:label: ar1p_ex3 - -In the lecture we discussed the following fact: for the $AR(1)$ process - -$$ -X_{t+1} = a X_t + b + c W_{t+1} -$$ - -with $\{ W_t \}$ iid and standard normal, - -$$ -\psi_t = N(\mu, s^2) \implies \psi_{t+1} -= N(a \mu + b, a^2 s^2 + c^2) -$$ - -Confirm this, at least approximately, by simulation. Let - -- $a = 0.9$ -- $b = 0.0$ -- $c = 0.1$ -- $\mu = -3$ -- $s = 0.2$ - -First, plot $\psi_t$ and $\psi_{t+1}$ using the true -distributions described above. - -Second, plot $\psi_{t+1}$ on the same figure (in a different -color) as follows: - -1. Generate $n$ draws of $X_t$ from the $N(\mu, s^2)$ - distribution -1. Update them all using the rule - $X_{t+1} = a X_t + b + c W_{t+1}$ -1. Use the resulting sample of $X_{t+1}$ values to produce a - density estimate via kernel density estimation. - -Try this for $n=2000$ and confirm that the -simulation based estimate of $\psi_{t+1}$ does converge to the -theoretical distribution. -``` - -```{solution-start} ar1p_ex3 -:class: dropdown -``` - -Here is our solution - -```{code-cell} ipython3 -a = 0.9 -b = 0.0 -c = 0.1 -μ = -3 -s = 0.2 -``` - -```{code-cell} ipython3 -μ_next = a * μ + b -s_next = np.sqrt(a**2 * s**2 + c**2) -``` - -```{code-cell} ipython3 -ψ = lambda x: K((x - μ) / s) -ψ_next = lambda x: K((x - μ_next) / s_next) -``` - -```{code-cell} ipython3 -ψ = norm(μ, s) -ψ_next = norm(μ_next, s_next) -``` - -```{code-cell} ipython3 -n = 2000 -x_draws = ψ.rvs(n) -x_draws_next = a * x_draws + b + c * np.random.randn(n) -kde = KDE(x_draws_next) - -x_grid = np.linspace(μ - 1, μ + 1, 100) -fig, ax = plt.subplots() - -ax.plot(x_grid, ψ.pdf(x_grid), label="$\psi_t$") -ax.plot(x_grid, ψ_next.pdf(x_grid), label="$\psi_{t+1}$") -ax.plot(x_grid, kde.f(x_grid), label="estimate of $\psi_{t+1}$") - -ax.legend() -plt.show() -``` - -The simulated distribution approximately coincides with the theoretical -distribution, as predicted. - -```{solution-end} -``` diff --git a/lectures/scalar_dynam.md b/lectures/scalar_dynam.md deleted file mode 100644 index 7a78b83e9..000000000 --- a/lectures/scalar_dynam.md +++ /dev/null @@ -1,518 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst -kernelspec: - display_name: Python 3 - language: python - name: python3 ---- - -```{raw} html - -``` - -# {index}`Dynamics in One Dimension ` - -```{contents} Contents -:depth: 2 -``` - -## Overview - -In this lecture we give a quick introduction to discrete time dynamics in one -dimension. - -In one-dimensional models, the state of the system is described by a single variable. - -Although most interesting dynamic models have two or more state variables, the -one-dimensional setting is a good place to learn the foundations of dynamics and build -intuition. - -Let's start with some standard imports: - -```{code-cell} ipython -import matplotlib.pyplot as plt -plt.rcParams["figure.figsize"] = (11, 5) #set default figure size -import numpy as np -``` - -## Some Definitions - -This section sets out the objects of interest and the kinds of properties we study. - -### Difference Equations - -A **time homogeneous first order difference equation** is an equation of the -form - -```{math} -:label: sdsod - -x_{t+1} = g(x_t) -``` - -where $g$ is a function from some subset $S$ of $\mathbb R$ to itself. - -Here $S$ is called the **state space** and $x$ is called the **state variable**. - -In the definition, - -* time homogeneity means that $g$ is the same at each time $t$ -* first order means dependence on only one lag (i.e., earlier states such as $x_{t-1}$ do not enter into {eq}`sdsod`). - -If $x_0 \in S$ is given, then {eq}`sdsod` recursively defines the sequence - -```{math} -:label: sdstraj - -x_0, \quad -x_1 = g(x_0), \quad -x_2 = g(x_1) = g(g(x_0)), \quad \text{etc.} -``` - -This sequence is called the **trajectory** of $x_0$ under $g$. - -If we define $g^n$ to be $n$ compositions of $g$ with itself, then we can write the trajectory more simply as $x_t = g^t(x_0)$ for $t \geq 0$. - -### Example: A Linear Model - -One simple example is the **linear difference equation** - -$$ -x_{t+1} = a x_t + b, \qquad S = \mathbb R -$$ - -where $a, b$ are fixed constants. - -In this case, given $x_0$, the trajectory {eq}`sdstraj` is - -```{math} -:label: sdslinmodpath - -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 {doc}`geometric series `, we find that, for any $t \geq 0$, - -```{math} -:label: sdslinmod - -x_t = a^t x_0 + b \frac{1 - a^t}{1 - a} -``` - -This is about all we need to know about the linear model. - -We have an exact expression for $x_t$ for all $t$ and hence a full -understanding of the dynamics. - -Notice in particular that $|a| < 1$, then, by {eq}`sdslinmod`, we have - -```{math} -:label: sdslinmodc - -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. - -### Example: A Nonlinear Model - -In the linear example above, we obtained an exact analytical expression for $x_t$ -in terms of arbitrary $t$ and $x_0$. - -This made analysis of dynamics very easy. - -When models are nonlinear, however, the situation can be quite different. - -For example, recall how we [previously studied](https://python-programming.quantecon.org/python_oop.html#example-the-solow-growth-model) the law of motion for the Solow growth model, a simplified version of which is - -```{math} -:label: solow_lom2 - -k_{t+1} = s z k_t^{\alpha} + (1 - \delta) k_t -``` - -Here $k$ is capital stock and $s, z, \alpha, \delta$ are positive -parameters with $0 < \alpha, \delta < 1$. - -If you try to iterate like we did in {eq}`sdslinmodpath`, you will find that -the algebra gets messy quickly. - -Analyzing the dynamics of this model requires a different method (see below). - -### Stability - -A **steady state** of the difference equation $x_{t+1} = g(x_t)$ 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$. - -A steady state $x^*$ of $x_{t+1} = g(x_t)$ 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 {eq}`sdslinmod`. - -A steady state $x^*$ of $x_{t+1} = g(x_t)$ 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. - -We will see examples below where the converse is not true. - -## 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 model with dynamics given in {eq}`solow_lom2`. - -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. - -```{code-cell} ipython ---- -tags: [output_scroll] ---- -def subplots(fs): - "Custom subplots with axes throught the origin" - fig, ax = plt.subplots(figsize=fs) - - # 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((6.5, 6)) - ax.set_xlim(xmin, xmax) - ax.set_ylim(xmin, xmax) - - 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((7, 5.5)) - 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 model with a fixed set of -parameters - -```{code-cell} ipython -A, s, alpha, delta = 2, 0.3, 0.3, 0.4 -``` - -Here's the update function corresponding to the model. - -```{code-cell} ipython -def g(k): - return A * s * k**alpha + (1 - delta) * k -``` - -Here is the 45 degree plot. - -```{code-cell} ipython -xmin, xmax = 0, 4 # Suitable plotting region. - -plot45(g, xmin, xmax, 0, num_arrows=0) -``` - -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 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)} -$$ - -### 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$. - -```{code-cell} ipython -k0 = 0.25 - -plot45(g, xmin, xmax, k0, num_arrows=5, var='k') -``` - -We can plot the time series of capital corresponding to the figure above as -follows: - -```{code-cell} ipython -ts_plot(g, xmin, xmax, k0, var='k') -``` - -Here's a somewhat longer view: - -```{code-cell} ipython -ts_plot(g, xmin, xmax, k0, ts_length=20, var='k') -``` - -When capital stock is higher than the unique positive steady state, we see that -it declines: - -```{code-cell} ipython -k0 = 2.95 - -plot45(g, xmin, xmax, k0, num_arrows=5, var='k') -``` - -Here is the time series: - -```{code-cell} ipython -ts_plot(g, xmin, xmax, k0, var='k') -``` - -### Complex Dynamics - -The Solow 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. - -```{code-cell} ipython -xmin, xmax = 0, 1 -g = lambda x: 4 * x * (1 - x) - -x0 = 0.3 -plot45(g, xmin, xmax, x0, num_arrows=0) -``` - -Now let's look at a typical trajectory. - -```{code-cell} ipython -plot45(g, xmin, xmax, x0, num_arrows=6) -``` - -Notice how irregular it is. - -Here is the corresponding time series plot. - -```{code-cell} ipython -ts_plot(g, xmin, xmax, x0, ts_length=6) -``` - -The irregularity is even clearer over a longer time horizon: - -```{code-cell} ipython -ts_plot(g, xmin, xmax, x0, ts_length=20) -``` - -## Exercises - -```{exercise} -:label: sd_ex1 - -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. -``` - -```{solution-start} sd_ex1 -:class: dropdown -``` - -We will start with the case $a=0.5$. - -Let's set up the model and plotting region: - -```{code-cell} ipython -a, b = 0.5, 1 -xmin, xmax = -1, 3 -g = lambda x: a * x + b -``` - -Now let's plot a trajectory: - -```{code-cell} ipython -x0 = -0.5 -plot45(g, xmin, xmax, x0, num_arrows=5) -``` - -Here is the corresponding time series, which converges towards the steady -state. - -```{code-cell} ipython -ts_plot(g, xmin, xmax, x0, ts_length=10) -``` - -Now let's try $a=-0.5$ and see what differences we observe. - -Let's set up the model and plotting region: - -```{code-cell} ipython -a, b = -0.5, 1 -xmin, xmax = -1, 3 -g = lambda x: a * x + b -``` - -Now let's plot a trajectory: - -```{code-cell} ipython -x0 = -0.5 -plot45(g, xmin, xmax, x0, num_arrows=5) -``` - -Here is the corresponding time series, which converges towards the steady -state. - -```{code-cell} ipython -ts_plot(g, xmin, xmax, x0, ts_length=10) -``` - -Once again, we have convergence to the steady state but the nature of -convergence differs. - -In particular, the time series jumps from above the steady state to below it -and back again. - -In the current context, the series is said to exhibit **damped oscillations**. - -```{solution-end} -``` From f5433bdfb64358340b934860ea27b1012f526510 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Wed, 24 Jan 2024 12:07:30 +1100 Subject: [PATCH 2/9] revert removal of scalar_dynam --- lectures/_toc.yml | 1 + lectures/scalar_dynam.md | 518 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 519 insertions(+) create mode 100644 lectures/scalar_dynam.md diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 6067e898c..588614dc1 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -38,6 +38,7 @@ parts: - caption: Introduction to Dynamics numbered: true chapters: + - file: scalar_dynam - file: finite_markov - file: inventory_dynamics - file: linear_models diff --git a/lectures/scalar_dynam.md b/lectures/scalar_dynam.md new file mode 100644 index 000000000..3e0f0d82f --- /dev/null +++ b/lectures/scalar_dynam.md @@ -0,0 +1,518 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{raw} html + +``` + +# {index}`Dynamics in One Dimension ` + +```{contents} Contents +:depth: 2 +``` + +## Overview + +In this lecture we give a quick introduction to discrete time dynamics in one +dimension. + +In one-dimensional models, the state of the system is described by a single variable. + +Although most interesting dynamic models have two or more state variables, the +one-dimensional setting is a good place to learn the foundations of dynamics and build +intuition. + +Let's start with some standard imports: + +```{code-cell} ipython +import matplotlib.pyplot as plt +plt.rcParams["figure.figsize"] = (11, 5) #set default figure size +import numpy as np +``` + +## Some Definitions + +This section sets out the objects of interest and the kinds of properties we study. + +### Difference Equations + +A **time homogeneous first order difference equation** is an equation of the +form + +```{math} +:label: sdsod + +x_{t+1} = g(x_t) +``` + +where $g$ is a function from some subset $S$ of $\mathbb R$ to itself. + +Here $S$ is called the **state space** and $x$ is called the **state variable**. + +In the definition, + +* time homogeneity means that $g$ is the same at each time $t$ +* first order means dependence on only one lag (i.e., earlier states such as $x_{t-1}$ do not enter into {eq}`sdsod`). + +If $x_0 \in S$ is given, then {eq}`sdsod` recursively defines the sequence + +```{math} +:label: sdstraj + +x_0, \quad +x_1 = g(x_0), \quad +x_2 = g(x_1) = g(g(x_0)), \quad \text{etc.} +``` + +This sequence is called the **trajectory** of $x_0$ under $g$. + +If we define $g^n$ to be $n$ compositions of $g$ with itself, then we can write the trajectory more simply as $x_t = g^t(x_0)$ for $t \geq 0$. + +### Example: A Linear Model + +One simple example is the **linear difference equation** + +$$ +x_{t+1} = a x_t + b, \qquad S = \mathbb R +$$ + +where $a, b$ are fixed constants. + +In this case, given $x_0$, the trajectory {eq}`sdstraj` is + +```{math} +:label: sdslinmodpath + +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 {doc}`geometric series `, we find that, for any $t \geq 0$, + +```{math} +:label: sdslinmod + +x_t = a^t x_0 + b \frac{1 - a^t}{1 - a} +``` + +This is about all we need to know about the linear model. + +We have an exact expression for $x_t$ for all $t$ and hence a full +understanding of the dynamics. + +Notice in particular that $|a| < 1$, then, by {eq}`sdslinmod`, we have + +```{math} +:label: sdslinmodc + +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. + +### Example: A Nonlinear Model + +In the linear example above, we obtained an exact analytical expression for $x_t$ +in terms of arbitrary $t$ and $x_0$. + +This made analysis of dynamics very easy. + +When models are nonlinear, however, the situation can be quite different. + +For example, recall how we [previously studied](https://python-programming.quantecon.org/python_oop.html#example-the-solow-growth-model) the law of motion for the Solow growth model, a simplified version of which is + +```{math} +:label: solow_lom2 + +k_{t+1} = s z k_t^{\alpha} + (1 - \delta) k_t +``` + +Here $k$ is capital stock and $s, z, \alpha, \delta$ are positive +parameters with $0 < \alpha, \delta < 1$. + +If you try to iterate like we did in {eq}`sdslinmodpath`, you will find that +the algebra gets messy quickly. + +Analyzing the dynamics of this model requires a different method (see below). + +### Stability + +A **steady state** of the difference equation $x_{t+1} = g(x_t)$ 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$. + +A steady state $x^*$ of $x_{t+1} = g(x_t)$ 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 {eq}`sdslinmod`. + +A steady state $x^*$ of $x_{t+1} = g(x_t)$ 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. + +We will see examples below where the converse is not true. + +## 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 model with dynamics given in {eq}`solow_lom2`. + +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. + +```{code-cell} ipython +--- +tags: [output_scroll] +--- +def subplots(fs): + "Custom subplots with axes throught the origin" + fig, ax = plt.subplots(figsize=fs) + + # 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((6.5, 6)) + ax.set_xlim(xmin, xmax) + ax.set_ylim(xmin, xmax) + + 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((7, 5.5)) + 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 model with a fixed set of +parameters + +```{code-cell} ipython +A, s, alpha, delta = 2, 0.3, 0.3, 0.4 +``` + +Here's the update function corresponding to the model. + +```{code-cell} ipython +def g(k): + return A * s * k**alpha + (1 - delta) * k +``` + +Here is the 45 degree plot. + +```{code-cell} ipython +xmin, xmax = 0, 4 # Suitable plotting region. + +plot45(g, xmin, xmax, 0, num_arrows=0) +``` + +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 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)} +$$ + +### 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$. + +```{code-cell} ipython +k0 = 0.25 + +plot45(g, xmin, xmax, k0, num_arrows=5, var='k') +``` + +We can plot the time series of capital corresponding to the figure above as +follows: + +```{code-cell} ipython +ts_plot(g, xmin, xmax, k0, var='k') +``` + +Here's a somewhat longer view: + +```{code-cell} ipython +ts_plot(g, xmin, xmax, k0, ts_length=20, var='k') +``` + +When capital stock is higher than the unique positive steady state, we see that +it declines: + +```{code-cell} ipython +k0 = 2.95 + +plot45(g, xmin, xmax, k0, num_arrows=5, var='k') +``` + +Here is the time series: + +```{code-cell} ipython +ts_plot(g, xmin, xmax, k0, var='k') +``` + +### Complex Dynamics + +The Solow 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. + +```{code-cell} ipython +xmin, xmax = 0, 1 +g = lambda x: 4 * x * (1 - x) + +x0 = 0.3 +plot45(g, xmin, xmax, x0, num_arrows=0) +``` + +Now let's look at a typical trajectory. + +```{code-cell} ipython +plot45(g, xmin, xmax, x0, num_arrows=6) +``` + +Notice how irregular it is. + +Here is the corresponding time series plot. + +```{code-cell} ipython +ts_plot(g, xmin, xmax, x0, ts_length=6) +``` + +The irregularity is even clearer over a longer time horizon: + +```{code-cell} ipython +ts_plot(g, xmin, xmax, x0, ts_length=20) +``` + +## Exercises + +```{exercise} +:label: sd_ex1 + +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. +``` + +```{solution-start} sd_ex1 +:class: dropdown +``` + +We will start with the case $a=0.5$. + +Let's set up the model and plotting region: + +```{code-cell} ipython +a, b = 0.5, 1 +xmin, xmax = -1, 3 +g = lambda x: a * x + b +``` + +Now let's plot a trajectory: + +```{code-cell} ipython +x0 = -0.5 +plot45(g, xmin, xmax, x0, num_arrows=5) +``` + +Here is the corresponding time series, which converges towards the steady +state. + +```{code-cell} ipython +ts_plot(g, xmin, xmax, x0, ts_length=10) +``` + +Now let's try $a=-0.5$ and see what differences we observe. + +Let's set up the model and plotting region: + +```{code-cell} ipython +a, b = -0.5, 1 +xmin, xmax = -1, 3 +g = lambda x: a * x + b +``` + +Now let's plot a trajectory: + +```{code-cell} ipython +x0 = -0.5 +plot45(g, xmin, xmax, x0, num_arrows=5) +``` + +Here is the corresponding time series, which converges towards the steady +state. + +```{code-cell} ipython +ts_plot(g, xmin, xmax, x0, ts_length=10) +``` + +Once again, we have convergence to the steady state but the nature of +convergence differs. + +In particular, the time series jumps from above the steady state to below it +and back again. + +In the current context, the series is said to exhibit **damped oscillations**. + +```{solution-end} +``` \ No newline at end of file From bbd1b3913f2a728415d681d581e8e92585b3ff05 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Wed, 24 Jan 2024 12:10:28 +1100 Subject: [PATCH 3/9] revert scalar_dynam removal --- lectures/scalar_dynam.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/scalar_dynam.md b/lectures/scalar_dynam.md index 3e0f0d82f..7a78b83e9 100644 --- a/lectures/scalar_dynam.md +++ b/lectures/scalar_dynam.md @@ -515,4 +515,4 @@ and back again. In the current context, the series is said to exhibit **damped oscillations**. ```{solution-end} -``` \ No newline at end of file +``` From 646cf0b076468b73a68c89865b0fbccedc9efe04 Mon Sep 17 00:00:00 2001 From: Humphrey Yang Date: Wed, 24 Jan 2024 12:11:52 +1100 Subject: [PATCH 4/9] add intersphinx tags --- lectures/finite_markov.md | 2 +- lectures/inventory_dynamics.md | 2 +- lectures/kesten_processes.md | 4 ++-- lectures/linear_models.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lectures/finite_markov.md b/lectures/finite_markov.md index 9d88afdac..7242dd05d 100644 --- a/lectures/finite_markov.md +++ b/lectures/finite_markov.md @@ -675,7 +675,7 @@ Such distributions are called **stationary** or **invariant**. Formally, a marginal distribution $\psi^*$ on $S$ is called **stationary** for $P$ if $\psi^* = \psi^* P$. (This is the same notion of stationarity that we learned about in the -{doc}`lecture on AR(1) processes ` applied to a different setting.) +{doc}`lecture on AR(1) processes ` applied to a different setting.) From this equality, we immediately get $\psi^* = \psi^* P^t$ for all $t$. diff --git a/lectures/inventory_dynamics.md b/lectures/inventory_dynamics.md index 7549afee0..67a25d596 100644 --- a/lectures/inventory_dynamics.md +++ b/lectures/inventory_dynamics.md @@ -283,7 +283,7 @@ histogram just above. This model is asymptotically stationary, with a unique stationary distribution. -(See the discussion of stationarity in {doc}`our lecture on AR(1) processes ` for background --- the fundamental concepts are the same.) +(See the discussion of stationarity in {doc}`our lecture on AR(1) processes ` for background --- the fundamental concepts are the same.) In particular, the sequence of marginal distributions $\{\psi_t\}$ is converging to a unique limiting distribution that does not depend on diff --git a/lectures/kesten_processes.md b/lectures/kesten_processes.md index ec78d9ae2..77c648628 100644 --- a/lectures/kesten_processes.md +++ b/lectures/kesten_processes.md @@ -38,7 +38,7 @@ tags: [hide-output] ## Overview -{doc}`Previously ` we learned about linear scalar-valued stochastic processes (AR(1) models). +{doc}`Previously ` we learned about linear scalar-valued stochastic processes (AR(1) models). Now we generalize these linear models slightly by allowing the multiplicative coefficient to be stochastic. @@ -170,7 +170,7 @@ is a Kesten process. ### Stationarity -In earlier lectures, such as the one on {doc}`AR(1) processes `, we introduced the notion of a stationary distribution. +In earlier lectures, such as the one on {doc}`AR(1) processes `, we introduced the notion of a stationary distribution. In the present context, we can define a stationary distribution as follows: diff --git a/lectures/linear_models.md b/lectures/linear_models.md index 442533745..9c019ff87 100644 --- a/lectures/linear_models.md +++ b/lectures/linear_models.md @@ -44,7 +44,7 @@ tags: [hide-output] This lecture introduces the **linear state space** dynamic system. -The linear state space system is a generalization of the scalar AR(1) process {doc}`we studied before `. +The linear state space system is a generalization of the scalar AR(1) process {doc}`we studied before `. This model is a workhorse that carries a powerful theory of prediction. From 1146d7f5c1e7205458d7efed02393f0cde983341 Mon Sep 17 00:00:00 2001 From: mmcky Date: Wed, 24 Jan 2024 15:43:07 +1100 Subject: [PATCH 5/9] apply redirect for ar1_processes to new https://intro.quantecon.org/ar1_processes.html --- lectures/_config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/lectures/_config.yml b/lectures/_config.yml index e5b05da3f..7734e341f 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -102,6 +102,7 @@ sphinx: # Remote Redirects redirects: heavy_tails: https://intro.quantecon.org/heavy_tails.html + ar_processes: https://intro.quantecon.org/ar1_processes.html tojupyter_static_file_path: ["source/_static", "_static"] tojupyter_target_html: true tojupyter_urlpath: "https://python.quantecon.org/" From 3ceb76b5ce2bbb1264d7c3baac44926564027f11 Mon Sep 17 00:00:00 2001 From: mmcky Date: Wed, 24 Jan 2024 16:26:16 +1100 Subject: [PATCH 6/9] fix typos --- lectures/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/_config.yml b/lectures/_config.yml index 7734e341f..0cd481ae9 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -102,7 +102,7 @@ sphinx: # Remote Redirects redirects: heavy_tails: https://intro.quantecon.org/heavy_tails.html - ar_processes: https://intro.quantecon.org/ar1_processes.html + ar1_processes: https://intro.quantecon.org/ar1_processes.html tojupyter_static_file_path: ["source/_static", "_static"] tojupyter_target_html: true tojupyter_urlpath: "https://python.quantecon.org/" From ca5a20ab6021b93b9ae2056c24f59c10c7f5b26f Mon Sep 17 00:00:00 2001 From: mmcky Date: Fri, 26 Jan 2024 12:14:46 +1100 Subject: [PATCH 7/9] TST: remove rerediraffe setting for ar1_processes --- lectures/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/_config.yml b/lectures/_config.yml index 0cd481ae9..06f4886a1 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -102,7 +102,7 @@ sphinx: # Remote Redirects redirects: heavy_tails: https://intro.quantecon.org/heavy_tails.html - ar1_processes: https://intro.quantecon.org/ar1_processes.html + # ar1_processes: https://intro.quantecon.org/ar1_processes.html tojupyter_static_file_path: ["source/_static", "_static"] tojupyter_target_html: true tojupyter_urlpath: "https://python.quantecon.org/" From eed366204db4f5fbae497dc5504c80e0b866852c Mon Sep 17 00:00:00 2001 From: mmcky Date: Fri, 26 Jan 2024 12:40:28 +1100 Subject: [PATCH 8/9] configure intersphinx in yml --- lectures/_config.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lectures/_config.yml b/lectures/_config.yml index 06f4886a1..a1364327c 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -87,9 +87,10 @@ sphinx: google_analytics_id: G-J0SMYR4SG3 launch_buttons: colab_url : https://colab.research.google.com - intersphinx_mapping: { - 'intro': ["https://intro.quantecon.org/", null] - } + intersphinx_mapping: + intro: + - "https://intro.quantecon.org/" + - null mathjax3_config: tex: macros: From cdf81e8991ea364d8fac761bcc5617be5c49b864 Mon Sep 17 00:00:00 2001 From: mmcky Date: Fri, 26 Jan 2024 13:03:26 +1100 Subject: [PATCH 9/9] add back in the reredirect as working locally --- lectures/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/_config.yml b/lectures/_config.yml index a1364327c..51848cf92 100644 --- a/lectures/_config.yml +++ b/lectures/_config.yml @@ -103,7 +103,7 @@ sphinx: # Remote Redirects redirects: heavy_tails: https://intro.quantecon.org/heavy_tails.html - # ar1_processes: https://intro.quantecon.org/ar1_processes.html + ar1_processes: https://intro.quantecon.org/ar1_processes.html tojupyter_static_file_path: ["source/_static", "_static"] tojupyter_target_html: true tojupyter_urlpath: "https://python.quantecon.org/"