GCN Files#

Like the R package gEcon, gEconpy uses .GCN files to represent a DSGE model. A GCN file is divided into blocks, each of which represents an optimization problem. Here is one block from the example Real Business Cycle (RBC) model included in the package.

An Example Model#

Here is an example of a GCN file that represents a simple RBC model, found in the examples/GCN files directory:

block HOUSEHOLD
{
    definitions
    {
        u[] = C[] ^ (1 - sigma_C) / (1 - sigma_C) -
              L[] ^ (1 + sigma_L) / (1 + sigma_L);
    };

    controls
    {
        C[], L[], I[], K[];
    };

    objective
    {
        U[] = u[] + beta * E[][U[1]];
    };

    constraints
    {
        C[] + I[] = r[] * K[-1] + w[] * L[] : lambda[];
        K[] = (1 - delta) * K[-1] + I[] : q[];
    };

    calibration
    {
        # Fixed parameters
        beta  = 0.99;
        delta = 0.02;

        # Parameters to estimate
        sigma_C ~ N(loc=1.5, scale=0.1, lower=1.0) = 1.5;
        sigma_L ~ N(loc=2.0, scale=0.1, lower=1.0) = 2.0;
    };
};

block FIRM
{
    controls
    {
        K[-1], L[];
    };

    objective
    {
        TC[] = -(r[] * K[-1] + w[] * L[]);
    };

    constraints
    {
        Y[] = A[] * K[-1] ^ alpha * L[] ^ (1 - alpha) : mc[];
    };

    identities
    {
        # Perfect competition
        mc[] = 1;
    };

    calibration
    {
        alpha = 0.35;
    };
};

block TECHNOLOGY_SHOCKS
{
    identities
    {
        log(A[]) = rho_A * log(A[-1]) + epsilon_A[];
    };

    shocks
    {
        epsilon_A[];
    };

    calibration
    {
        rho_A = 0.95;
    };
};

The file is structured around the optimization problems of the agents in the model. In this case, there are two agents: households and firms. We also add a separate block for the exogenous technology process, to make it clear that it is not part of either agent. The model corresponds to the following equations:

\[\begin{split}\begin{align} \text{Household} & \\ & \max_{C_t, L_t, I_t, K_t} U_t = \sum_{t=0}^\infty \beta^t \left ( \frac{C_t^{1 - \sigma_C}}{1 - \sigma_C} - \frac{L_t^{1 + \sigma_L}}{1 + \sigma_L} \right ) \\ \text{Subject to} & \\ & C_t + I_t = r_t K_{t-1} + w_t L_t \\ & K_t = (1 - \delta) K_{t-1} + I_t \\ && \\ \text{Firm} & \\ & \min_{K_{t-1}, L_t} TC_t = r_t K_{t-1} + w_t L_t \\ \text{Subject to} & \\ & Y_t = A_t K_{t-1}^\alpha L_t^{1 - \alpha} \\ && \\ \text{Technology Shock} & \\ & A_t = \rho_A A_{t-1} + \epsilon_{A_t} \end{align}\end{split}\]

Explanation of GCN Syntax#

A .GCN file uses an easy-to-read syntax. Whitespace is not meaningful - lines are terminated with a “;”, so long equations can be split into multiple lines for readability. There are no reserved keywords* to avoid – feel free to write beta instead of betta!

Model variables are written with a name followed by square brackets, as in U[]. The square brackets give the time index the variable enters with. Following Dynare conventions, capital stock K[-1] enters with a lag, while all other variables enter in the present. Expectations are denoted by wrapping variables with E[], as in E[U[1]] for expected utility at t+1. So I lied, there are a couple reserved keywords (hence the asterisk). Finally, you can refer directly to steady-state values as K[ss].

Parameters are written exactly as variables, except they have no square brackets [].

Anatomy of a Block Blocks are divided into five components: definitions, controls, objective, constraints, identities, shocks, and, calibration. In this block, we see five of the seven. The blocks have the following functions:

Definitions#

definitions contains equations that are not stored in the model. Instead, they are immediately substituted into all equations within the same block. In this example, a definition is used for the instantaneous utility function. It will be immediately substituted into the Bellman equation written in the objective block. Importantly, variables defined in the definitions block will not be available in other blocks!

