Skip to content

Commit 93e6735

Browse files
committed
Merge branch 'main' into gorman-updates
2 parents 472b2ac + 885ed67 commit 93e6735

4 files changed

Lines changed: 75 additions & 62 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ jobs:
88
steps:
99
- name: Checkout
1010
uses: actions/checkout@v5
11+
with:
12+
fetch-depth: 0
1113
- name: Setup Anaconda
1214
uses: conda-incubator/setup-miniconda@v3
1315
with:

.github/workflows/publish.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
steps:
1111
- name: Checkout
1212
uses: actions/checkout@v5
13+
with:
14+
fetch-depth: 0
1315
- name: Setup Anaconda
1416
uses: conda-incubator/setup-miniconda@v3
1517
with:

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ dependencies:
99
- jupyter-book>=1.0.4post1,<2.0
1010
- quantecon-book-theme==0.15.1
1111
- sphinx-tojupyter==0.6.0
12-
- sphinxext-rediraffe==0.2.7
12+
- sphinxext-rediraffe==0.3.0
1313
- sphinx-exercise==1.2.1
1414
- sphinx-proof==0.3.0
1515
- sphinxcontrib-youtube==1.4.1

lectures/gorman_heterogeneous_households.md

Lines changed: 70 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ kernelspec:
2525

2626
# Gorman Aggregation
2727

28-
{cite:t}`gorman1953community` described a class of preferences with the useful property that there exists a "representative household"
29-
in the sense that competitive equilibrium allocations can be computed by following a recursive procedure:
28+
## Overview
29+
30+
{cite:t}`gorman1953community` described a class of models with preferences having the useful property that there exists a "representative household" in the sense that competitive equilibrium allocations can be computed in the following way:
3031

3132
* take the heterogeneous preferences of a diverse collection of households and from them synthesize the preferences of a single hypothetical "representative household"
3233
* collect the endowments of all households and give them to the representative household
@@ -45,44 +46,30 @@ In general, computing a competitive equilibrium requires solving for the price s
4546
```
4647

4748

48-
49+
Chapter 12 of {cite:t}`HansenSargent2013` described how to adapt the preference specifications of {cite:t}`gorman1953community`
50+
to a linear-quadratic class of environments.
4951

5052

5153
This lecture uses the `quantecon.DLE` class to study economies that satisfy necessary conditions for Gorman
5254
aggregation of preferences.
5355

54-
Chapter 12 of {cite:t}`HansenSargent2013` described how to adapt the preference specifications of {cite:t}`gorman1953community`
55-
to the linear-quadratic class of environments assumed in their book.
56-
57-
The first step in implementing the above recursive algorithm will be to form a representative agent economy and then apply our DLE tools to compute its competitive equilibrium.
58-
59-
Thus, this lecture builds on tools and Python code described in {doc}`hs_recursive_models`, {doc}`growth_in_dles`, and {doc}`irfs_in_hall_model`.
60-
6156

6257

58+
To compute a competitive equilibrium, our first step will be to form a representative agent.
6359

6460

65-
In addition to what's in Anaconda, this lecture uses the `quantecon` library
66-
67-
```{code-cell} ipython3
68-
:tags: [hide-output]
61+
After that, we can use some of our DLE tools to compute competitive equilibrium
6962

