@@ -210,47 +210,36 @@ This follows from the fact that the columns of $R$ sum to 1.
210210
211211Let's code up these equations.
212212
213- To do this we're going to use a class that we'll call ` LakeModel ` that stores the primitives $\alpha, \lambda, b, d$
213+ ### Model
214+
215+ To begin, we set up a class called ` LakeModel ` that stores the primitives $\alpha, \lambda, b, d$.
214216
215217``` {code-cell} ipython3
216218class LakeModel(NamedTuple):
217219 """
218220 Parameters for the lake model
219221 """
220- λ: float = 0.283
221- α: float = 0.013
222- b: float = 0.0124
223- d: float = 0.00822
224- A: jnp.ndarray = None
225- R: jnp.ndarray = None
226- g: float = None
227-
228-
229- def create_lake_model(λ: float = 0.283,
230- α: float = 0.013,
231- b: float = 0.0124,
232- d: float = 0.00822) -> LakeModel:
222+ λ: float
223+ α: float
224+ b: float
225+ d: float
226+ A: jnp.ndarray
227+ R: jnp.ndarray
228+ g: float
229+
230+
231+ def create_lake_model(
232+ λ: float = 0.283, # job finding rate
233+ α: float = 0.013, # separation rate
234+ b: float = 0.0124, # birth rate
235+ d: float = 0.00822 # death rate
236+ ) -> LakeModel:
233237 """
234238 Create a LakeModel instance with default parameters.
235239
236240 Computes and stores the transition matrices A and R,
237241 and the labor force growth rate g.
238242
239- Parameters
240- ----------
241- λ : float, optional
242- Job finding rate (default: 0.283)
243- α : float, optional
244- Job separation rate (default: 0.013)
245- b : float, optional
246- Entry rate into labor force (default: 0.0124)
247- d : float, optional
248- Exit rate from labor force (default: 0.00822)
249-
250- Returns
251- -------
252- LakeModel
253- A LakeModel instance with computed matrices A, R, and growth rate g
254243 """
255244 # Compute growth rate
256245 g = b - d
@@ -267,11 +256,33 @@ def create_lake_model(λ: float = 0.283,
267256 return LakeModel(λ=λ, α=α, b=b, d=d, A=A, R=R, g=g)
268257```
269258
259+ As an experiment, let's create two instances, one with $α=0.013$ and another with $α=0.03$
260+
261+ ``` {code-cell} ipython3
262+ model = create_lake_model()
263+ print(f"Default α: {model.α}")
264+ print(f"A matrix:\n{model.A}")
265+ print(f"R matrix:\n{model.R}")
266+ ```
267+
268+ ``` {code-cell} ipython3
269+ model_new = create_lake_model(α=0.03)
270+ print(f"New α: {model_new.α}")
271+ print(f"New A matrix:\n{model_new.A}")
272+ print(f"New R matrix:\n{model_new.R}")
273+ ```
274+
275+ ### Code for dynamics
276+
270277We will also use a specialized function to generate time series in an efficient
271278JAX-compatible manner.
272279
273- (Iteratively generating time series is somewhat nontrivial in JAX because arrays
274- are immutable.)
280+ Iteratively generating time series is somewhat nontrivial in JAX because arrays
281+ are immutable.
282+
283+ Here we use ` lax.scan ` , which allows the function to be jit-compiled.
284+
285+ Readers who prefer to skip the details can safely continue reading after the function definition.
275286
276287``` {code-cell} ipython3
277288@partial(jax.jit, static_argnames=['f', 'num_steps'])
@@ -307,7 +318,7 @@ def generate_path(f, initial_state, num_steps, **kwargs):
307318 return path.T
308319```
309320
310- Now we can simulate the dynamics .
321+ Here are functions to update $X_t$ and $x_t$ .
311322
312323``` {code-cell} ipython3
313324def stock_update(X: jnp.ndarray, model: LakeModel) -> jnp.ndarray:
@@ -321,26 +332,12 @@ def rate_update(x: jnp.ndarray, model: LakeModel) -> jnp.ndarray:
321332 return R @ x
322333```
323334
324- We create two instances, one with $α=0.013$ and another with $α=0.03$
325-
326- ``` {code-cell} ipython3
327- model = create_lake_model()
328- model_new = create_lake_model(α=0.03)
329-
330- print(f"Default α: {model.α}")
331- print(f"A matrix:\n{model.A}")
332- print(f"R matrix:\n{model.R}")
333- ```
334-
335- ``` {code-cell} ipython3
336- print(f"New α: {model_new.α}")
337- print(f"New A matrix:\n{model_new.A}")
338- print(f"New R matrix:\n{model_new.R}")
339- ```
340335
341336### Aggregate dynamics
342337
343- Let's run a simulation under the default parameters (see above) starting from $X_0 = (12, 138)$.
338+ Let's run a simulation under the default parameters starting from $X_0 = (12, 138)$.
339+
340+ We will plot the sequences $\{ E_t\} $, $\{ U_t\} $ and $\{ N_t\} $.
344341
345342``` {code-cell} ipython3
346343N_0 = 150 # Population
@@ -351,23 +348,26 @@ T = 50 # Simulation length
351348U_0 = u_0 * N_0
352349E_0 = e_0 * N_0
353350
354- fig, axes = plt.subplots(3, 1, figsize=(10, 8))
351+ # Generate X path
355352X_0 = jnp.array([U_0, E_0])
356353X_path = generate_path(stock_update, X_0, T, model=model)
357354
355+ # Plot
356+ fig, axes = plt.subplots(3, 1, figsize=(10, 8))
358357titles = ['unemployment', 'employment', 'labor force']
359358data = [X_path[0, :], X_path[1, :], X_path.sum(0)]
360-
361359for ax, title, series in zip(axes, titles, data):
362360 ax.plot(series, lw=2)
363361 ax.set_title(title)
364-
365362plt.tight_layout()
366363plt.show()
367364```
368365
369366The aggregates $E_t$ and $U_t$ don't converge because their sum $E_t + U_t$ grows at rate $g$.
370367
368+
369+ ### Rate dynamics
370+
371371On the other hand, the vector of employment and unemployment rates $x_t$ can be in a steady state $\bar x$ if
372372there exists an $\bar x$ such that
373373
0 commit comments