Here is the definiton block used in the RBC model above:

definitions
{
    u[] = C[] ^ (1 - sigma_C) / (1 - sigma_C) -
          L[] ^ (1 + sigma_L) / (1 + sigma_L);
};

This gives us a “helper” variable u[] that represents the single-period utility function. In this case, the agent’s utility is described using a CRRA utility function.

Controls#

controls are the variables under the agent’s control. The objective function represented by the block will be solved by forming a Lagrange function and taking derivatives with respect to the controls.

Here is the control block used in the RBC model above:

controls
{
    C[], L[], I[], K[];
};

This block means that the agent is free to choose consumption, labor, investment, and the next-period capital stock. In mathematical notation, these are the variables that appear under the \(\max\) operator in the agent’s utility function.

Objective#

The objective block contains only a single equation, and gives the function an agent will try to maximize over an infinite time horizon. In this case, the agent has a CRRA utility function.

In the above example, there are two examples of objectives. The household seeks to maximize utility. This is represented by the following block:

objective
{
    U[] = u[] + beta * E[][U[1]];
};

In the mathematical notation above, this was written with an infinite sum. These sums cannot be represented in the GCN file, so the user must first convert the sum to a recursive Bellman equation. Notice also that the variable u[], defined in the definitions block, is used here to shorten the expression.

The firm seeks to minimize total costs. This is represented by the following block:

objective
{
    TC[] = -(r[] * K[-1] + w[] * L[]);
};

In gEconpy, all objectives must be written as maximization problems. Since the firm is minimizing costs, the objective function is written with a minus sign.

Constraints#

constraints give the resource constraints that the agent’s maximization must respect. All constraints are given their own Lagrange multipliers.

In the above example, the household’s optimization is done subject to a budget constraint and a law of motion of capital. These are represented by the following block:

constraints
{
    C[] + I[] = r[] * K[-1] + w[] * L[] : lambda[];
    K[] = (1 - delta) * K[-1] + I[] : q[];
};

The firm’s minimization is done subject to a production technology, in this case Cobb-Douglas:

constraints
{
    Y[] = A[] * K[-1] ^ alpha * L[] ^ (1 - alpha) : mc[];
};

Identities#

identities are equations that are not part of an optimization problem, but that are a part of the model. Unlike equations defined in the definitions block, identities are saved in the model’s system of equations. Unlike equations in the constraints block, no Lagrange multipliers are assigned to identities.

The most important fact to know about identities that they are directly inserted into the model.

In the above example, there are two identity blocks. One is in the firm’s problem, and gives the perfect competition condition:

identities
{
    # Perfect competition
    mc[] = 1;
};

This implies that price is euqal to marginal cost, and that prices

Shocks#

shocks are exogenous variables that are not under the agent’s control. In this case, the exogenous technology process is given in the TECHNOLOGY_SHOCKS block.

shocks are where the user defines exogenous shocks, as in varexo in Dynare.

Calibration#

The calibration block where free parameters, calibrated parameters, and parameter prior distributions are defined.

Parameters#

All parameters must be given values. In general, there are three ways to assign a value: directly, by calibration, or by prior distribution.

Direct Assignment#

In the household block above, all parameters are given a value directly. In the HOUSEHOLD block above, the parameters beta and delta are given values directly in the calibration block, like this:

calibration
{
    # Fixed parameters
    beta  = 0.99;
    delta = 0.02;
};

Calibration Equations#

As an alternative to setting a parameter value directly, the user can declare a parameter to be calibrated. To do this, give a steady-state relationship that the parameter should be calibrated to ensure is true. The following GCN code block for the firm’s optimization problem shows how this is done:

calibration
{
    L[ss] / K[ss] = 0.36 -> alpha;
};

The alpha parameter is set so that in the steady state, the ratio of labor to capital is 0.36. On the back end, gEconpy will use an optimizer to find a value of alpha that satsifies the user’s condition. Note that calibrated parameters cannot have prior distributions!

Prior Distributions#

The user can also assign a prior distribution to a parameter. This is done by using the ~ operator. The following GCN code block for the household’s optimization problem shows how this is done:

calibration
{
    sigma_C ~ N(loc=1.5, scale=0.1, lower=1.0) = 1.5;
    sigma_L ~ N(loc=2.0, scale=0.1, lower=1.0) = 2.0;
};

