Implementation Details

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.Model990Type.
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 of parameters.

  • keys::OrderedDict{Symbol,Int}: Maps human-readable names for all model parameters and steady-states to their indices in parameters and steady_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 after gensys solves 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. If true, settings from m.test_settings are used in place of those in m.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. See load_data and Observable for further details.

  • pseudo_observable_mappings::OrderedDict{Symbol,PseudoObservable}: A dictionary that stores names and transformations to/from model units. See PseudoObservable for further details.

source

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:

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 + Π η_t

where Γ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.

All Parameters have the fields defined in UnscaledParameter:

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, key should conform to the guidelines established in the DSGE Style Guide.
  • value::T: Parameter value. Initialized in model space (guaranteed to be between valuebounds), but can be transformed between model space and the real line via calls to transform_to_real_line and

transform_to_model_space.

  • valuebounds::Interval{T}: Bounds for the parameter's value in model space.
  • transform_parameterization::Interval{T}: Parameters used to transform value between model space and the real line.
  • transform::U: Transformation used to transform value between 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.
source

ScaledParameters also have the following fields:

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:

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.
source

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.ObservableType.
mutable struct Observable

Fields

  • key::Symbol
  • input_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 appropriate input_series from 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"
source
mutable struct PseudoObservable

Fields

  • key::Symbol
  • name::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.
source

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.SettingType.
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 setting
  • value::T: Value of setting
  • print::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=val2 etc. where codes are listed in alphabetical order.
  • code::String: string of <=4 characters to print to output file suffixes when print=true.
  • description::String: Short description of what the setting is used for.
source

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 T

Update all parameters in pvec that are not fixed with values. Length of values must equal length of pvec. Function optimized for speed.

source
update!(m::AbstractModel, values::Vector{T}) where T<:AbstractFloat

Update m.parameters with values, recomputing the steady-state parameter values.

Arguments:

  • m: the model object
  • values: the new values to assign to non-steady-state parameters.
source
update!(a::Setting, b::Setting)

Update a with the fields of b if:

  • The key field is updated if a.key == b.key
  • The print boolean and code string are overwritten if a.print is false and b.print is true, or a.print is true, b.print is false, and b.code is non-empty.
  • The description field is updated if b.description is nonempty
source
transform_to_model_space!(m::AbstractModel, values::Vector{T}) where T<:AbstractFloat

Transforms 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 object
  • values: the new values to assign to non-steady-state parameters.
source
load_parameters_from_file(m::AbstractModel,path::String)

Returns a vector of parameters, read from a file, suitable for updating m.

source
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)
source
DSGE.specify_hessianFunction.
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.

source

Parameter Interface

DSGE.parameterMethod.
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.

source
DSGE.parameterMethod.
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.

source
DSGE.parameterMethod.
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.

source
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))
source
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))
source
DSGE.update!Method.
update!(pvec::ParameterVector{T}, values::Vector{T}) where T

Update all parameters in pvec that are not fixed with values. Length of values must equal length of pvec. Function optimized for speed.

source
DSGE.updateMethod.
update(pvec::ParameterVector{T}, values::Vector{T}) where T

Returns 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!

source
Base.randMethod.
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.

source
Base.randMethod.
Distributions.rand(p::Vector{AbstractParameter{Float64}})

Generate a draw from the prior of each parameter in p.

source

Setting Interface

DSGE.get_settingMethod.
get_setting(m::AbstractModel, setting::Symbol)

Returns the value of the setting

source
DSGE.update!Method.
update!(a::Setting, b::Setting)

Update a with the fields of b if:

  • The key field is updated if a.key == b.key
  • The print boolean and code string are overwritten if a.print is false and b.print is true, or a.print is true, b.print is false, and b.code is non-empty.
  • The description field is updated if b.description is nonempty
source
Base.:<=Method.
(<=)(m::AbstractModel, s::Setting)

Syntax for adding a setting to a model/overwriting a setting via m <= Setting(...)

source