Skip to content

Commit a862bc6

Browse files
authored
Merge branch 'main' into blume_easley
2 parents 15ab932 + eb30e4f commit a862bc6

12 files changed

Lines changed: 129 additions & 49 deletions

.github/workflows/collab.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ jobs:
1111
with:
1212
ref: ${{ github.event.pull_request.head.sha }}
1313
# Install build software
14-
- name: Install Build Software & LaTeX (kalman_2)
14+
- name: Install Build Software & LaTeX
1515
shell: bash -l {0}
1616
run: |
1717
pip install jupyter-book==1.0.3 quantecon-book-theme==0.8.2 sphinx-tojupyter==0.3.0 sphinxext-rediraffe==0.2.7 sphinxcontrib-youtube==1.3.0 sphinx-togglebutton==0.3.2 arviz sphinx-proof sphinx-exercise sphinx-reredirects
18+
apt-get update
1819
apt-get install dvipng texlive texlive-latex-extra texlive-fonts-recommended cm-super
1920
- name: Check nvidia drivers
2021
shell: bash -l {0}

lectures/aiyagari.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ jupytext:
33
text_representation:
44
extension: .md
55
format_name: myst
6+
format_version: 0.13
7+
jupytext_version: 1.16.7
68
kernelspec:
7-
display_name: Python 3
9+
display_name: Python 3 (ipykernel)
810
language: python
911
name: python3
1012
---
@@ -26,10 +28,9 @@ kernelspec:
2628

2729
In addition to what's in Anaconda, this lecture will need the following libraries:
2830