In this case, the parameters sigma_C and sigma_L are given normal prior distributions with means of 1.5 and 2.0, respectively. The standard deviation of the prior distribution is 0.1, and the lower bound is 1.0. The user can also specify an upper bound by adding upper= to the prior distribution declaration.

After the distribution, the user can also assign a starting value of each parameter. This is done by adding an equals sign and the starting value after the prior distribution declaration. In the example above, the starting value of sigma_C is 1.5, and the starting value of sigma_L is 2.0. If the user does not specify a starting value, gEconpy will use the mean of the prior distribution as the starting value. This starting value is used for all non-estimation tasks, such as solving for the inital steady state or the initial perturbation solution.

Lagrange Multipliers and First Order Conditions#

To solve the model and find the first order conditions, gEconpy uses the Lagrange multiplier method. Take the household problem stated above:

\[\begin{split}\begin{align} & \max_{C_t, L_t, I_t, K_t} U_t = \sum_{t=0}^\infty \beta^t \left ( \frac{C_t^{1 - \sigma_C}}{1 - \sigma_C} - \frac{L_t^{1 + \sigma_L}}{1 + \sigma_L} \right ) \\ \text{Subject to} & \\ & C_t + I_t = r_t K_{t-1} + w_t L_t \\ & K_t = (1 - \delta) K_{t-1} + I_t \\ \end{align}\end{split}\]

This problem can be solved by forming the Lagrange function:

\[\mathcal{L} = \sum_{t=0}^\infty \beta^t \left ( \frac{C_t^{1 - \sigma_C}}{1 - \sigma_C} - \frac{L_t^{1 + \sigma_L}}{1 + \sigma_L} \right ) - \lambda_t (C_t + I_t - r_t K_{t-1} - w_t L_t) - q_t (K_t - (1 - \delta) K_{t-1} - I_t)\]

Then solving for the first order conditions with respect to the control variables:

\[\begin{split}\begin{align} & \frac{\partial \mathcal{L}}{\partial C_t} = 0 \Rightarrow C_t^{-\sigma_C} - \lambda_t = 0 \\ & \frac{\partial \mathcal{L}}{\partial L_t} = 0 \Rightarrow -L_t^{\sigma_L} + \lambda_t w_t = 0 \\ & \frac{\partial \mathcal{L}}{\partial I_t} = 0 \Rightarrow -\lambda_t + q_t = 0 \\ & \frac{\partial \mathcal{L}}{\partial K_t} = 0 \Rightarrow -q_t + \beta \mathbb{E} \left [ \lambda_{t+1} r_{t+1} + q_{t+1} (1 - \delta) \right ] = 0 \\ \end{align}\end{split}\]

As mentioned, all constraints will automatically have a Lagrange multiplier assigned to them. The user name these multipliers himself by putting a colon “:” after an equation, followed by the Lagrange multipler name. Looking at the household constraints block fom above:

constraints
{
    C[] + I[] = r[] * K[-1] + w[] * L[] : lambda[];
    K[] = (1 - delta) * K[-1] + I[] : q[];
};

The multiplier associated with the budget constraint has been given the name “lambda”, as is usual in the literature, while the law of motion of capital has been given the name q[]. If the user wanted, she could use these variables in further computations within the block, for example Q[] = q[] / lambda[], Tobin’s Q, could be added in the identities block.

Interally, first order conditions are solved by first making all substitutions from definitions, then forming the following Lagrangian function: L = objective.RHS - lm1 * (control_1.LHS - control_1.RHS) - lm2 * (control_2.LHS - control_2.RHS) ... - lm_k * (control_k.LHS - control_k.RHS)

Next, the derivative of this Lagrangian is taken with respect to all control variables and all lagrange multipliers. Derivaties are are computed “though time” using TimeAwareSymbols, an extension of a normal Sympy symbol. For a control variable x, the total derivative over time is built up as dL[]/dx[] + beta * dL[+1]/dx + beta * beta * dL[+2]/dx[] .... This unrolling terminates when dL[+n]/dx[] = 0.

The result of this unrolling and taking derivatives process are the first order conditions (FoC). All model FoCs, along with objectives, constraints, and identities, are saved into the system of equations that represents the model.