70-
!pip install --upgrade quantecon
71-
```
63+
* prices without knowing the allocation of consumption to individual households
64+
* households' individual wealth levels
65+
* households' consumption levels
7266

73-
We make the following imports
67+
Thus, this lecture builds on tools and Python code described in {doc}`hs_recursive_models`, {doc}`growth_in_dles`, and {doc}`irfs_in_hall_model`.
7468

75-
```{code-cell} ipython3
76-
import numpy as np
77-
from scipy.linalg import solve_discrete_are
78-
from quantecon import DLE
79-
from quantecon import LQ
80-
import matplotlib.pyplot as plt
81-
```
69+
8270

83-
## Overview
8471

85-
When conditions for Gorman aggregation of preferences are satisfied, we can compute a competitive equilibrium of heterogeneous-household economy in two steps: solve a representative-agent linear-quadratic planning problem for aggregates, then recover household allocations via a sharing-formula that makes each household's consumption a household-specific constant share of aggregate consumption.
72+
In a little more detail, when conditions for Gorman aggregation of preferences are satisfied, we can compute a competitive equilibrium of a heterogeneous-household economy in two steps: solve a representative-agent linear-quadratic planning problem for aggregates, then recover household allocations via a sharing-formula that makes each household's consumption a household-specific constant share of aggregate consumption.
8673

8774
* a household's share parameter will depend on the implicit Pareto weight implied by the initial distribution of endowment.
8875

@@ -110,18 +97,39 @@ With the help of this powerful result, we proceed in two steps:
11097
2. Compute household-specific policies and the Gorman sharing rule.
11198

11299

113-
For the special case in Section 12.6 of {cite:t}`HansenSargent2013`, where preference shocks are inactive, we can also
100+
For a special case described in Section 12.6 of {cite:t}`HansenSargent2013`, where preference shocks are inactive, we can also
114101

115-
3. Implement the Arrow-Debreu allocation using only a mutual fund (aggregate stock) and a one-period bond.
102+
3. Implement the Arrow-Debreu allocation by allowing households to trade a risk-free one-period bond and a single mutual fund that owns all of the economy's physical capital.
116103

117-
We shall provide examples of these steps in economies with two and many households.
104+
We shall provide examples of these steps in economies with two and then with many households.
105+
106+
Before studying these things in the context of the DLE class, we'll first introduce Gorman aggregation in a static economy.
107+
108+
109+
110+
In addition to what's in Anaconda, this lecture uses the `quantecon` library
111+
112+
```{code-cell} ipython3
113+
:tags: [hide-output]
114+
115+
!pip install --upgrade quantecon
116+
```
117+
118+
We make the following imports
119+
120+
```{code-cell} ipython3
121+
import numpy as np
122+
from scipy.linalg import solve_discrete_are
123+
from quantecon import DLE
124+
from quantecon import LQ
125+
import matplotlib.pyplot as plt
126+
```
118127

119-
Before studying these things in the context of the DLE class, we first introduce Gorman aggregation in a static economy.
120128

121129
(static_gorman)=
122130
### Gorman aggregation in a static economy
123131

124-
To see where the sharing rule comes from, start with a static economy with $n$ goods, price vector $p$, and households $j = 1, \ldots, J$.
132+
To indicate where our competitive equilibrium sharing rule originates, we start with a static economy with $n$ goods, price vector $p$, and households $j = 1, \ldots, J$.
125133

126134
Let $c^a$ denote the aggregate amount of consumption to be allocated among households.
127135

@@ -425,7 +433,7 @@ All households observe the same aggregate information set $\{\mathcal{J}_t\}$; i
425433
426434
These restrictions enable Gorman aggregation by ensuring that household demands are affine in wealth.
427435
428-
This will allow us to solve for aggregate allocations and prices without knowing the distribution of wealth across households as we shall see in {ref}`sharing_rules`.
436+
This will allow us to solve for aggregate allocations and prices without knowing the distribution of wealth across households, as we shall see in {ref}`sharing_rules`.
429437
430438
### The representative agent problem
431439
@@ -440,11 +448,13 @@ $$ (eq:agg_preference_aggregates)
440448
441449
Aggregates are economy-wide totals: $c_t := \sum_j c_{jt}$, $b_t := \sum_j b_{jt}$, $d_t := \sum_j d_{jt}$, and similarly for $(i_t, k_t, h_t, s_t, g_t)$.
442450
443-
Under the Gorman/LQ restrictions, we can compute equilibrium prices and aggregate quantities by synthesizing a fictitious *representative agent* whose first-order conditions reproduce the competitive equilibrium conditions for aggregates.
451+
Under the Gorman/LQ restrictions, we can compute equilibrium prices and aggregate quantities by synthesizing a fictitious *representative agent* whose first-order conditions generate equations that determine correct equilibrium prices and a correct *aggregate* consumption allocation and aggregate capital process.
452+
453+
* these equations will not be sufficient to determine the allocation of aggregate consumption among individual households.
444454
445-
This representative problem is an aggregation device: it is chosen to deliver the correct *aggregate* allocation and prices.
455+
Posing a social planning problem for a representative agent is thus a device for computing the correct *aggregate* allocation along with correct competitive equilibrium prices.
446456
447-
The representative agent maximizes
457+
The social planner in our representative agent economy maximizes
448458
449459
$$
450460
-\frac{1}{2} \mathbb{E}_0 \sum_{t=0}^\infty \beta^t
@@ -909,7 +919,7 @@ def heter(
909919
910920
911921
912-
This section studies the special case from Section 12.6 of {cite:t}`HansenSargent2013` in which the Arrow-Debreu allocation can be implemented by opening competitive markets only in a mutual fund and a one-period bond.
922+
This section studies a special case from Section 12.6 of {cite:t}`HansenSargent2013` in which the Arrow-Debreu allocation can be implemented by opening competitive markets only in a mutual fund and a one-period bond.
913923
914924
* So in our setting, we don't literally require that markets in a complete set of contingent claims be present.
915925
@@ -995,7 +1005,7 @@ First, write the budget constraint.
9951005
9961006
Household $j$'s time-$t$ resources are its mutual fund dividend $\mu_j d_t$ plus the return on its bond position $R(\mu_j k_{t-1} + \hat{k}_{j,t-1})$.
9971007
998-
Its uses of funds are consumption $c_{jt}$ plus the new bond position $(\mu_j k_t + \hat{k}_{jt})$:
1008+
Its uses of funds are consumption $c_{jt}$ plus the new bond position $(\mu_j k_t + \hat{k}_{jt})$, so
9991009
10001010
$$
10011011
\underbrace{\mu_j d_t}_{\text{mutual fund dividend}} + \underbrace{R(\mu_j k_{t-1} + \hat{k}_{j,t-1})}_{\text{bond return}} = \underbrace{c_{jt}}_{\text{consumption}} + \underbrace{(\mu_j k_t + \hat{k}_{jt})}_{\text{new bonds}}
@@ -1244,7 +1254,8 @@ Using the `LQ` class, we solve the LQ problem and simulate paths for the full st
12441254
Finally, we call `compute_household_paths` to get household allocations and limited-markets portfolios along the simulated path
12451255
12461256
```{code-cell} ipython3
1247-
def solve_model(info, tech, pref, U_b_list, U_d_list, γ_1, Λ, z0, ts_length=2000):
1257+
def solve_model(info, tech, pref, U_b_list, U_d_list, γ_1, Λ,
1258+
z0, ts_length=2000, seed=1):
12481259
"""
12491260
Solve the representative-agent DLE problem and compute household paths.
12501261
"""
@@ -1259,7 +1270,8 @@ def solve_model(info, tech, pref, U_b_list, U_d_list, γ_1, Λ, z0, ts_length=20
12591270
# Solve LQ problem and simulate paths
12601271
lq = LQ(econ.Q, econ.R, econ.A, econ.B,
12611272
econ.C, N=econ.W, beta=econ.beta)
1262-
x_path, _, _ = lq.compute_sequence(x0_full, ts_length=ts_length)
1273+
x_path, _, _ = lq.compute_sequence(x0_full,
1274+
ts_length=ts_length, random_state=seed)
12631275
12641276
paths = compute_household_paths(
12651277
econ=econ,
@@ -1362,7 +1374,8 @@ ts_length = 2_000
13621374
# Solve LQ problem and simulate paths
13631375
lq = LQ(econ.Q, econ.R, econ.A, econ.B,
13641376
econ.C, N=econ.W, beta=econ.beta)
1365-
x_path, _, _ = lq.compute_sequence(x0, ts_length=ts_length)
1377+
x_path, _, _ = lq.compute_sequence(x0,
1378+
ts_length=ts_length, random_state=1)
13661379
13671380
paths = compute_household_paths(
13681381
econ=econ,
@@ -1385,10 +1398,12 @@ mystnb:
13851398
name: fig-gorman-consumption
13861399
---
13871400
T_plot = 250
1401+
t0 = 200
1402+
13881403
fig, ax = plt.subplots()
1389-
ax.plot(paths["c"][0, 5:T_plot], lw=2, label="aggregate")
1390-
ax.plot(paths["c_j"][0, 5:T_plot], lw=2, label="household 1")
1391-
ax.plot(paths["c_j"][1, 5:T_plot], lw=2, label="household 2")
1404+
ax.plot(paths["c"][0, t0:t0+T_plot], lw=2, label="aggregate")
1405+
ax.plot(paths["c_j"][0, t0:t0+T_plot], lw=2, label="household 1")
1406+
ax.plot(paths["c_j"][1, t0:t0+T_plot], lw=2, label="household 2")
13921407
ax.set_xlabel("time")
13931408
ax.set_ylabel("consumption")
13941409
ax.legend()
@@ -1401,13 +1416,13 @@ The next figure plots the limited-markets bond adjustment and confirms that the
14011416
---
14021417
mystnb:
14031418
figure:
1404-
caption: bond adjustment positions
1419+
caption: bond position adjustments
14051420
name: fig-gorman-bond-adjustment
14061421
---
14071422
fig, ax = plt.subplots()
1408-
ax.plot(paths["k_hat"][0, 5:T_plot], lw=2, label="household 1")
1409-
ax.plot(paths["k_hat"][1, 5:T_plot], lw=2, label="household 2")
1410-
ax.plot(paths["k_hat"][:, 5:T_plot].sum(axis=0), lw=2, label="sum")
1423+
ax.plot(paths["k_hat"][0, t0:t0+T_plot], lw=2, label="household 1")
1424+
ax.plot(paths["k_hat"][1, t0:t0+T_plot], lw=2, label="household 2")
1425+
ax.plot(paths["k_hat"][:, t0:t0+T_plot].sum(axis=0), lw=2, label="sum")
14111426
ax.axhline(0.0, color="k", lw=1, alpha=0.5)
14121427
ax.set_xlabel("time")
14131428
ax.set_ylabel("bond position")
@@ -1697,8 +1712,6 @@ b_bar = 5.0
16971712
γs_pref = np.zeros(N)
16981713
ρ_pref = 0.0
16991714
1700-
t0 = 200
1701-
17021715
A22, C2, Ub, Ud, Ub_list, Ud_list, x0 = build_gorman_extended(
17031716
n=N,
17041717
rho1=ρ1, rho2=ρ2, sigma_a=σ_a,
@@ -1755,9 +1768,7 @@ plt.show()
17551768
17561769
### Closed-loop state-space system
17571770
1758-
The DLE framework represents the economy as a linear state-space system.
1759-
1760-
After solving the optimal control problem and substituting the policy rule, we obtain a closed-loop system:
1771+
We can use our DLE tools first to solve the representative-household social planning problem and represent equilibrium quantities as a linear closed-loop state-space system that takes the usual Chapter 5 {cite:t}`HansenSargent2013` form
17611772
17621773
$$
17631774
x_{t+1} = A_0 x_t + C w_{t+1},
@@ -1774,7 +1785,7 @@ z_t
17741785
\end{bmatrix},
17751786
$$
17761787
1777-
with $h_{t-1}$ the household service stock, $k_{t-1}$ the capital stock, and $z_t$ the exogenous state (constant, aggregate endowment states, and idiosyncratic shock states).
1788+
with $h_{t-1}$ the aggregate household service stock, $k_{t-1}$ the aggregate capital stock, and $z_t$ the exogenous state (constant, aggregate endowment states, and idiosyncratic shock states).
17781789
17791790
Any equilibrium quantity is a linear function of the state.
17801791
@@ -1816,7 +1827,7 @@ n_k = np.atleast_2d(econ.thetak).shape[0]
18161827
n_endo = n_h + n_k # endogenous state dimension
18171828
```
18181829
1819-
With the state-space representation, we can compute impulse responses to show how shocks propagate through the economy.
1830+
With the state-space representation, we can compute impulse responses to show how shocks propagate.
18201831
18211832
To trace the impulse response to shock $j$, we set `shock_idx=j` which selects column $j$ of the loading matrix $C$.
18221833
@@ -1904,18 +1915,18 @@ fig, axes = plt.subplots(2, 1, figsize=(14, 8))
19041915
# Top panel: Aggregate endowment
19051916
axes[0].plot(time_idx, d_agg[:T_plot], linewidth=2.5, color='C0',
19061917
label='Aggregate endowment $d_t$')
1907-
axes[0].set_ylabel('Endowment')
19081918
axes[0].set_title('Aggregate Endowment')
1919+
axes[0].set_ylabel('endowment')
19091920
axes[0].legend()
19101921
19111922
# Also plot the mean across households
19121923
d_mean = d_households[:, :T_plot].mean(axis=0)
19131924
axes[1].plot(time_idx, d_mean, linewidth=2.5, color='black', linestyle='--',
19141925
label=f'Mean across {d_households.shape[0]} households', alpha=0.8)
19151926
1916-
axes[1].set_xlabel('Time (after burn-in)')
1917-
axes[1].set_ylabel('Endowment')
19181927
axes[1].set_title(f'Average of Individual Household Endowments')
1928+
axes[1].set_xlabel('time (after burn-in)')
1929+
axes[1].set_ylabel('endowment')
19191930
axes[1].legend(loc='upper right', ncol=2)
19201931
19211932
plt.tight_layout()
@@ -1927,12 +1938,10 @@ Indeed, the average of individual household endowments tracks the aggregate endo
19271938
19281939
## Redistributing by adjusting Pareto weights
19291940
1930-
This section analyzes Pareto-efficient tax-and-transfer schemes by simply taking competitive equilibrium allocations and then using
1931-
a set of nonnegative Pareto weights that sum to one.
1941+
This section analyzes Pareto-efficient tax-and-transfer schemes by starting with competitive equilibrium allocations and using a specific set of nonnegative Pareto weights that sum to one.
19321942
19331943
```{note}
1934-
There are various schemes that would deliver such efficient redistributions, but in terms of what interests us in this example,
1935-
they are all equivalent.
1944+
There are various tax-and-transfer schemes that would deliver such efficient redistributions, but in terms of what interests us in this example, they are all equivalent.
19361945
```
19371946
19381947
### Redistribution via Pareto weights

0 commit comments

Comments
 (0)