@@ -349,6 +349,14 @@ u_prime_inv = lambda c, γ: c**(-1/γ)
349349
350350### Solver
351351
352+ Here is the operator $K$ that transforms current guess $\sigma$ into next period
353+ guess $K\sigma$.
354+
355+ We understand $\sigma$ is an array of shape $(n_a, n_z)$, where $n_a$ and $n_z$
356+ are the respective grid sizes.
357+
358+ The value ` σ[i,j] ` corresponds to $\sigma(a'_ i, z_j)$.
359+
352360``` {code-cell} ipython3
353361def K(σ: jnp.ndarray, ifp: IFP) -> jnp.ndarray:
354362 """
@@ -358,33 +366,21 @@ def K(σ: jnp.ndarray, ifp: IFP) -> jnp.ndarray:
358366 This operator implements one iteration of the EGM algorithm to
359367 update the consumption policy function.
360368
361- Parameters
362- ----------
363- σ : jnp.ndarray, shape (n_a, n_z)
364- Current guess of consumption policy, σ[i, j] is consumption
365- when assets = asset_grid[i] and income state = z_grid[j]
366- ifp : IFP
367- Model parameters
368-
369- Returns
370- -------
371- σ_new : jnp.ndarray, shape (n_a, n_z)
372- Updated consumption policy
373-
374369 Algorithm
375370 ---------
376371 The EGM works backwards from next period:
377372 1. Given σ(a', z'), compute current consumption c that
378373 satisfies Euler equation
379- 2. Compute the endogenous current asset level a that leads
374+ 2. Compute the endogenous current asset level a^e that leads
380375 to (c, a')
381- 3. Interpolate back to exogenous grid to get σ_new(a, z)
376+ 3. Interpolate back to exogenous grid to get σ_new(a', z')
377+
382378 """
383379 R, β, γ, Π, z_grid, asset_grid = ifp
384380 n_a = len(asset_grid)
385381 n_z = len(z_grid)
386382
387- def compute_c_for_state (j):
383+ def compute_c_for_fixed_income_state (j):
388384 """
389385 Compute updated consumption policy for income state z_j.
390386
@@ -416,9 +412,9 @@ def K(σ: jnp.ndarray, ifp: IFP) -> jnp.ndarray:
416412
417413 return σ_new # Consumption over the asset grid given z[j]
418414
419- # Vectorize computation over all exogenous states using vmap
420- # Resulting shape is (n_z, n_a), so one row per income state
421- σ_new = jax.vmap(compute_c_for_state)( jnp.arange(n_z))
415+ # Compute consumption over all income states using vmap
416+ c_vmap = jax.vmap(compute_c_for_fixed_income_state)
417+ σ_new = c_vmap( jnp.arange(n_z)) # Shape (n_z, n_a), one row per income state
422418
423419 return σ_new.T # Transpose to get (n_a, n_z)
424420```
@@ -444,11 +440,9 @@ def solve_model(ifp: IFP,
444440 error = jnp.max(jnp.abs(σ_new - σ))
445441 return i + 1, σ_new, error
446442
447- # Initialize loop state
448443 initial_state = (0, σ_init, tol + 1)
449-
450- # Run the loop
451- i, σ, error = jax.lax.while_loop(condition, body, initial_state)
444+ final_loop_state = jax.lax.while_loop(condition, body, initial_state)
445+ i, σ, error = final_loop_state
452446
453447 return σ
454448```
@@ -475,6 +469,45 @@ ax.legend()
475469plt.show()
476470```
477471
472+ To begin to understand the long run asset levels held by households under the default parameters, let's look at the
473+ 45 degree diagram showing the law of motion for assets under the optimal consumption policy.
474+
475+ ``` {code-cell} ipython3
476+ ifp = create_ifp()
477+ R, β, γ, Π, z_grid, asset_grid = ifp
478+ σ_init = R * asset_grid[:, None] + y(z_grid)
479+ σ_star = solve_model(ifp, σ_init)
480+ a = asset_grid
481+
482+ fig, ax = plt.subplots()
483+ for z, lb in zip((0, 1), ('low income', 'high income')):
484+ ax.plot(a, R * (a - σ_star[:, z]) + y(z) , label=lb)
485+
486+ ax.plot(a, a, 'k--')
487+ ax.set(xlabel='current assets', ylabel='next period assets')
488+
489+ ax.legend()
490+ plt.show()
491+ ```
492+
493+ The unbroken lines show the update function for assets at each $z$, which is
494+
495+ $$
496+ a \mapsto R (a - \sigma^*(a, z)) + y(z)
497+ $$
498+
499+ The dashed line is the 45 degree line.
500+
501+ The figure suggests that the dynamics will be stable --- assets do not diverge
502+ even in the highest state.
503+
504+ In fact there is a unique stationary distribution of assets that we can calculate by simulation -- we examine this below.
505+
506+ * Can be proved via theorem 2 of {cite}` HopenhaynPrescott1992 ` .
507+ * It represents the long run dispersion of assets across households when households have idiosyncratic shocks.
508+
509+
510+
478511### A Sanity Check
479512
480513One way to check our results is to
@@ -524,11 +557,12 @@ This looks pretty good.
524557
525558Let's consider how the interest rate affects consumption.
526559
527- * Step ` r ` through ` np.linspace(0, 0.04 , 4) ` .
560+ * Step ` r ` through ` np.linspace(0, 0.016 , 4) ` .
528561* Other than ` r ` , hold all parameters at their default values.
529562* Plot consumption against assets for income shock fixed at the smallest value.
530563
531- Your figure should show that higher interest rates boost savings and suppress consumption.
564+ Your figure should show that, for this model, higher interest rates boost
565+ suppress consumption (because they encourage more savings).
532566
533567``` {exercise-end}
534568```
@@ -541,7 +575,7 @@ Here's one solution:
541575
542576``` {code-cell} ipython3
543577# With β=0.98, we need R*β < 1, so r < 0.0204
544- r_vals = np.linspace(0, 0.015 , 4)
578+ r_vals = np.linspace(0, 0.016 , 4)
545579
546580fig, ax = plt.subplots()
547581for r_val in r_vals:
@@ -564,56 +598,12 @@ plt.show()
564598:label: ifp_ex2
565599```
566600
567- Now let's consider the long run asset levels held by households under the
568- default parameters.
569-
570- The following figure is a 45 degree diagram showing the law of motion for assets when consumption is optimal
571-
572- ``` {code-cell} ipython3
573- ifp = create_ifp()
574- R, β, γ, Π, z_grid, asset_grid = ifp
575- σ_init = R * asset_grid[:, None] + y(z_grid)
576- σ_star = solve_model(ifp, σ_init)
577- a = asset_grid
578-
579- fig, ax = plt.subplots()
580- for z, lb in zip((0, 1), ('low income', 'high income')):
581- ax.plot(a, R * (a - σ_star[:, z]) + y(z) , label=lb)
582-
583- ax.plot(a, a, 'k--')
584- ax.set(xlabel='current assets', ylabel='next period assets')
585-
586- ax.legend()
587- plt.show()
588- ```
589-
590- The unbroken lines show the update function for assets at each $z$, which is
591-
592- $$
593- a \mapsto R (a - \sigma^*(a, z)) + y(z)
594- $$
595-
596- The dashed line is the 45 degree line.
597-
598- We can see from the figure that the dynamics will be stable --- assets do not
599- diverge even in the highest state.
600-
601- In fact there is a unique stationary distribution of assets that we can calculate by simulation
602-
603- * Can be proved via theorem 2 of {cite}` HopenhaynPrescott1992 ` .
604- * It represents the long run dispersion of assets across households when households have idiosyncratic shocks.
605-
606- Ergodicity is valid here, so stationary probabilities can be calculated by averaging over a single long time series.
607-
608- Hence to approximate the stationary distribution we can simulate a long time
609- series for assets and histogram it.
601+ Let's approximate the stationary distribution by simulation.
610602
611- Your task is to generate such a histogram.
603+ Run a large number of households forward for $T$ periods and then histogram the
604+ cross-sectional distribution of assets.
612605
613- * Use a single time series $\{ a_t\} $ of length 500,000.
614- * Given the length of this time series, the initial condition $(a_0,
615- z_0)$ will not matter.
616- * You might find it helpful to use the ` MarkovChain ` class from ` quantecon ` .
606+ Set ` num_households=50_000, T=500 ` .
617607
618608``` {exercise-end}
619609```
0 commit comments