Computation of the steady state and dimensionality reduction
Most of the code of this section is in the submodule SteadyState
(src/SubModules/SteadyState/
), except for prepare_linearization()
, which is generated by the preprocessor and can be found in src/Preprocessor/generated_fcns/prepare_linearization_generated.jl
. The preprocessor uses the template stored as src/Preprocessor/template_fcns/prepare_linearization.jl
.
The model features uninsured income shocks $y$ (by assumption, all workers supply the same efficiency units of labor [BBL], so idiosyncratic productivity shocks translate to income shocks) and two assets, liquid assets (bonds) $m$ and illiquid assets (capital) $k$. Entrepreneurs (last income-state) receive no labor income, but firm profits, while workers additionally receive labor union profits.
The steady state equilibrium contains, aside from the capital stock, marginal value functions $V_m$ and $V_k$ on a three-dimensional grid $(m \times k \times y)$ and the ergodic joint distribution over these idiosyncratic states. We do dimensionality reduction [BL] by applying the Discrete Cosine Transformation to the marginal value functions and approximating the joint distribution with a copula and state-dependent marginals.
The main functions are call_find_steadystate()
and call_prepare_linearization()
, with compute_steadystate()
being a wrapper for both of them.
compute_steadystate
BASEforHANK.compute_steadystate
— Functioncompute_steadystate(m_par)
A wrapper for call_find_steadystate()
and call_prepare_linearization()
.
Arguments
m_par::ModelParameters
Returns
SteadyResults
, containing returns ofprepare_linearization()
Combines steady state computation and preparation of linearization in one function call. It has the same returns as call_prepare_linearization()
.
call_find_steadystate
BASEforHANK.call_find_steadystate
— Functioncall_find_steadystate(m_par)
Computes the steady state of the household problem and fills the SteadyStateStruct struct (without further steps of preparing the linearization).
Arguments
m_par::ModelParameters
Returns
SteadyStateStruct
, containing returns offind_steadystate()
BASEforHANK.SteadyState.find_steadystate
— Functionfind_steadystate(m_par)
Find the stationary equilibrium capital stock as well as the associated marginal value functions and the stationary distribution of idiosyncratic states.
This function solves for the market clearing capital stock in the Aiyagari model with idiosyncratic income risk. That is, it uses CustomBrent()
to find the root of the excess capital demand function, which is defined in Kdiff()
. It does so first on a coarse grid and then on the actual grid.
Arguments
m_par::ModelParameters
Returns
KSS
: Steady-state capital stockWbSS
,WkSS
: Marginal value functionsdistrSS::Array{Float64,3}
: Steady-state distribution of idiosyncratic states, computed byKsupply()
n_par::NumericalParameters
,m_par::ModelParameters
The function takes the parameter struct
ModelParameters
as input m_par
(see Parameters).
To find the stationary equilibrium, we proceed in roughly the following steps:
Instantiate the parameter
struct
NumericalParameters
asn_par
(see Parameters). Within the struct, we set the number of income states [nh
] and use theBASEforHANK.Tools.Tauchen()
method to obtain a grid and a transition matrix of income, given the autocorrelation of the income process [m_par.ρ_h
]. Then, include entrepreneurial state.Find equilibrium capital stock (by finding a root of
BASEforHANK.SteadyState.Kdiff()
), where the supply of capital by households is calculated inBASEforHANK.SteadyState.Ksupply()
.Ksupply()
uses the Endogenous Grid Method (seeBASEforHANK.SteadyState.EGM_policyupdate()
) to iteratively obtain optimal policies and marginal value functions. The supply of capital by households is then computed based on the eigenvector associated with the unit eigenvalue of the transition matrix that comes out of the households' policies.Root finding is performed using Brent's method where the customized algorithm generates initial guesses for value functions and distributions based on previous iterations in the root finding.
This procedure is performed twice: First for a coarse grid (specified in the function) and then for the user-specified grid up to the user-desired precision [n_par.ϵ
] (both defined in the Parameters).
call_prepare_linearization
BASEforHANK.call_prepare_linearization
— Functioncall_prepare_linearization(ss, m_par)
Prepares linearization and fills the SteadyResults struct.
Arguments
ss::SteadyStateStruct
: Output ofcall_find_steadystate()
m_par::ModelParameters
Returns
SteadyResults
, containing returns ofprepare_linearization()
BASEforHANK.PerturbationSolution.prepare_linearization
— Functionprepare_linearization(K, Wb, Wk, distr, n_par, m_par)
Given the stationary equilibrium of the household side, computed in find_steadystate()
, this function performs several steps:
- Step 1: compute the stationary equilibrium.
- Step 2: perform the dimensionality reduction of the marginal value functions as well as the distribution.
- Step 3: compute the aggregate steady state from
input_aggregate_steady_state.mod
. - Step 4: produce indexes to access the variables in the linearized model.
- Step 5: return the results.
Arguments
K::Float64
: steady-state capital stockWb::Array{Float64,3}
,Wk::Array{Float64,3}
: steady-state marginal value functionsdistr::Array{Float64,3}
: steady-state distribution of idiosyncratic statesn_par::NumericalParameters
,m_par::ModelParameters
Returns
XSS::Array{Float64,1}
,XSSaggr::Array{Float64,1}
: steady state vectors produced by@writeXSS()
indexes
,indexes_aggr
:struct
s for accessingXSS
,XSSaggr
by variable names, produced by@make_fn()
,@make_fnaggr()
compressionIndexes::Array{Array{Int,1},1}
: indexes for compressed marginal value functions (V_m
andV_k
)n_par::NumericalParameters
,m_par::ModelParameters
: updated parametersCDFSS
,CDF_bSS
,CDF_kSS
,CDF_hSS
: cumulative distribution functions (joint and marginals)distrSS::Array{Float64,3}
: steady state distribution of idiosyncratic states, computed byKsupply()
We first calculate other equilibrium quantities and produce distributional summary statistics (BASEforHANK.Tools.distrSummaries()
). Next, we reduce the dimensionality:
- Find the sparse representation of fluctuations of $V_m$ and $V_k$ around the steady state. For this purpose, calculate the derivatives of $V_m$ and $V_k$ with respect to all prices that enter the household problem. Then transform these derivatives using the Discrete Cosine Transformation (Julia-package
FFTW
) into polynomial coefficients. Calculate the average absolute value of those coefficients and retain those that explain a large share of the variance of coefficients (up to100*(1-n_par.reduc_marginal_value)
percent). Add, in the same way, polynomial coefficients that explain $V_m$ and $V_k$ themselves. The quality of the latter approximation is controlled byn_par.reduc_value
. The corresponding indices are saved incompressionIndexes
. This whole step is being done infirst_stage_reduction()
. - Prepare a node mesh on which the time-varying linear interpolant of the copula is defined. The grid in each $m$, $k$, and $y$ dimension is selected such that each resulting bin holds approximately the same share of the respective aggregate variable.
Lastly, we collect the steady-state values of all model variables in the vector XSS
(see BASEforHANK.Parsing.@writeXSS
). The state variables consist of the marginal distributions over $m$, $k$ and $y$ and the aggregate state variables (collected in state_names
). The control variables consist of the steady state marginal value functions (over the full grid) and the aggregate control variables (collected in control_names
; these vectors are defined in the main script BASEforHANK.jl
).
While the steady-state marginal value functions have full dimensionality, in the vectors that collect deviations from steady state (in BASEforHANK.PerturbationSolution.Fsys()
, those are X
and XPrime
) only the coefficients of the most important Chebyshev polynomials are saved. Additionally, the deviations of the marginal distributions are saved with one entry short of the grid size, since the marginals are restricted to sum up to 1. We manage this by creating the struct
indexes
(using BASEforHANK.Parsing.@make_fn
), that has two fields for each variable: steady state value and deviation.
We also construct the vector XSSaggr
and the struct
indexes_aggr
, which are similar to the above but only store (and manage) aggregate variables. This is useful for differentiating only with respect to aggregate variables in the estimation part (see BASEforHANK.PerturbationSolution.LinearSolution_reduced_system()
).
If you change the household decision model and hence need to customize the steady state solution, you will need to adjust the template Preprocessor/template_fcns/prepare_linearization.jl
and not Preprocessor/generated_fcns/prepare_linearization_generated.jl
which will be overwritten by the model parser based on Preprocessor/template_fcns/prepare_linearization.jl
. Note that the "definition" of the function (right click in VSCode) in the module is the generated one.
Parameters
The model parameters for the steady state have to be calibrated. We set them in the struct
ModelParameters
. It also contains all other parameters that are estimated, including the stochastic process-parameters for the aggregate shocks.
BASEforHANK.Parsing.ModelParameters
— TypeModelParameters()
A structure to collect all model parameters, including calibrated values and prior distributions for estimation.
Overview
- This struct is designed for macroeconomic models and includes parameters related to household preferences, income processes, technological factors, monetary policy, fiscal policy, and exogenous shocks.
- The parameters are annotated with metadata such as names (both ASCII and LaTeX), prior distributions, and a boolean flag indicating whether they are estimated.
- Uses the
Parameters
,FieldMetadata
, andFlatten
packages to facilitate parameter management.
Fields
Each field follows the structure:
parameter::T = value | "ascii_name" | L"latex_name" | prior_distribution | estimated
parameter
: Internal model parameter name.value
: Default numerical value.ascii_name
: Human-readable name used in output or logging.latex_name
: Corresponding LaTeX notation for use in reports and documentation.prior_distribution
: Prior distribution for Bayesian estimation (if applicable).estimated
: Boolean indicating whether the parameter is estimated.
The numerical parameters contain the grid (and the meshes) on which the stationary equilibrium is solved, discretization results of call_find_steadystate()
like the transition matrix of income and the joint distribution, and other parameters that determine the numerical approximation or solution technique, like reduc
or sol_algo
.
BASEforHANK.Parsing.NumericalParameters
— TypeNumericalParameters()
Collect parameters for the numerical solution of the model in a struct
.
In particular, nh
, nk
, and nb
control the resolution for the income, illiquid asset, and liquid asset grid. The resolution of the copula used in the linearization does not need to coincide with that grid and is controlled by nh_copula
, nk_copula
, and nb_copula
, respectively. Note, however, that the copula resolution should not exceed the actual grid size.
Find stationary equilibrium: functions
BASEforHANK.SteadyState.Kdiff
— FunctionKdiff(
KD,
n_par,
m_par,
initialize = true,
Wb_guess = zeros(1, 1, 1),
Wk_guess = zeros(1, 1, 1),
distr_guess = zeros(1, 1, 1)
)
This function is used to find the stationary equilibrium of the household block of the model, in particular, it is used in find_steadystate()
.
Calculate the difference between the capital stock that is demanded/assumed (KD) and the capital stock that prevails under that demanded capital stock's implied prices when households face idiosyncratic income risk (Aiyagari model).
Requires global functions from the IncomesETC module and Ksupply()
.
Arguments
KD::Float64
: Assumed capital demand (guess)n_par::NumericalParameters
,m_par::ModelParameters
initialize::Bool = true
: If true, initialize the marginal value functions and stationary distribution, otherwise use the provided guesses that follow. Providing the guesses can be used inCustomBrent()
to speed up the solution since the results from the previous iteration can be used as starting values.Wb_guess::AbstractArray = zeros(1, 1, 1)
: Guess for marginal value of liquid assetsWk_guess::AbstractArray = zeros(1, 1, 1)
: Guess for marginal value of illiquid assetsdistr_guess::AbstractArray = zeros(1, 1, 1)
: Guess for stationary distribution
Returns
diff::Float64
: Difference between the demanded and supplied capital stockWb::AbstractArray
: Marginal value of liquid assets, implied by capital demandWk::AbstractArray
: Marginal value of illiquid assets, implied by capital demanddistr::AbstractArray
: Stationary distribution of idiosyncratic states, implied by capital demand
BASEforHANK.SteadyState.Ksupply
— FunctionKsupply(
args_hh_prob,
n_par,
m_par,
Wb,
Wk,
distr_guess,
net_income,
eff_int,
)
Calculate the aggregate savings when households face idiosyncratic income risk by first solving the household problem using the endogenous grid method (EGM) and then finding the stationary distribution of idiosyncratic states.
Idiosyncratic state is tuple (b,k,y)
, where:
b
: liquid assets,k
: illiquid assets,y
: labor income.
This function is used in find_steadystate()
to find the stationary equilibrium, as an input to Kdiff()
, and in BASEforHANK.PerturbationSolution.prepare_linearization()
to prepare the linearization of the model.
Arguments
args_hh_prob
: Vector of arguments to the household problemRK_guess
: gross real interest rate illiquid assetsn_par
,m_par
Wb
,Wk
: guess for marginal value functionsdistr_guess
: guess for stationary distributionnet_income
: incomes, output of functions from the IncomesETC moduleeff_int
: effective interest rate, output of functions from the IncomesETC module
Returns
K
,B
: aggregate saving in illiquid (K
) and liquid (B
) assetsΓ
,Γ_a
,Γ_n
:sparse
transition matrices (average, with [a
] or without [n
] adjustment of illiquid asset)x_a_star
,b_a_star
,k_a_star
,x_n_star
,b_n_star
: optimal policies for consumption [c
], liquid [m
] and illiquid [k
] asset, with [a
] or without [n
] adjustment of illiquid assetWb
,Wk
: marginal value functionsdistr
: ergodic steady state ofΓ
BASEforHANK.SteadyState.EGM_policyupdate
— FunctionEGM_policyupdate(
EWbPrime::Array,
EWkPrime::Array,
args_hh_prob::Vector,
net_income::Array,
n_par,
m_par,
warnme::Bool,
model::Union{CompleteMarkets,OneAsset,TwoAsset},
)
Find optimal policies, given tomorrows marginal continuation values EWbPrime
, EWkPrime
, today's prices [args_hh_prob
], and income [net_income
], using the Endogenous Grid Method.
Optimal policies are defined over the exogenously fixed grid, while values of optimal policies (b
and k
) can have off-grid values. Please refer to the subsection with the title 'Update the optimal policy functions' of the document 'Computational Notes.md', for a detailed explanation of the function's code. The FOC's mentioned in the code are the Euler Equations as in the 'documentation of the household problem'.
Arguments
EWbPrime
,EWkPrime
: Marginal continuation values of liquid and illiquid assetsargs_hh_prob
: Vector of arguments to the household problemnet_income
: Incomes, output of functions from the IncomesETC modulen_par
,m_par
warnme
: Iftrue
, warns about non-monotonicity in resources or liquid asset choicesmodel
: Model type, eitherCompleteMarkets
,OneAsset
, orTwoAsset
Returns
x_a_star
,b_a_star
,k_a_star
,x_n_star
,b_n_star
: Optimal (on-grid) policies for the composite [x
], liquid [b
] and illiquid [k
] asset, with [a
] or without [n
] adjustment of illiquid asset
- BBLFor details, see the paper Shocks, Frictions, and Inequality in US Business Cycles, American Economic Review, forthcoming.
- BLFor details, see the paper Solving heterogeneous agent models in discrete time with many idiosyncratic states by perturbation methods, Quantitative Economics, Vol.11(4), November 2020, p. 1253-1288.