29-
```{code-cell} ipython
30-
---
31-
tags: [hide-output]
32-
---
31+
```{code-cell} ipython3
32+
:tags: [hide-output]
33+
3334
!pip install quantecon
3435
```
3536

@@ -54,7 +55,7 @@ The Aiyagari model has been used to investigate many topics, including
5455

5556
Let's start with some imports:
5657

57-
```{code-cell} ipython
58+
```{code-cell} ipython3
5859
import matplotlib.pyplot as plt
5960
plt.rcParams["figure.figsize"] = (11, 5) #set default figure size
6061
import numpy as np
@@ -208,7 +209,7 @@ when the parameters change.
208209

209210
The class also includes a default set of parameters that we'll adopt unless otherwise specified.
210211

211-
```{code-cell} python3
212+
```{code-cell} ipython3
212213
class Household:
213214
"""
214215
This class takes the parameters that define a household asset accumulation
@@ -318,7 +319,7 @@ def asset_marginal(s_probs, a_size, z_size):
318319

319320
As a first example of what we can do, let's compute and plot an optimal accumulation policy at fixed prices.
320321

321-
```{code-cell} python3
322+
```{code-cell} ipython3
322323
# Example prices
323324
r = 0.03
324325
w = 0.956
@@ -366,7 +367,7 @@ The following code draws aggregate supply and demand curves.
366367

367368
The intersection gives equilibrium interest rates and capital.
368369

369-
```{code-cell} python3
370+
```{code-cell} ipython3
370371
A = 1.0
371372
N = 1.0
372373
α = 0.33
@@ -410,7 +411,7 @@ def prices_to_capital_stock(am, r):
410411
# Extract the marginal distribution for assets
411412
asset_probs = asset_marginal(stationary_probs, am.a_size, am.z_size)
412413
# Return K
413-
return np.sum(asset_probs * am.a_vals)
414+
return asset_probs @ am.a_vals
414415
415416
416417
# Create an instance of Household

lectures/cass_koopmans_1.md

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jupytext:
44
extension: .md
55
format_name: myst
66
format_version: 0.13
7-
jupytext_version: 1.16.4
7+
jupytext_version: 1.17.2
88
kernelspec:
99
display_name: Python 3 (ipykernel)
1010
language: python
@@ -62,6 +62,13 @@ The lecture uses important ideas including
6262
long but finite-horizon economies.
6363
- A **stable manifold** and a **phase plane**
6464

65+
In addition to what's in Anaconda, this lecture will need the following libraries:
66+
67+
```{code-cell} ipython
68+
:tags: [hide-output]
69+
!pip install quantecon
70+
```
71+
6572
Let's start with some standard imports:
6673

6774
```{code-cell} ipython3
@@ -614,7 +621,7 @@ tolerance bounds), we stop.
614621
def bisection(pp, c0, k0, T=10, tol=1e-4, max_iter=500, k_ter=0, verbose=True):
615622
616623
# initial boundaries for guess c0
617-
c0_upper = pp.f(k0)
624+
c0_upper = pp.f(k0) + (1 - pp.δ) * k0
618625
c0_lower = 0
619626
620627
i = 0
@@ -648,7 +655,7 @@ def plot_paths(pp, c0, k0, T_arr, k_ter=0, k_ss=None, axs=None):
648655
649656
if axs is None:
650657
fix, axs = plt.subplots(1, 3, figsize=(16, 4))
651-
ylabels = ['$c_t$', '$k_t$', '$\mu_t$']
658+
ylabels = ['$c_t$', '$k_t$', r'$\mu_t$']
652659
titles = ['Consumption', 'Capital', 'Lagrange Multiplier']
653660
654661
c_paths = []
@@ -801,6 +808,76 @@ A rule of thumb for the planner is
801808
The planner accomplishes this by adjusting the saving rate $\frac{f(K_t) - C_t}{f(K_t)}$
802809
over time.
803810
811+
```{exercise}
812+
:label: ck1_ex1
813+
814+
The turnpike property is independent of the initial condition
815+
$K_0$ provided that $T$ is sufficiently large.
816+
817+
Expand the `plot_paths` function so that it plots trajectories for multiple initial points using `k0s = [k_ss*2, k_ss*3, k_ss/3]`.
818+
```
819+
820+
```{solution-start} ck1_ex1
821+
:class: dropdown
822+
```
823+
824+
Here is one solution
825+
826+
```{code-cell} ipython3
827+
def plot_multiple_paths(pp, c0, k0s, T_arr, k_ter=0, k_ss=None, axs=None):
828+
if axs is None:
829+
fig, axs = plt.subplots(1, 3, figsize=(16, 4))
830+
831+
ylabels = ['$c_t$', '$k_t$', r'$\mu_t$']
832+
titles = ['Consumption', 'Capital', 'Lagrange Multiplier']
833+
834+
colors = plt.cm.viridis(np.linspace(0, 1, len(k0s)))
835+
836+
all_c_paths = []
837+
all_k_paths = []
838+
839+
for i, k0 in enumerate(k0s):
840+
k0_c_paths = []
841+
k0_k_paths = []
842+
843+
for T in T_arr:
844+
c_vec, k_vec = bisection(pp, c0, k0, T, k_ter=k_ter, verbose=False)
845+
k0_c_paths.append(c_vec)
846+
k0_k_paths.append(k_vec)
847+
848+
μ_vec = pp.u_prime(c_vec)
849+
paths = [c_vec, k_vec, μ_vec]
850+
851+
for j in range(3):
852+
axs[j].plot(paths[j], color=colors[i],
853+
label=f'$k_0 = {k0:.2f}$' if j == 0 and T == T_arr[0] else "", alpha=0.7)
854+
axs[j].set(xlabel='t', ylabel=ylabels[j], title=titles[j])
855+
856+
if k_ss is not None and i == 0 and T == T_arr[0]:
857+
axs[1].axhline(k_ss, c='k', ls='--', lw=1)
858+
859+
axs[1].axvline(T+1, c='k', ls='--', lw=1)
860+
axs[1].scatter(T+1, paths[1][-1], s=80, color=colors[i])
861+
862+
all_c_paths.append(k0_c_paths)
863+
all_k_paths.append(k0_k_paths)
864+
865+
# Add legend if multiple initial points
866+
if len(k0s) > 1:
867+
axs[0].legend()
868+
869+
return all_c_paths, all_k_paths
870+
```
871+
872+
```{code-cell} ipython3
873+
_ = plot_multiple_paths(pp, 0.3, [k_ss*2, k_ss*3, k_ss/3], [250, 150, 75, 50], k_ss=k_ss)
874+
```
875+
876+
We see that the turnpike property holds for various initial values of $K_0$.
877+
878+
```{solution-end}
879+
```
880+
804881
Let's calculate and plot the saving rate.
805882
806883
```{code-cell} ipython3
@@ -1075,15 +1152,15 @@ studied in {doc}`Cass-Koopmans Competitive Equilibrium <cass_koopmans_2>` is a f
10751152
### Exercise
10761153
10771154
```{exercise}
1078-
:label: ck1_ex1
1155+
:label: ck1_ex2
10791156
10801157
- Plot the optimal consumption, capital, and saving paths when the
10811158
initial capital level begins at 1.5 times the steady state level
10821159
as we shoot towards the steady state at $T=130$.
10831160
- Why does the saving rate respond as it does?
10841161
```
10851162
1086-
```{solution-start} ck1_ex1
1163+
```{solution-start} ck1_ex2
10871164
:class: dropdown
10881165
```
10891166

lectures/egm_policy_iter.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ We found time iteration to be significantly more accurate and efficient.
3535

3636
In this lecture, we'll look at a clever twist on time iteration called the **endogenous grid method** (EGM).
3737

