Implementation Details
This section describes important functions and implementation features in greater detail. If the user is interested only in running the default model and reproducing the estimation results, this section can be ignored. Additional documentation can also be found in function documentation or in-line.
This section focuses on what the code does and why. Docstrings and the code itself (including comments) provide detailed information regarding how these basic procedures are implemented.
The AbstractModel Type
The AbstractModel type provides a common interface for all model objects, which greatly facilitates the implementation of new model specifications. Any concrete subtype of AbstractModel can be passed to any function defined for AbstractModel, provided that the concrete type has the fields that the function expects to be available.
Model990 is one example of a concrete subtype of AbstractModel that implements a single specification of the New York Fed DSGE model. All model objects must have these fields so that the interface for AbstractModel objects works correctly. See Editing or Extending a Model for more detail.
DSGE.Model990 — Type.Model990{T} <: AbstractRepModel{T}The Model990 type defines the structure of the New York Fed DSGE model.
Fields
Parameters and Steady-States
parameters::Vector{AbstractParameter}: Vector of all time-invariant model parameters.steady_state::Vector{AbstractParameter}: Model steady-state values, computed as a function of elements ofparameters.keys::OrderedDict{Symbol,Int}: Maps human-readable names for all model parameters and steady-states to their indices inparametersandsteady_state.
Inputs to Measurement and Equilibrium Condition Equations
The following fields are dictionaries that map human-readable names to row and column indices in the matrix representations of of the measurement equation and equilibrium conditions.
endogenous_states::OrderedDict{Symbol,Int}: Maps each state to a column in the measurement and equilibrium condition matrices.exogenous_shocks::OrderedDict{Symbol,Int}: Maps each shock to a column in the measurement and equilibrium condition matrices.expected_shocks::OrderedDict{Symbol,Int}: Maps each expected shock to a column in the measurement and equilibrium condition matrices.equilibrium_conditions::OrderedDict{Symbol,Int}: Maps each equlibrium condition to a row in the model's equilibrium condition matrices.endogenous_states_augmented::OrderedDict{Symbol,Int}: Maps lagged states to their columns in the measurement and equilibrium condition equations. These are added aftergensyssolves the model.observables::OrderedDict{Symbol,Int}: Maps each observable to a row in the model's measurement equation matrices.pseudo_observables::OrderedDict{Symbol,Int}: Maps each pseudo-observable to a row in the model's pseudo-measurement equation matrices.
Model Specifications and Settings
spec::String: The model specification identifier, "m990", cached here for filepath computation.subspec::String: The model subspecification number, indicating that some parameters from the original model spec ("ss3") are initialized differently. Cached here for filepath computation.settings::Dict{Symbol,Setting}: Settings/flags that affect computation without changing the economic or mathematical setup of the model.test_settings::Dict{Symbol,Setting}: Settings/flags for testing mode
Other Fields
rng::MersenneTwister: Random number generator. Can be is seeded to ensure reproducibility in algorithms that involve randomness (such as Metropolis-Hastings).testing::Bool: Indicates whether the model is in testing mode. Iftrue, settings fromm.test_settingsare used in place of those inm.settings.observable_mappings::OrderedDict{Symbol,Observable}: A dictionary that stores data sources, series mnemonics, and transformations to/from model units. DSGE.jl will fetch data from the Federal Reserve Bank of St. Louis's FRED database; all other data must be downloaded by the user. Seeload_dataandObservablefor further details.pseudo_observable_mappings::OrderedDict{Symbol,PseudoObservable}: A dictionary that stores names and transformations to/from model units. SeePseudoObservablefor further details.
Defining Indices
The model's equilibrium conditions and observables are represented as fairly large matrices, and keeping track of which rows and columns correspond to which states, shocks, equations, etc. can be confusing. To improve clarity, we define several dictionaries that map variable names to indices in these matrices:
endogenous_states: Indices of endogenous model statesexogenous_shocks: Indices of exogenous shocksexpected_shocks: Indices of expectation shocksequilibrium_conditions: Indices of equilibrium condition equationsendogenous_states_augmented: Indices of model states, after model solution and system augmentationobservables: Indices of named observables
This approach has a number of advantages. Most importantly, it is robust to inadvertent typos or indexing errors. Since the actual index number doesn't matter to us, the user only needs to define the names of their equilibrium conditions, states, and other variables. Adding states is easy - we have only to add them to the appropriate list in the model constructor, and they will be assigned an index.
As an example, consider the model's equilibrium conditions. The canonical representation of the equilibrium conditions is
Γ0 s_t = Γ1 s_{t-1} + C + Ψ ε_t + Π η_twhere Γ0, Γ1, C, Ψ, and Π are matrices of coefficients for s_t (states at time t), s_{t-1} (lagged states), ε_t (exogenous shocks) and η_t (expectational shocks). Each row of these matrices corresponds to an equilibrium condition, which we define using a descriptive name (for example, we name the consumption Euler equation :euler). States (columns of Γ0 and Γ1), exogenous shocks (columns of Ψ), and expectational shocks (columns Π) also have names.
The AbstractParameter Type
The AbstractParameter type implements our notion of a model parameter: a time-invariant, unobserved value that has economic significance in the model's equilibrium conditions. We estimate the model to find the values of these parameters.
Though all parameters are time-invariant, each has different features. Some parameters are scaled for use in the model's equilibrium conditions and measurement equations. During optimization, parameters can be transformed from model space to the real line via one of three different transformations. These transformations are also defined as types, and require additional information for each parameter. Finally, steady-state parameters are not estimated directly, but are calculated as a function of other parameters.
These various requirements are nicely addressed using a parameterized type hierarchy.
AbstractParameter{T<:Number}: The common abstract supertype for all parameters.Parameter{T<:Number, U<:Transform}: The abstract supertype for parameters that are directly estimated.UnscaledParameter{T<:Number, U:<Transform}: Concrete type for parameters that do not need to be scaled for equilibrium conditions.ScaledParameter{T<:Number, U:<Transform}: Concrete type for parameters that are scaled for equilibrium conditions.
SteadyStateParameter{T<:Number}: Concrete type for steady-state parameters.
All Parameters have the fields defined in UnscaledParameter:
DSGE.UnscaledParameter — Type.UnscaledParameter{T<:Number,U<:Transform} <: Parameter{T,U}Time-invariant model parameter whose value is used as-is in the model's equilibrium conditions.
Fields
key::Symbol: Parameter name. For maximum clarity,keyshould conform to the guidelines established in the DSGE Style Guide.value::T: Parameter value. Initialized in model space (guaranteed to be betweenvaluebounds), but can be transformed between model space and the real line via calls totransform_to_real_lineand
transform_to_model_space.
valuebounds::Interval{T}: Bounds for the parameter's value in model space.transform_parameterization::Interval{T}: Parameters used to transformvaluebetween model space and the real line.transform::U: Transformation used to transformvaluebetween model space and real line.prior::NullablePrior: Prior distribution for parameter value.fixed::Bool: Indicates whether the parameter's value is fixed rather than estimated.description::String: A short description of the parameter's economic significance.tex_label::String: String for printing the parameter name to LaTeX.
ScaledParameters also have the following fields:
scaledvalue::T: Parameter value scaled for use ineqcond.jlscaling::Function: Function used to scale parameter value for use in equilibrium conditions.
Note: Though not strictly necessary, defining a scaling with the parameter object allows for much a much cleaner definition of the equilibrium conditions.
Because the values of SteadyStateParameters are directly computed as a function of ScaledParameters and UnscaledParameters, they only require 4 fields:
DSGE.SteadyStateParameter — Type.SteadyStateParameter{T} <: AbstractParameter{T}Steady-state model parameter whose value depends upon the value of other (non-steady-state) Parameters. SteadyStateParameters must be constructed and added to an instance of a model object m after all other model Parameters have been defined. Once added to m, SteadyStateParameters are stored in m.steady_state. Their values are calculated and set by steadystate!(m), rather than being estimated directly. SteadyStateParameters do not require transformations from the model space to the real line or scalings for use in equilibrium conditions.
Fields
key::Symbol: Parameter name. Should conform to the guidelines established in the DSGE Style Guide.value::T: The parameter's steady-state value.description::String: Short description of the parameter's economic significance.tex_label::String: String for printing parameter name to LaTeX.
The Observable and PseudoObservable Types
We similarly encapsulate information about observables and pseudo-observables (unobserved linear combinations of states, e.g. the output gap) into the Observable and PseudoObservable types. Each type has identifier fields key, name, and longname.
Most importantly, both Observables and PseudoObservables include the information needed for transformations to and from model units. For Observables, these are the input_series, fwd_transform, and rev_transform fields. "Forward transformations" are applied to transform the raw input data series specified in input_series to model units. The model is estimated and forecasted in model units, and then we apply "reverse transformations" to get human-readable units before computing means and bands or plotting. Pseudo-observables are not observed, so they do not have input_series or fwd_transforms, but they may however have rev_transforms.
As an example, the :obs_gdp Observable uses as input_series aggregate nominal GDP in levels, the GDP price index, and population in levels, all from FRED. These series are fwd_transformed to get quarter-over-quarter log growth rates of per-capita real GDP, which are the Observable's model units. The reverse transformation then converts :obs_gdp into annualized quarter-over-quarter percent changes of aggregate real GDP.
DSGE.Observable — Type.mutable struct ObservableFields
key::Symbolinput_series::Vector{Symbol}: vector of mnemonics, each in the form:MNEMONIC__SOURCE(e.g.:GDP__FRED). This vector is parsed to determine source (e.g. per-capita consumption gets population and consumption).fwd_transform::Function: Extracts appropriateinput_seriesfrom a DataFrame of levels, and transforms data to model units (for example, computes per-capita growth rates from levels).rev_transform::Function: Transforms a series from model units into observable units. May take kwargs.name::String: e.g. "Real GDP growth"longname::String: e.g. "Real GDP growth per capita"
DSGE.PseudoObservable — Type.mutable struct PseudoObservableFields
key::Symbolname::String: e.g. "Flexible Output Growth"longname::String: e.g. "Output that would prevail in a flexible-price economy"rev_transform::Function: Transforms a series from model units into observable units. May take kwargs.
Model Settings
The Setting type implements computational settings that affect how the code runs without affecting the mathematical definition of the model. These include flags (e.g. whether or not to recompute the Hessian), parameterization for the Metropolis-Hastings algorithm (e.g. number of times to draw from the posterior distribution), and the vintage of data being used (Setting is a parametric type - a Setting{T<:Any}, so Booleans, Numbers, and Strings can all be turned into Settings). They are stored centrally in the settings dictionary within the model object.
Why implement a Setting type when we could put their values directly into the source code or dictionary? The most obvious answer is that the parametric type allows us to implement a single interface for all Settings (Booleans, Strings, etc.), so that when we access a particular setting during the estimation and forecast steps, we don't have to think about the setting's type.
Settings play an important role in addition to providing useful abstraction. Estimating and forecasting the New York Fed DSGE model takes many hours of computation time and creates a lot of output files. It is useful to be able to compare model output from two different models whose settings differ slightly (for example, consider two identical models that use different vintages of data as input). A central feature of the Setting type is a mechanism that generates unique, meaningful filenames when code is executed with different settings. Specifically, when a setting takes on a non-default value, a user-defined setting code (along with the setting's value) are appended to all output files generated during execution.
The Setting{T<:Any} type is defined as follows:
DSGE.Setting — Type.Setting{T}The Setting type is an interface for computational settings that affect how the code runs without affecting the mathematical definition of the model. It also provides support for non-conflicting file names for output of 2 models that differ only in the values of their computational settings.
Fields
key::Symbol: Name of settingvalue::T: Value of settingprint::Bool: Indicates whether to append this setting's code and value to output file names. If true, output file names will include a suffix of the form_code1=val1_code2=val2etc. where codes are listed in alphabetical order.code::String: string of <=4 characters to print to output file suffixes whenprint=true.description::String: Short description of what the setting is used for.
To update the value of an existing function, the user has two options. First, the user may use the <= syntax as shown in the Running with Default Settings section. However, for this to work properly, it is essential that the setting's key field be exactly the same as that of an existing entry in m.settings. Otherwise, an additional entry will be added to m.settings and the old setting will be the one accessed from other all routines. A potentially safer, though clunkier, option is to use the update! method.
Type Interfaces
AbstractModel Interface
DSGE.update! — Function.update!(pvec::ParameterVector{T}, values::Vector{T}) where TUpdate all parameters in pvec that are not fixed with values. Length of values must equal length of pvec. Function optimized for speed.
update!(m::AbstractModel, values::Vector{T}) where T<:AbstractFloatUpdate m.parameters with values, recomputing the steady-state parameter values.
Arguments:
m: the model objectvalues: the new values to assign to non-steady-state parameters.
update!(a::Setting, b::Setting)Update a with the fields of b if:
- The
keyfield is updated ifa.key == b.key - The
printboolean andcodestring are overwritten ifa.printis false andb.printis true, ora.printis true,b.printis false, and b.code is non-empty. - The
descriptionfield is updated ifb.descriptionis nonempty
DSGE.transform_to_model_space! — Function.transform_to_model_space!(m::AbstractModel, values::Vector{T}) where T<:AbstractFloatTransforms values from the real line to the model space, and assigns values[i] to m.parameters[i].value for non-steady-state parameters. Recomputes the steady-state paramter values.
Arguments
m: the model objectvalues: the new values to assign to non-steady-state parameters.
DSGE.load_parameters_from_file — Function.load_parameters_from_file(m::AbstractModel,path::String)Returns a vector of parameters, read from a file, suitable for updating m.
DSGE.specify_mode! — Function.specify_mode!(m::AbstractModel, mode_file::String=""; verbose=:low)Updates the values of m.parameters with the values from mode_file. Sets reoptimize setting to false.
Usage: should be run before calling estimate(m), e.g.:
m = Model990()
specify_mode!(m, modefile)
estimate(m)DSGE.specify_hessian — Function.specify_hessian(m::AbstractModel, path::String=""; verbose=:low)Specify a Hessian matrix calculated at the posterior mode to use in the model estimation. If no path is provided, will attempt to detect location.
Parameter Interface
DSGE.parameter — Method.parameter(p::ScaledParameter{T,U}, newvalue::T) where {T<:Number,U<:Transform}Returns a ScaledParameter with value field equal to newvalue and scaledvalue field equal to p.scaling(newvalue). If p is a fixed parameter, it is returned unchanged.
DSGE.parameter — Method.parameter{T,U<:Transform}(key::Symbol, value::T, valuebounds = (value,value),
transform_parameterization = (value,value),
transform = Untransformed(), prior = NullablePrior();
fixed = true, scaling::Function = identity, description = "",
tex_label::String = "")By default, returns a fixed UnscaledParameter object with key key and value value. If scaling is given, a ScaledParameter object is returned.
DSGE.parameter — Method.parameter(p::UnscaledParameter{T,U}, newvalue::T) where {T<:Number,U<:Transform}Returns an UnscaledParameter with value field equal to newvalue. If p is a fixed parameter, it is returned unchanged.
DSGE.transform_to_model_space — Method.transform_to_model_space{T<:Number, U<:Transform}(p::Parameter{T,U}, x::T)Transforms x from the real line to lie between p.valuebounds without updating p.value. The transformations are defined as follows, where (a,b) = p.transform_parameterization and c a scalar (default=1):
- Untransformed:
x - SquareRoot:
(a+b)/2 + (b-a)/2 * c * x/sqrt(1 + c^2 * x^2) - Exponential:
a + exp(c*(x-b))
DSGE.transform_to_real_line — Method.transform_to_real_line(p::Parameter{T,U}, x::T = p.value) where {T<:Number, U<:Transform}Transforms p.value from model space (between p.valuebounds) to the real line, without updating p.value. The transformations are defined as follows, where (a,b) = p.transform_parameterization, c a scalar (default=1), and x = p.value:
- Untransformed: x
- SquareRoot: (1/c)*cx/sqrt(1 - cx^2), where cx = 2 * (x - (a+b)/2)/(b-a)
- Exponential: a + exp(c*(x-b))
DSGE.update! — Method.update!(pvec::ParameterVector{T}, values::Vector{T}) where TUpdate all parameters in pvec that are not fixed with values. Length of values must equal length of pvec. Function optimized for speed.
DSGE.update — Method.update(pvec::ParameterVector{T}, values::Vector{T}) where TReturns a copy of pvec where non-fixed parameter values are updated to values. pvec remains unchanged. Length of values must equal length of pvec.
We define the non-mutating version like this because we need the type stability of map!
Base.rand — Method.Distributions.rand(p::Vector{AbstractParameter{Float64}}, n::Int)Generate n draws from the priors of each parameter in p.This returns a matrix of size (length(p),n), where each column is a sample.
Base.rand — Method.Distributions.rand(p::Vector{AbstractParameter{Float64}})Generate a draw from the prior of each parameter in p.
Setting Interface
DSGE.get_setting — Method.get_setting(m::AbstractModel, setting::Symbol)Returns the value of the setting
DSGE.update! — Method.update!(a::Setting, b::Setting)Update a with the fields of b if:
- The
keyfield is updated ifa.key == b.key - The
printboolean andcodestring are overwritten ifa.printis false andb.printis true, ora.printis true,b.printis false, and b.code is non-empty. - The
descriptionfield is updated ifb.descriptionis nonempty
Base.:<= — Method.(<=)(m::AbstractModel, s::Setting)Syntax for adding a setting to a model/overwriting a setting via m <= Setting(...)