Programmatic model writing
Programmatic model writing is a powerful tool to write complex models using concise code. More specifically, the @model and @parameters macros allow for the use of indexed variables and for-loops.
Model block
for loops for time indices
In practice this means that this is no longer needed:
Y_annual[0] = Y[0] + Y[-1] + Y[-2] + Y[-3]but instead this can be written:
Y_annual[0] = for lag in -3:0 Y[lag] endIn the background the package expands the for loop and adds up the elements for the different values of lag.
In case the elements should not be added up but multiplied this can be done:
R_annual[0] = for operator = :*, lag in -3:0 R[lag] endfor loops for variables / parameter specific indices
Another use-case are models with repetitive equations such as multi-sector or multi-country models.
For example, defining the production function for two countries (home country H and foreign country F) would look as follows without the use of programmatic features:
y_H[0] = A_H[0] * k_H[-1]^alpha_H
y_F[0] = A_F[0] * k_F[-1]^alpha_Fand this can be written more conveniently using loops:
for co in [H, F] y{co}[0] = A{co}[0] * k{co}[-1]^alpha{co} endNote that the package internally writes out the for loop and creates two equations; one each for country H and F. The variables and parameters are indexed using the curly braces {}. These can also be used outside loops. When using more than one index it is important to make sure the indices are in the right order.
Example model block
Putting these elements together the multi-country model equations of the Backus, Kehoe, and Kydland (1992) model can be written like this:
julia> using MacroModellingjulia> @model Backus_Kehoe_Kydland_1992 begin for co in [H, F] Y{co}[0] = ((LAMBDA{co}[0] * K{co}[-4]^theta{co} * N{co}[0]^(1 - theta{co}))^(-nu{co}) + sigma{co} * Z{co}[-1]^(-nu{co}))^(-1 / nu{co}) K{co}[0] = (1 - delta{co}) * K{co}[-1] + S{co}[0] X{co}[0] = for lag in (-4+1):0 phi{co} * S{co}[lag] end A{co}[0] = (1 - eta{co}) * A{co}[-1] + N{co}[0] L{co}[0] = 1 - alpha{co} * N{co}[0] - (1 - alpha{co}) * eta{co} * A{co}[-1] U{co}[0] = (C{co}[0]^mu{co} * L{co}[0]^(1 - mu{co}))^gamma{co} psi{co} * mu{co} / C{co}[0] * U{co}[0] = LGM[0] psi{co} * (1 - mu{co}) / L{co}[0] * U{co}[0] * (-alpha{co}) = - LGM[0] * (1 - theta{co}) / N{co}[0] * (LAMBDA{co}[0] * K{co}[-4]^theta{co} * N{co}[0]^(1 - theta{co}))^(-nu{co}) * Y{co}[0]^(1 + nu{co}) for lag in 0:(4-1) beta{co}^lag * LGM[lag]*phi{co} end + for lag in 1:4 -beta{co}^lag * LGM[lag] * phi{co} * (1 - delta{co}) end = beta{co}^4 * LGM[+4] * theta{co} / K{co}[0] * (LAMBDA{co}[+4] * K{co}[0]^theta{co} * N{co}[+4]^(1 - theta{co})) ^ (-nu{co}) * Y{co}[+4]^(1 + nu{co}) LGM[0] = beta{co} * LGM[+1] * (1 + sigma{co} * Z{co}[0]^(-nu{co} - 1) * Y{co}[+1]^(1 + nu{co})) NX{co}[0] = (Y{co}[0] - (C{co}[0] + X{co}[0] + Z{co}[0] - Z{co}[-1])) / Y{co}[0] end (LAMBDA{H}[0] - 1) = rho{H}{H} * (LAMBDA{H}[-1] - 1) + rho{H}{F} * (LAMBDA{F}[-1] - 1) + Z_E{H} * E{H}[x] (LAMBDA{F}[0] - 1) = rho{F}{F} * (LAMBDA{F}[-1] - 1) + rho{F}{H} * (LAMBDA{H}[-1] - 1) + Z_E{F} * E{F}[x] for co in [H,F] C{co}[0] + X{co}[0] + Z{co}[0] - Z{co}[-1] end = for co in [H,F] Y{co}[0] end endModel: Backus_Kehoe_Kydland_1992 Variables Total: 56 Auxiliary: 31 States: 20 Auxiliary: 10 Jumpers: 28 Auxiliary: 21 Shocks: 2 Parameters: 28
Parameter block
Having defined parameters and variables with indices in the model block parameter values can also be declared, including by means of calibration equations, in the parameter block.
In the above example the production function was defined for countries H and F. Implicitly there are two parameters alpha and their value can be defined individually by setting
alpha{H} = 0.3
alpha{F} = 0.3or jointly by writing
alpha = 0.3By not using the index, the package understands that there are two parameters with this name and different indices and will set both accordingly.
This logic also applies to calibration equations; for example:
y{H}[ss] = 1 | alpha{H}
y{F}[ss] = 1 | alpha{F}to find the value of alpha that corresponds to y being equal to 1 in the non-stochastic steady state. Alternatively indices can be omitted and the package understands that both indices are referred to:
y[ss] = 1 | alphaMaking use of the indices a level of y for country H with alpha for country H could also be targeted and the ratio of the two ys targeted with the alpha for country F:
y{H}[ss] = 1 | alpha{H}
y{H}[ss] / y{F}[ss] = y_ratio | alpha{F}
y_ratio = 0.9Example parameter block
Making use of this and continuing the example of the Backus, Kehoe and Kydland (1992) model the parameters can be defined as follows:
julia> @parameters Backus_Kehoe_Kydland_1992 begin K_ss = 11 K[ss] = K_ss | beta mu = 0.34 gamma = -1.0 alpha = 1 eta = 0.5 theta = 0.36 nu = 3 sigma = 0.01 delta = 0.025 phi = 1/4 psi = 0.5 Z_E = 0.00852 rho{H}{H} = 0.906 rho{F}{F} = rho{H}{H} rho{H}{F} = 0.088 rho{F}{H} = rho{H}{F} endRemove redundant variables in non-stochastic steady state problem: 0.321 seconds Set up non-stochastic steady state problem: 1.821 seconds Find non-stochastic steady state: 13.483 seconds Take symbolic derivatives up to first order: 0.95 seconds Model: Backus_Kehoe_Kydland_1992 Variables Total: 56 Auxiliary: 31 States: 20 Auxiliary: 10 Jumpers: 28 Auxiliary: 21 Shocks: 2 Parameters: 28 Calibration equations: 2