38-
EGM is a numerical method for implementing policy iteration invented by [Chris Carroll](http://www.econ2.jhu.edu/people/ccarroll/).
38+
EGM is a numerical method for implementing policy iteration invented by [Chris Carroll](https://econ.jhu.edu/directory/christopher-carroll/).
3939

4040
The original reference is {cite}`Carroll2006`.
4141

lectures/ge_arrow.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,15 +964,15 @@ class RecurCompetitive:
964964
def price_risk_free_bond(self):
965965
"Give Q, compute price of one-period risk free bond"
966966
967-
PRF = np.sum(self.Q, 0)
967+
PRF = np.sum(self.Q, axis=1)
968968
self.PRF = PRF
969969
970970
return PRF
971971
972972
def risk_free_rate(self):
973973
"Given Q, compute one-period gross risk-free interest rate R"
974974
975-
R = np.sum(self.Q, 0)
975+
R = np.sum(self.Q, axis=1)
976976
R = np.reciprocal(R)
977977
self.R = R
978978

lectures/kalman_2.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,9 @@ def simulate_workers(worker, T, ax, mu_0=None, Sigma_0=None,
447447
A, C, G, R = worker.A, worker.C, worker.G, worker.R
448448
xhat_0, Σ_0 = worker.xhat_0, worker.Σ_0
449449
450-
if isinstance(mu_0, type(None)):
450+
if mu_0 is None:
451451
mu_0 = xhat_0
452-
if isinstance(Sigma_0, type(None)):
452+
if Sigma_0 is None:
453453
Sigma_0 = worker.Σ_0
454454
455455
ss = LinearStateSpace(A, C, G, np.sqrt(R),
@@ -471,12 +471,12 @@ def simulate_workers(worker, T, ax, mu_0=None, Sigma_0=None,
471471
kalman.update(y[i])
472472
x_hat, Σ = kalman.x_hat, kalman.Sigma
473473
Σ_t.append(Σ)
474-
[y_hat_t[i]] = worker.G @ x_hat
475-
[u_hat_t[i]] = x_hat[1]
474+
y_hat_t[i] = (worker.G @ x_hat).item()
475+
u_hat_t[i] = x_hat[1].item()
476476
477-
if diff == True:
477+
if diff :
478478
title = ('Difference between inferred and true work ethic over time'
479-
if title == None else title)
479+
if title is None else title)
480480
481481
ax.plot(u_hat_t - u_0, alpha=.5)
482482
ax.axhline(y=0, color='grey', linestyle='dashed')
@@ -485,10 +485,10 @@ def simulate_workers(worker, T, ax, mu_0=None, Sigma_0=None,
485485
ax.set_title(title)
486486
487487
else:
488-
label_line = (r'$E[u_t|y^{t-1}]$' if name == None
488+
label_line = (r'$E[u_t|y^{t-1}]$' if name is None
489489
else name)
490490
title = ('Inferred work ethic over time'
491-
if title == None else title)
491+
if title is None else title)
492492
493493
u_hat_plot = ax.plot(u_hat_t, label=label_line)
494494
ax.axhline(y=u_0, color=u_hat_plot[0].get_color(),
@@ -525,9 +525,7 @@ for i, (uhat_0, α, β) in enumerate(zip(uhat_0s, αs, βs)):
525525
simulate_workers(worker, T, ax,
526526
# By setting diff=False, it will give u_t
527527
diff=False, name=r'$u_{{{}, t}}$'.format(i))
528-
529-
ax.axhline(y=u_0, xmin=0, xmax=0, color='grey',
530-
linestyle='dashed', label=r'$u_{i, 0}$')
528+
531529
ax.legend(bbox_to_anchor=(1, 0.5))
532530
plt.show()
533531
```
@@ -554,8 +552,6 @@ for i, (uhat_0, α, β) in enumerate(zip(uhat_0s, αs, βs)):
554552
555553
# This controls the boundary of plots
556554
ax.set_ylim(ymin=-3, ymax=3)
557-
ax.axhline(y=u_0, xmin=0, xmax=0, color='grey',
558-
linestyle='dashed', label=r'$u_{i, 0}$')
559555
ax.legend(bbox_to_anchor=(1, 0.5))
560556
plt.show()
561557
```

lectures/mccall_model.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ class McCallModel:
404404
# Evaluate value for each state-action pair
405405
# Consider action = accept or reject the current offer
406406
accept = w[i] / (1 - β)
407-
reject = c + β * np.sum(v * q)
407+
reject = c + β * (v @ q)
408408
409409
return np.array([accept, reject])
410410
```
@@ -488,7 +488,7 @@ def compute_reservation_wage(mcm,
488488
489489
# == Now compute the reservation wage == #
490490
491-
return (1 - β) * (c + β * np.sum(v * q))
491+
return (1 - β) * (c + β * (v @ q))
492492
```
493493

494494
The next line computes the reservation wage at default parameters
@@ -622,13 +622,13 @@ def compute_reservation_wage_two(mcm,
622622
623623
# == First compute h == #
624624
625-
h = np.sum(w * q) / (1 - β)
625+
h = (w @ q) / (1 - β)
626626
i = 0
627627
error = tol + 1
628628
while i < max_iter and error > tol:
629629
630630
s = np.maximum(w / (1 - β), h)
631-
h_next = c + β * np.sum(s * q)
631+
h_next = c + β * (s @ q)
632632
633633
error = np.abs(h_next - h)
634634
i += 1

lectures/mccall_q.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class McCallModel:
171171
# Evaluate value for each state-action pair
172172
# Consider action = accept or reject the current offer
173173
accept = w[i] / (1 - β)
174-
reject = c + β * np.sum(v * q)
174+
reject = c + β * (v @ q)
175175
176176
return np.array([accept, reject])
177177

0 commit comments

Comments
 (0)