Getting Started: Krusell and Smith (1998)

The model describes a production economy with idiosyncratic uninsurable labor income risks faced by households. The aggregate shock is a shock to total factor productivity. The toolbox solves the steady state, and the deterministic linear/non-linear transition path after an unexpected aggregate shock. Following Boppart, Krusell and Mitman (2018) and Auclert et al. (2021), the deterministic transition path characterizes the first order effect of the aggregate shock.

We use the parameterization from Den Haan, Judd and Juillard (2010): Computational suite of models with heterogeneous agents: Incomplete markets and aggregate uncertainty. We also follow the notation in the paper.

HANS implements an optimization-based value function iteration approach to the individual problem. The current individual problem can also be solved by solving Euler equations with complementary slackness conditions (see the GDSGE example) or the endogenous grid method (see the implementation by the Sequence Space Jacobian toolbox).

The Model

Households are heterogeneous in their employment status \(e\in\{0,1\}\) and capital holding \(a \in R^+\). They solve the following Bellman equation:

\[\begin{split} v_t(e,a) = \max_{c,a'} \log(c)+ \beta\mathbb{E}[v_{t+1}(e',a')|e] \\s.t. \quad c+a' \leq (1+r_t)a + [(1-\tau)\overline{l}e + \mu(1-e)]w_t \\a'\geq 0, c \geq 0, \end{split}\]
(1)\[\]

where \(\bar{l}\) is the labor supply if being employed, \(\tau\) is the labor income tax rate, and \(\mu\) is the unemployment insurance payment rate. \(r_t\) and \(w_t\) are interest rate and wage rate, respectively. Households face a no-borrowing constraint \(a'\geq 0\).

Representative firms hire capital and labor and produce according to \(Y_t = Z_t K_t^{\alpha} L_t^{1-\alpha}\). Capital depreciates at rate \(\delta\). Interest and wage rates are competitively determined

\[\begin{split} r_t = \alpha Z_t K_t^{\alpha-1}L_t^{1-\alpha} - \delta \\ w_t = (1-\alpha)Z_tK_t^{\alpha}L_t^{-\alpha} \end{split}\]
(2)\[\]

Given an initial distribution over households’ states, \(\Phi_0\), a sequential competitive equilibrium is a sequence of (1) distribution over households’ states \(\{\Phi_t\}_{t=0}^{\infty}\), (2) households’ value and policy functions \(\{v_t,g_{c,t},g_{a',t}\}_{t=0}^{\infty}\), and (3) aggregate quantities and prices \(\{K_t, L_t, r_t, w_t\}_{t=0}^{\infty}\) such that

  • \(\{v_t,g_{c,t},g_{a',t}\}\) solve households’ decision problems defined by (1)

  • Market clearing: \(K_t=\int a \ \mathrm{d}\Phi_t(e,a)\), \(L_t=\int \bar{l} e \ \mathrm{d}\Phi_t(e,a)\). Goods market clearing implied by Walras’s law.

  • \(r_t\) and \(w_t\) are determined by (2).

  • Unemployment benefit is financed by labor income tax: \(w_t\int \bar{l} \tau e \ \mathrm{d}\Phi_t(e,a)=w_t\int (1-e)\mu \ \mathrm{d}\Phi_t(e,a)\).

  • \(\{\Phi_t\}\) are consistent with policy functions \(g_{a',t}\) and exogenous transitions of \(e\).

The Toolbox Script (hmod) File

The model can be represented using KS_JEDC10.hmod, listed below.

 1% The parameters are from from den Haan, Judd, Juillard, 2010, "Computational Suite of models with heterogeneous agents: 
 2% Incomplete markets and aggregate uncertainty" Journal of Economic Dynamics and Control, 34, pp 1 - 3.
 3parameters beta r w;
 4beta = 0.99;        % subjective discount factor
 5r = 0.009;          % asset return
 6w = 0.89;           % wage rate
 7labor = 1.0/0.9;    % exogenous labor supply when working
 8mu = 0.15;          % unemployment insurance replacement ratio
 9
10var_shock e;
11shock_trans = [0.600000, 0.400000;
12               0.044445, 0.955555];
13e = [0.00;1.00];
14shock_invariant_dist = [0.1;0.9];
15e_bar = shock_invariant_dist(:).'*e(:); 
16L = labor*e_bar;
17unemp_rate = shock_invariant_dist(1);  % unemployment rate 
18tau = mu*unemp_rate/L; % labor income tax rate
19
20var_state a;
21a = exp(linspace(log(0.25), log(200 + 0.25), 500)) - 0.25;
22
23var_pre_vfi budget;
24budget = (1+r)*a + w*((1.0-tau)*e*labor + mu*(1- e));
25
26% var_policy defines the choice variable
27var_policy ap;
28initial ap 0.0;
29% var_aux defines varaibles that can be simply evaluated
30var_aux c;
31
32vfi;
33    c = budget - ap;
34    u = log(c);
35    Tv = u + beta*EXPECT(v(ap));
36    ap <= budget;
37    ap >= 0.0;
38end;
39
40var_agg K;
41K = 43.0; % initial guess
42alpha = 0.36;   % capital share
43delta = 0.025;  % depreciation
44
45var_agg_shock Z;
46Z = 1.0; % steady state value
47
48model;
49    % Aggregate conditions stated like Dynare
50    r = alpha * Z * K(-1)^(alpha-1) * L^(1-alpha) - delta;
51    w = (1-alpha) * Z * K(-1)^alpha * L^(-alpha);
52    K == ap; % asset demand = asset supply
53    % Allow box constraints for aggregate variables
54    K >= 38.0;
55    % post evaluation
56    Y = Z*(K(-1)^alpha)*(L^(1-alpha));
57    I = K - (1 - delta)*K(-1);
58    C = Y - I;
59end;

The goal of the script file is to define a vfi block (Value Function Iteration) that defines the individual decision problem, and a model block that defines the aggregate equilibrium conditions.

Information required for solving the individual problem needs to be defined before the vfi block. Blocks defining the information are explained in order.

1% The parameters are from from den Haan, Judd, Juillard, 2010, "Computational Suite of models with heterogeneous agents: 
2% Incomplete markets and aggregate uncertainty" Journal of Economic Dynamics and Control, 34, pp 1 - 3.
3parameters beta r w;
4beta = 0.99;        % subjective discount factor
5r = 0.009;          % asset return
6w = 0.89;           % wage rate
7labor = 1.0/0.9;    % exogenous labor supply when working
8mu = 0.15;          % unemployment insurance replacement ratio

This block defines parameters that are used in the vfi block and their values.

10var_shock e;
11shock_trans = [0.600000, 0.400000;
12               0.044445, 0.955555];
13e = [0.00;1.00];
14shock_invariant_dist = [0.1;0.9];
15e_bar = shock_invariant_dist(:).'*e(:); 
16L = labor*e_bar;
17unemp_rate = shock_invariant_dist(1);  % unemployment rate 
18tau = mu*unemp_rate/L; % labor income tax rate

This block declares individual exogenous states in var_shock and specifies their values. They need to be defined as discrete Markov processes with joint transition matrix defined in shock_trans. Given the calibration of unemployment insurance payment \(\mu\), balanced-budget labor income tax rate \(\tau\) can be determined in advance.

20var_state a;
21a = exp(linspace(log(0.25), log(200 + 0.25), 500)) - 0.25;

This block declares individual endogenous states in var_state, and specifies the values of discretized grids over which the value and policy functions are approximated. For multi-dimension states, functions will be approximated over the tensor products of discretized state values.

23var_pre_vfi budget;
24budget = (1+r)*a + w*((1.0-tau)*e*labor + mu*(1- e));

This block defines variables that are simple functions of exogenous and/or endogenous states, which can be evaluated before solving the decision problem. Here, the budget is simply the sum of capital and labor income, evaluated at certain prices which are defined as parameters. This block is optional.

26% var_policy defines the choice variable
27var_policy ap;
28initial ap 0.0;

Variables that are to be optimized with (here, future capital holding \(a'\)) are declared as var_policy. Auxiliary variables (here, consumption \(c\)) that can be directly evaluated as simple functions of var_shock, var_state and/or var_policy are declared as var_aux.

With all information ready, the individual problem is defined in the vfi block enclosed by vfi; and end;.

32vfi;
33    c = budget - ap;
34    u = log(c);
35    Tv = u + beta*EXPECT(v(ap));
36    ap <= budget;
37    ap >= 0.0;
38end;

The vfi block starts from given values of var_state (here, \((e,a)\)) and var_policy (here, \(a'\)), to define an objective specified in Tv, in the line highlighted. As shown, this line has a natural syntax following the Bellman equation, where the future value function v is treated as known and called over future endogenous state values. The EXPECT operator is used to integrate over realizations of future exogenous states.

Box constraints for var_policy (here \(0 \leq a'\leq budget\)) and arbitrary equality or inequality constraints can be defined after the line that defines the objective.

All var_auxs (here, \(c\)) needs to be defined, and their values be accessed from the returned solution.

The script file can stop after defning the vfi block so the toolbox only generates code for solving the decision problem that is self-contained.

For solving the equilibrium, a system of equations for aggregate variables needs to be defined in the model block, with all required information defined before the block explained in order.

40var_agg K;
41K = 43.0; % initial guess
42alpha = 0.36;   % capital share
43delta = 0.025;  % depreciation

Unknowns of the equilibrium system needs to be declared as var_agg (here, \(K\)), with their initial values specified. Values of any parameters(here, \(\alpha,\delta\)) that are used in defining the aggregate system need to be specified.

45var_agg_shock Z;
46Z = 1.0; % steady state value

Aggregate shocks are declared as var_agg_shock. Aggregate shocks are essentially model parameters that are allowing to be time variant. Here is the aggregate TFP, \(Z\).

With all information ready, the aggregate equilibrium system is defined in

48model;
49    % Aggregate conditions stated like Dynare
50    r = alpha * Z * K(-1)^(alpha-1) * L^(1-alpha) - delta;
51    w = (1-alpha) * Z * K(-1)^alpha * L^(-alpha);
52    K == ap; % asset demand = asset supply
53    % Allow box constraints for aggregate variables
54    K >= 38.0;
55    % post evaluation
56    Y = Z*(K(-1)^alpha)*(L^(1-alpha));
57    I = K - (1 - delta)*K(-1);
58    C = Y - I;
59end;

The goal of the model block is to define the equation system that characterizes equilibrium conditions. Each equation is defined with “==”, as highlighted in the code block. Here, the system consists of a simple equation, asset market clearing, \(K_{t+1}=\int g_{a',t} d\Phi_t(e,a)\). var_policys can be used in the equation definition to represent the aggregates of individual policy functions integrated over the distribution at time \(t\), i.e., ap in the line represents \(\int g_{a',t} d\Phi_t(e,a)\) (recall \(ap\) is declared as one var_policy).

Before defining the system, intermediate variables, such as \(r,w\) are evaluated in order. Note that before defining the equation, parameters for solving individual decision problems need to be updated (here, \(r\), \(w\)) to respect the change in var_agg. For indexing time sequence of variables, the notation follows a convention of Dynare: the aggregate predetermined variables need to be indexed as lag variables (here, \(K(-1)\) that enters the evaluations of \(r\) and \(w\)).

Box constraints can be imposed for var_agg. Here \(K \geq 38\) is specfied so that \(r\) is bounded below to guarantee the convergence of value function iteration.

Other other aggregate equilibrium variables can be defined after the definition of equations (here, \(Y,I,C\) defined in the last three lines). The values of these variables will be returned after the system is solved.

Use the Toolbox

After parsing the script file, the toolbox generates MATLAB files: solve_vfi.m, solve_ss.m, solve_trans_linear.m, solve_trans_nonlinear.m and other functions that can be called to solve the steady state, stationary distribution, and transition paths of the model. The usages of these functions are illustrated below.

Parse .hmod Files

Parse .hmod Files

Suppose you have KS_JEDC10.hmod in the working directory. Call in MATLAB
clear_hans
hans KS_JEDC10
Parsing...ok! Compiling dpopt_vfi Building with 'MinGW64 Compiler (C++)'. MEX completed successfully.
ans = struct with fields:
parameters: {'beta' 'sigma' 'r' 'w'} var_shock: 'e' var_state: 'a' var_pre_vfi: 'budget' var_policy: 'ap' var_aux: 'c' var_agg: 'K' var_agg_shock: 'Z' var_agg_params: {'alpha' 'delta' 'L'} var_agg_assign: {'r' 'w'} var_agg_in_ind_params: {'r' 'w'} var_ind_in_eq: 'ap'
As shown, HANS parases the hmod file, compiles the mex files, and returns a structure that describes the model.
clear_hans in the first line clears any cached files generated before.

Solve the Stationary Equilibrium

Call the generated code solve_ss to solve the stationary equilibrium
tic;
ss_rslt = solve_ss;
Evaluating at var_agg: 43, VFI converged (metric_v) 0.00663442, (metric_pol) 0 in 489 iterations Range of a: 0, 18.9484 Equilbirium residual: 32.0071, Iteration Line Search Func-count ||f(x)||^2 fnorm(x) Norm of Step Step Size Algorithm 0 0 1 1.024452e+03 3.200706e+01 Evaluating at var_agg: 43.0043, VFI converged (metric_v) 0.000364795, (metric_pol) 0 in 290 iterations Range of a: 0, 18.9484 Equilbirium residual: 32.015, Evaluating at var_agg: 40.5, VFI converged (metric_v) 2.14285e-05, (metric_pol) 0 in 646 iterations Range of a: 0, 30.8489 Equilbirium residual: 26.1081, 1 1 3 6.816343e+02 2.610813e+01 2.500000e+00 1.437515e-01 Newton Evaluating at var_agg: 39.25, VFI converged (metric_v) 1.0435e-06, (metric_pol) 0 in 865 iterations Range of a: 0, 60.5201 Equilbirium residual: 20.2586, 2 1 4 4.104102e+02 2.025858e+01 1.250000e+00 1.129711e-01 Broyden Evaluating at var_agg: 38.625, VFI converged (metric_v) 1.17248e-07, (metric_pol) 0 in 991 iterations Range of a: 0, 128.441 Equilbirium residual: 13.1583, 3 1 5 1.731411e+02 1.315831e+01 6.250000e-01 1.443720e-01 Broyden Evaluating at var_agg: 38.3125, VFI converged (metric_v) 1.22019e-07, (metric_pol) 0 in 1034 iterations Range of a: 0, 200 Equilbirium residual: 2.91778, 4 1 6 8.513465e+00 2.917784e+00 3.125000e-01 2.698019e-01 Broyden Evaluating at var_agg: 38.2235, VFI converged (metric_v) 1.49177e-07, (metric_pol) 0 in 915 iterations Range of a: 0, 200 Equilbirium residual: -4.10224, 5 1 7 1.682838e+01 4.102240e+00 8.903913e-02 1.000000e+00 Broyden Evaluating at var_agg: 38.268, VFI converged (metric_v) 1.27167e-07, (metric_pol) 0 in 860 iterations Range of a: 0, 200 Equilbirium residual: -0.0836401, 5 2 8 6.995670e-03 8.364012e-02 4.451957e-02 5.000000e-01 Broyden Evaluating at var_agg: 38.2692, VFI converged (metric_v) 7.76193e-08, (metric_pol) 0 in 564 iterations Range of a: 0, 200 Equilbirium residual: 0.0116397, 6 1 9 1.354831e-04 1.163972e-02 1.240618e-03 1.000000e+00 Broyden Evaluating at var_agg: 38.2691, VFI converged (metric_v) 8.09795e-08, (metric_pol) 0 in 355 iterations Range of a: 0, 200 Equilbirium residual: 0.000535046, 7 1 10 2.862740e-07 5.350458e-04 1.515583e-04 1.000000e+00 Broyden Evaluating at var_agg: 38.2691, VFI converged (metric_v) 7.74544e-08, (metric_pol) 0 in 109 iterations Range of a: 0, 200 Equilbirium residual: 5.71076e-06, 8 1 11 3.261282e-11 5.710763e-06 7.302386e-06 1.000000e+00 Broyden Evaluating at var_agg: 38.2691, VFI result reused Range of a: 0, 200 Equilbirium residual: 5.71076e-06,
fprintf('Time used for solving the stationary equilibrium:\n');toc;
Time used for solving the stationary equilibrium: Elapsed time is 1.488543 seconds.
ss_rslt
ss_rslt = struct with fields:
vfi_rslt: [1×1 struct] stats: [1×1 struct] var_agg: [1×1 struct] dist: [2×500 double] parameters: [1×1 struct] var_agg_params: [1×1 struct] shock_trans: [2×2 double] shock_invariant_dist: [2×1 double] resid: 5.7108e-06 exit_flag: 1 rslt_type: 'ss' solver_output: [1×1 struct] ind_rslt_dict: [1×1 ArrayKeyMap]
As shown, the function returns a structure that describes the solved stationary equilibrium.
We can inspect the values of equilibrium variables:
ss_rslt.var_agg
ans = struct with fields:
K: 38.2691 Z: 1 r: 0.0099 w: 2.3769 Y: 3.7139 I: 0.9567 C: 2.7571
We can insepct the stationary distribution
plot(ss_rslt.vfi_rslt.var_state.a, ss_rslt.dist);
xlabel('k');
ylabel('fractions');
and the policy functions
plot(ss_rslt.vfi_rslt.var_state.a, ss_rslt.vfi_rslt.var_policy.ap);
xlabel('a');
title('Policy functions for ap');
legend({'low e','high e'})

Solve the Transition Path After A Temporay Shock

Solve the linearized transition path

We first construct the sequence of productivity shock.
T = 200;
shock_Z = 0.01; rho_Z = 0.9;
Z_t = 1 + shock_Z *rho_Z.^(0:(T-1));
figure;
plot(Z_t)
We then pass the productivity shock and the solved ss_rslt into solve_trans_linear to solve the linearized transition path.
options = struct;
options.T = T;
options.Z_t = Z_t;
tic;
trans_linear_rslt = solve_trans_linear(ss_rslt, options);
fprintf('Time used for solving the linearized transition path:\n');toc;
Time used for solving the linearized transition path: Elapsed time is 0.686213 seconds.
trans_linear_rslt
trans_linear_rslt = struct with fields:
var_agg_t: [1×1 struct] var_agg_shock_t: [1×1 struct] jacs_ind_wrt_agg: {[200×200 double] [200×200 double]} jac_eqs_of_var_agg: [200×200 double] irf_ssj: [200×200 double]
We can plot the transition path (note that K is the next period capital).
figure;
plot(trans_linear_rslt.var_agg_t.K)
title('K');
xlabel('time');

Solve the nonlinear transition path

Now we pass the solved ss_rslt to solve_nonlinear_trans(init_ss, final_ss, options) to solve the nonlinear transition path.
Note that we pass ss_rslt as both init_ss and final_ss.
tic;
trans_nonlinear_rslt = solve_trans_nonlinear(ss_rslt, ss_rslt, options);
Iteration Line Search Func-count ||f(x)||^2 fnorm(x) Norm of Step Step Size Algorithm 0 0 1 5.800552e-04 2.408433e-02 1 1 2 6.663947e-10 2.581462e-05 3.095308e-03 1.000000e+00 Broyden
fprintf('Time used for solving the nonlinear transition path:\n');toc;
Time used for solving the nonlinear transition path: Elapsed time is 1.229093 seconds.
trans_nonlinear_rslt
trans_nonlinear_rslt = struct with fields:
var_agg_t: [1×1 struct] var_agg_shock_t: [1×1 struct] T: 200 vfi_rslt: [1×1 struct] shock_trans: [2×2 double] exitflag: 1 HANS_x: [200×1 double] eqs_resid: [200×1 double] rslt_type: 'nonlinear_trans' solver_output: [1×1 struct]
We compare the solution of the nonlinear transition path and the linear transition path.
figure;
plot(trans_linear_rslt.var_agg_t.K);
hold on;
plot(trans_nonlinear_rslt.var_agg_t.K, '--');
xlabel('time');
title('K');
legend({'Linear','Nonlinear'});
We can also inspect other defined equilibrium varialbes along the transition path.
figure;
plot(trans_nonlinear_rslt.var_agg_t.w);
title('w');
xlabel('time');

Solve the Transition Path After A Permanent Shock

We now consider an unexpected shock that raises Z permanently by 100%.
We first sovle the new stationary equilibrium.
options = struct;
options.Z = 2.0;
ss_rslt_new = solve_ss(options);
Evaluating at var_agg: 43, VFI converged (metric_v) 0.0403421, (metric_pol) 0 in 413 iterations Range of a: 0, 200 Equilbirium residual: -160.841, Iteration Line Search Func-count ||f(x)||^2 fnorm(x) Norm of Step Step Size Algorithm 0 0 1 2.586975e+04 1.608408e+02 Evaluating at var_agg: 43.0043, VFI converged (metric_v) 0.00550782, (metric_pol) 0 in 199 iterations Range of a: 0, 200 Equilbirium residual: -160.836, Evaluating at var_agg: 195.495, VFI converged (metric_v) 0.0173235, (metric_pol) 0 in 251 iterations Range of a: 0, 25.1867 Equilbirium residual: 177.356, 1 1 3 3.145508e+04 1.773558e+02 1.524948e+02 1.000000e+00 Newton Evaluating at var_agg: 119.247, VFI converged (metric_v) 0.000418207, (metric_pol) 0 in 593 iterations Range of a: 0, 95.5869 Equilbirium residual: 75.8555, 1 2 4 5.754062e+03 7.585554e+01 7.624738e+01 5.000000e-01 Newton Evaluating at var_agg: 94.8119, VFI converged (metric_v) 9.83391e-07, (metric_pol) 0 in 1024 iterations Range of a: 0, 200 Equilbirium residual: -104.716, 2 1 5 1.096535e+04 1.047156e+02 2.443547e+01 1.000000e+00 Broyden Evaluating at var_agg: 107.03, VFI converged (metric_v) 9.58706e-08, (metric_pol) 0 in 1299 iterations Range of a: 0, 200 Equilbirium residual: -86.2799, 2 2 6 7.444222e+03 8.627991e+01 1.221774e+01 5.000000e-01 Broyden Evaluating at var_agg: 118.026, VFI converged (metric_v) 9.32533e-06, (metric_pol) 0 in 674 iterations Range of a: 0, 115.361 Equilbirium residual: 71.2133, 2 3 7 5.071333e+03 7.121329e+01 1.221774e+00 5.000000e-02 Broyden Evaluating at var_agg: 99.2833, VFI converged (metric_v) 9.8147e-08, (metric_pol) 0 in 1217 iterations Range of a: 0, 200 Equilbirium residual: -99.1582, 3 1 8 9.832350e+03 9.915820e+01 1.874234e+01 1.000000e+00 Broyden Evaluating at var_agg: 108.654, VFI converged (metric_v) 1.78346e-07, (metric_pol) 0 in 1192 iterations Range of a: 0, 200 Equilbirium residual: -81.0655, 3 2 9 6.571617e+03 8.106551e+01 9.371172e+00 5.000000e-01 Broyden Evaluating at var_agg: 117.088, VFI converged (metric_v) 5.73028e-06, (metric_pol) 0 in 713 iterations Range of a: 0, 137.358 Equilbirium residual: 66.8543, 3 3 10 4.469492e+03 6.685426e+01 9.371172e-01 5.000000e-02 Broyden Evaluating at var_agg: 102.716, VFI converged (metric_v) 1.82466e-07, (metric_pol) 0 in 1156 iterations Range of a: 0, 200 Equilbirium residual: -94.3721, 4 1 11 8.906088e+03 9.437207e+01 1.437252e+01 1.000000e+00 Broyden Evaluating at var_agg: 109.902, VFI converged (metric_v) 2.69193e-08, (metric_pol) 0 in 1337 iterations Range of a: 0, 200 Equilbirium residual: -73.9379, 4 2 12 5.466809e+03 7.393788e+01 7.186259e+00 5.000000e-01 Broyden Evaluating at var_agg: 116.37, VFI converged (metric_v) 4.568e-06, (metric_pol) 0 in 719 iterations Range of a: 0, 161.361 Equilbirium residual: 62.7817, 4 3 13 3.941536e+03 6.278166e+01 7.186259e-01 5.000000e-02 Broyden Evaluating at var_agg: 105.292, VFI converged (metric_v) 4.31381e-08, (metric_pol) 0 in 1283 iterations Range of a: 0, 200 Equilbirium residual: -90.0579, 5 1 14 8.110429e+03 9.005792e+01 1.107805e+01 1.000000e+00 Broyden Evaluating at var_agg: 110.831, VFI converged (metric_v) 4.6242e-08, (metric_pol) 0 in 1285 iterations Range of a: 0, 200 Equilbirium residual: -63.5917, 5 2 15 4.043907e+03 6.359172e+01 5.539026e+00 5.000000e-01 Broyden Evaluating at var_agg: 113.743, VFI converged (metric_v) 5.9994e-08, (metric_pol) 0 in 963 iterations Range of a: 0, 200 Equilbirium residual: 31.5864, 5 3 16 9.977013e+02 3.158641e+01 2.626473e+00 2.370880e-01 Broyden Evaluating at var_agg: 111.084, VFI converged (metric_v) 6.99602e-08, (metric_pol) 0 in 1145 iterations Range of a: 0, 200 Equilbirium residual: -59.2506, 6 1 17 3.510630e+03 5.925057e+01 2.659407e+00 1.000000e+00 Broyden Evaluating at var_agg: 112.414, VFI converged (metric_v) 4.37522e-08, (metric_pol) 0 in 1094 iterations Range of a: 0, 200 Equilbirium residual: -17.4686, 6 2 18 3.051521e+02 1.746860e+01 1.329704e+00 5.000000e-01 Broyden Evaluating at var_agg: 112.887, VFI converged (metric_v) 2.50023e-08, (metric_pol) 0 in 950 iterations Range of a: 0, 200 Equilbirium residual: 2.94162, 7 1 19 8.653100e+00 2.941615e+00 4.735105e-01 1.000000e+00 Broyden Evaluating at var_agg: 112.819, VFI converged (metric_v) 1.57584e-08, (metric_pol) 0 in 813 iterations Range of a: 0, 200 Equilbirium residual: 0.0719135, 8 1 20 5.171552e-03 7.191350e-02 6.824452e-02 1.000000e+00 Broyden Evaluating at var_agg: 112.817, VFI converged (metric_v) 1.43607e-08, (metric_pol) 0 in 488 iterations Range of a: 0, 200 Equilbirium residual: -0.000647376, 9 1 21 4.190962e-07 6.473764e-04 1.710179e-03 1.000000e+00 Broyden Evaluating at var_agg: 112.817, VFI converged (metric_v) 9.91224e-09, (metric_pol) 2.00672e-08 in 80 iterations Range of a: 0, 200 Equilbirium residual: -0.000487595, 10 1 22 2.377487e-07 4.875948e-04 1.525794e-05 1.000000e+00 Broyden Evaluating at var_agg: 112.817, VFI converged (metric_v) 9.96806e-09, (metric_pol) 1.00087e-08 in 203 iterations Range of a: 0, 200 Equilbirium residual: 0.00145568, 11 1 23 2.119016e-06 1.455684e-03 4.656163e-05 1.000000e+00 Broyden Evaluating at var_agg: 112.817, VFI converged (metric_v) 9.99162e-09, (metric_pol) 2.00287e-08 in 113 iterations Range of a: 0, 200 Equilbirium residual: 0.000980458, 11 2 24 9.612978e-07 9.804580e-04 2.328082e-05 5.000000e-01 Broyden Evaluating at var_agg: 112.817, VFI converged (metric_v) 9.94487e-09, (metric_pol) 2.00652e-08 in 146 iterations Range of a: 0, 200 Equilbirium residual: 9.24834e-05, 11 3 25 8.553178e-09 9.248339e-05 2.328082e-06 5.000000e-02 Broyden Evaluating at var_agg: 112.817, VFI result reused Range of a: 0, 200 Equilbirium residual: 9.24834e-05,
We then solve the transition path from the initial stationary equilibrium to the new stationary equilibrium.
options = struct;
T = 200;
options.Z_t = 2.0*ones(1,T); % shock hits at period 1
options.T = T;
tic;
trans_to_new_ss_rslt = solve_trans_nonlinear(ss_rslt, ss_rslt_new, options);
Iteration Line Search Func-count ||f(x)||^2 fnorm(x) Norm of Step Step Size Algorithm 0 0 1 5.361269e+05 7.322069e+02 1 1 2 1.831519e+04 1.353336e+02 2.746381e+02 1.000000e+00 Broyden 2 1 3 1.928935e+03 4.391964e+01 2.326839e+01 1.000000e+00 Broyden 3 1 4 1.277507e+00 1.130268e+00 4.819679e+00 1.000000e+00 Broyden 4 1 5 1.582870e-01 3.978530e-01 5.717419e-01 1.000000e+00 Broyden 5 1 6 1.003643e-04 1.001820e-02 1.033724e-01 1.000000e+00 Broyden 6 1 7 1.266697e-08 1.125476e-04 2.258355e-03 1.000000e+00 Broyden 7 1 8 3.681201e-11 6.067290e-06 5.298983e-05 1.000000e+00 Broyden
fprintf('Time for solving the nonlinear transition path after a permanent shock:\n');toc;
Time for solving the nonlinear transition path after a permanent shock: Elapsed time is 2.120954 seconds.
trans_to_new_ss_rslt
trans_to_new_ss_rslt = struct with fields:
var_agg_t: [1×1 struct] var_agg_shock_t: [1×1 struct] T: 200 vfi_rslt: [1×1 struct] shock_trans: [2×2 double] exitflag: 1 HANS_x: [200×1 double] eqs_resid: [200×1 double] rslt_type: 'nonlinear_trans' solver_output: [1×1 struct]
We next inspect the nonlinear transition path.
figure;
subplot(2,2,1);
plot(trans_to_new_ss_rslt.var_agg_t.K); title('K');
subplot(2,2,2);
plot(trans_to_new_ss_rslt.var_agg_t.C); title('C');
subplot(2,2,3);
plot(trans_to_new_ss_rslt.var_agg_t.w); title('w');
subplot(2,2,4);
plot(trans_to_new_ss_rslt.var_agg_t.r); title('r');

Simulate Individual Samples

Simulate Individual Samples at the Stationary Distribution

We can simulate individual samples at the stationary equilibrium or along the transition path.
Let's start with the stationary equilibrium.
tic;
simu_rslt = simulate_stochastic(ss_rslt);
period shock a ap cstate_transition_value_1 1000 1.896 37.87 37.86 2.753 37.86
fprintf('Time used for simulating individual samples at the stationary equilibrium:\n');toc;
Time used for simulating individual samples at the stationary equilibrium: Elapsed time is 0.807524 seconds.
simu_rslt
simu_rslt = struct with fields:
shock: [10000×1000 double] a: [10000×1000 double] ap: [10000×1000 double] c: [10000×1000 double] state_transition_value_1: [10000×1000 double]
As shown, passing ss_rslt to simulate_stochastic returns a panel of simualted individual samples.
Printed information is the mean of variables at the printed period.
By default, it simulates 10,000 samples for 1,000 periods, and starts from random state values drawn from the stationary distribution.
We can overwrite the num_samples and num_periods:
simu_options = struct;
simu_options.num_samples = 2e4;
simu_options.num_periods = 2e3;
tic;
simu_rslt = simulate_stochastic(ss_rslt, simu_options);
period shock a ap cstate_transition_value_1 1000 1.899 38.25 38.25 2.758 38.25 2000 1.895 37.82 37.81 2.752 37.81
fprintf('Time used for simulating 2e4 individual samples for 2e3 periods at the stationary equilibrium:\n');toc;
Time used for simulating 2e4 individual samples for 2e3 periods at the stationary equilibrium: Elapsed time is 2.490324 seconds.
We can compare the histogram of simulated individual samples to the one constructed based on the non-stochastic simulation.
figure;
subplot(1,2,1);
histogram(simu_rslt.a(:,end),ss_rslt.vfi_rslt.var_state.a,'Normalization','probability');
xlim([-10,210]);ylim([0,0.014]);
subplot(1,2,2);
plot(ss_rslt.vfi_rslt.var_state.a, sum(ss_rslt.dist,1)');
xlim([-10,210]);ylim([0,0.014]);

Simulate Individual Samples Along the Transition Path

To simulate individual samples along the transition path, we need to specify values of initial state values.
Let's specify them to be drawn from the stationary distribution.
simulate_initials = struct;
% Use the last period of the simulated results at the stationary distirubtion
simulate_initials.shock = simu_rslt.shock(:,end);
simulate_initials.a = simu_rslt.a(:,end);
We now pass the initial values into options, and simulate individual samples along the transition path to the new stationary equilibrium.
simu_options = struct;
simu_options.num_samples = 2e4; % to be consistent with size of initial values
simu_options.simulate_initials = simulate_initials;
simu_trans_rslt = simulate_stochastic(trans_to_new_ss_rslt, simu_options);
period shock a ap cstate_transition_value_1 0200 1.9 113.9 113.9 8.138 113.9
We then compare the aggregate variables constructed from individual samples and from non-stochastic simulations.
figure;
plot(trans_to_new_ss_rslt.var_agg_t.c,'-');
hold on;
plot(mean(simu_trans_rslt.c),'--');
legend({'Determinstic', 'Stochastic'},'Location','Best');
title('c');
xlabel('t');

What’s Next?

Behind the scene: understand the details of the Algorithm.

Check the Toolbox API reference.

More examples:

  • McKay, Nakamura and Steinsson (2016) for a Heterogeneous-Agent New-Keynesian model for defining complex equilibrium conditions and handling nonlinearity

  • A discrete-time two-asset HANK model for handling portfolio choices

  • Khan and Thomas (2008) for handling non-convex adjustment costs and stochastic state transitions