1.3. Zero-th order approximation: steady state and balanced-growth path

The most flexible way to approach the solving of the steady state and the balanced-growth path is through the writing of a separate steady-state file. (Setting the steady state inside the model file via @steady_state_model is also supported – see Model file language.)

1.3.1. Anatomy of a steady-state file

A steady-state file is a plain MATLAB function (name of your choice). Its signature:

[y, newp, retcode] = my_ssfile(m, y, p, d, id)

Args:

  • m – model object (not always needed).

  • y – endo_nbr x 1 vector of initial steady state (stationary models) or endo_nbr x 2 matrix of initial steady state and growth rate (non-stationary models).

  • p – parameter structure.

  • d – definitions.

  • id – locations of the variables to calculate.

Returns:

  • y – the updated steady-state vector (or vector + growth rate for non-stationary models).

  • newp – structure of updated parameters, if any (a steady state can pin parameters implied by SS conditions; these belong here, not as numerics in the params file).

  • retcode – 0 if no problems, non-zero otherwise.

Note

The steady-state file is regime-agnostic:

  • The same file is valid whether the model has many regimes or not.

  • The user does not need to know which regime is being computed.

  • It is in sync with the steady-state model.

RISE calls the function twice:

  1. First call with one argument (the model object only). Collects:

    • the list of variables for which the steady state is solved and the order in which the calculations will be returned;

    • the list of parameters whose value is computed in the steady state.

  2. Second call with all input arguments. The user returns the steady state and the steady-state-computed parameters.

A complete listing, for a simple non-stationary model:

function [y, newp, retcode] = simple_ssfile(m, y, p, d, id)

retcode = 0;

if nargin == 1
    % list of endogenous variables to be calculated and the
    % order in which they will appear
    y    = {'Y','Z','h'};
    newp = {};       % list of parameters computed during SS
else
    % steady states and new parameter values
    newp = struct();

    h = [1/3,    0];
    Z = [p.zss,  p.mu];
    Y = [Z(1)*h(1),  Z(2)];

    ys = [Y; Z; h];   % order matches the list above

    if any(isnan(ys(:)))
        retcode = 1;
    else
        y(id, :) = ys;
    end
end

end

1.3.2. Incomplete analytical solution

Sometimes the user’s program does not solve the steady state or the balanced-growth path completely. This can occur because the user can only calculate part of the steady state, or because RISE created auxiliary variables (notably the Lagrange multipliers under optimal policy).

While RISE knows how to handle its own auxiliary variables, it falls back to a numerical solve for the remaining variables given the partial steady state the user supplied.

1.3.3. Steady-state loops

Sometimes the user can compute the steady state conditional on the knowledge of a particular variable. For instance, in an optimal-policy problem where only monetary policy is missing, knowing steady-state inflation may pin every other endogenous variable (Lagrange multipliers excluded).

Write a steady-state file that takes the missing variables as given. RISE proposes values for those missing variables in the second argument of the steady-state file. The locations of the missing variables come from:

get(m, 'endo_list')

Set the option sstate_loop to true to inform RISE that only a subset of variables is unknown.

1.3.4. Facilitators

Several facilitators help the numerical solve and can be combined.

Equation simplification

The user provides both a dynamic equation and a steady-state companion (the #-companion form, see Model file language):

log(X{t}) = (1-rho)*log(xss) + rho*log(X{t-1}) + sig*E{t} #
    X{t} = xss;

log(Z{t}/Z{t-1}) = log(muz) + sigz*EZ{t} #
    Z{t} = muz*Z{t-1};

Declaring log and level variables

Besides the economic interpretation, taking log approximations restricts the search domain for log variables to \((0, +\infty)\), which prevents:

  • division by 0;

  • log of zero;

  • log of negative values.

Setting bounds on variables

RISE accepts user-defined bounds on the search space for the steady state and the growth rate of variables under a numerical solve.

1.3.5. Steady states of growing variables in the dynamic equations

On a balanced growth path the steady state of a growing variable is not a number but a path. When a dynamic equation refers to the steady state of the lead of a variable, stst(V{+1}) (also steady_state(V{+1})), and the variable grows, RISE reads it as an anchor that moves with the trend, not as the value of the path at the date of the expansion. In the coordinates of the dynamic equations (the log of a log variable) it is replaced by the reference that @cognitive_discount uses:

\[R_{V,t+1} = \mathrm{stst}(V_{t+1}) + \sum_Z b_{VZ}\,\big(Z_{t+1}-\mathrm{stst}(Z_{t+1})\big) + \sum_X b_{VX}\,\big(X_{t}-\mathrm{stst}(X_{t})\big)\]
  • \(Z\) are the exogenous stochastic trends RISE finds in the equations (an own equation with only its lags, parameters and shocks and a unit root, e.g. A = A{-1}*gz*exp(sig*E); or a level whose first difference is such a process), at their realized value;

  • \(X\) carry the other trend directions (a variable with a first-difference variable, e.g. the log price level p = p{-1} + pi, or a log variable whose steady state is written this way), at their previous value plus one period of trend growth;

  • the exponents \(b\) (parameters cdtrend_<V>_<carrier>) are the loadings of \(V\) on the trend directions, recomputed after every steady-state solve. A stationary variable has \(b=0\): its anchor is its steady state, as before.

For the log price level with p = p{-1} + pi and a target pis:

stst(p{+1}) + m*(p{+1} - stst(p{+1}))

is p + pis + m*(pi{+1} - pis): the anchor of p{t+1} is p{t} + pis. The expectation is p{t} + pis when m = 0 and p{t+1} when m = 1. With a unit-root technology A and a consumption C that grows like it, stst(C{+1}) is stst(C{+1})*A{+1}/stst(A{+1}), so a hand-written discounting stst(C{+1}) + mcd*(C{+1} - stst(C{+1})) keeps the balanced growth path an equilibrium for every mcd. Before this change the anchor was the fixed date-0 value and, for mcd < 1, the solution drifted away from the path without shocks.

Limits:

  • only leads, stst(V{+1}), are rewritten. stst(V) and the steady states of lags, of expressions and of exogenous variables stay the steady state at the expansion date;

  • models without any trend carrier (no unit-root exogenous process, no first-difference variable) are parsed exactly as written;

  • a growing variable that loads on a trend direction no carrier spans keeps the fixed anchor, with the warning rise:stst:fixedAnchor;

  • the steady-state model and files, the @epilogue and the planner objective are not touched. In an optimal-policy model the rewrite applies only when the expectations are formed before the first-order conditions (br_b4_opt_policy = true); otherwise the equations stay as written;

  • @cognitive_discount builds the same reference for the leads of the variables it tags: a steady state written by hand and one created by the discounting are treated once, alike.

1.3.6. Multiple regimes

The presence of multiple regimes does not add complexity for the steady-state computation. The steady state is computed either:

  • at the ergodic mean of the parameters (Foerster, Rubio-Ramirez, Waggoner and Zha, 2016); or

  • with a different vector of parameters per regime (Maih-Waggoner, 2018; Chang et al., 2021).