1.15. Template differentiation

Many large models are a few equations repeated many times: one copy per grid cell in a heterogeneous-agent model, one per country or sector in a multi-country or multi-sector model. Each copy is the same expression with its variables and parameters renamed. The construction option RISE finds these repeated expressions by itself, differentiate each one once, and evaluate each derivative for all its copies in one vectorized call. The derivatives are exactly those of the standard path; only the time and memory change.

1.15.1. It is on by default

Template differentiation is the default: the construction option template_diff is true. Nothing is to be annotated in the model file, and an equation with no repeated term is differentiated as it is. The standard path stays available:

m = dsge_model('mymodel.rs');                            % templates (default)
m = dsge_model('mymodel.rs', 'template_diff', false);    % standard path

It works at every order up to max_deriv_order, with or without regime switching (constant or time-varying transition probabilities), and in every solve_function_mode, including 'disk'.

At construction RISE prints one line saying what it found, for instance (a two-asset HANK model with 150 grid cells):

template_diff: 2413 equations, 33920 terms: 76 templates cover 33912 terms,
               7 equations keep a remainder; 1491 derivative rows

Read it as follows. The 2,413 equations were split into 33,920 additive terms that involve a variable. They are copies of 76 distinct expressions (the templates), which are differentiated once each. Seven equations contain terms that have no twin; those terms are differentiated the standard way. The derivatives are evaluated by 1,491 vectorized rows instead of one function per Jacobian entry (295,455 rows without the option).

1.15.2. What it recognizes

RISE looks at the final, expanded equations only, and groups terms that are the same expression up to a one-to-one renaming of variables and parameters. It does not know or care how the repetition was produced:

  • Heterogeneous-agent models. The expansion of @heterogeneity_axis models (see Heterogeneous agents (HANK)) writes one copy of each individual equation per cell. Those copies are templates, and so is every source term of the synthesized distribution law and every cell term of an @Agg sum.

  • Loop-generated models. Each @for body is a template and each iteration a renaming. Country-specific parameters (rho_@{i}) are renamed like variables, and each summand of a loop-generated sum becomes one term, so the \(N^2\) bilateral terms below form a single template:

    @for i in countries
      Z_@{i} = rho_@{i}*Z_@{i}{-1} + sig_@{i}*E_@{i}
    @for j in countries
        + kap_@{i}_@{j}*(K_@{j}{-1}/K_@{i}{-1} - 1)
    @end
      ;
    @end
    
  • Equations written out by hand. The same model typed copy by copy gets exactly the same templates as the loop version (this is locked by a unit test).

It is one mechanism for all three, and it is not specific to heterogeneous agents.

1.15.3. What breaks a template

Nothing can make the answer wrong: anything that is not provably a pure renaming is differentiated the standard way. Only the gain depends on how the model is written.

Situation

Effect

a different literal number in some copies (e.g. bin indicators)

one class of copies per value

two placeholders that coincide in some copy (an own-country term K_@{i}/K_@{i})

a separate class

a copy written differently from its siblings, with no twin

that term uses the standard path (its equation keeps a remainder)

a function that is not elementwise-safe, or a user (alien) function

that term uses the standard path

a comparison or logical operator at the top level of an equation

that equation is not split into terms

1.15.4. What it saves

Measured on one machine, separate MATLAB processes, first order unless stated. “Differentiation” is the symbolic-differentiation stage of dsge_model; “build” is the whole construction.

Model

Differentiation, off / on

Peak memory, off / on

Jacobian evaluation, off / on

Two-asset HANK, 54 cells (661 equations)

56 s / 3.3 s

–

1.14 s / 0.035 s

Two-asset HANK, 150 cells (2,413 equations)

655 s / 40 s

29.8 GB / 5.2 GB

– / 0.29 s

Two-asset HANK, 288 cells (5,197 equations)

out of memory / 31 s

– / 14.9 GB

– / 0.33 s

One-asset HANK, 80 cells (3,532 equations)

249 s / 11 s

5.1 GB / 2.1 GB

3.49 s / 0.038 s

One-asset HANK, 20 cells, order 2

1,937 s / 4.7 s

–

–

200 countries, bilateral spillovers (1,203 equations)

199 s / 3.2 s

13.7 GB / 2.2 GB

1.38 s / 0.006 s

Two things follow. First, the symbolic work no longer grows with the number of copies (the 54-, 150- and 288-cell HANK models have the same 76 or 77 templates). Second, the Jacobian is evaluated 30 to 230 times faster, and that evaluation happens at every solve, every likelihood evaluation and every MCMC draw.

With the option on, the construction of a very large model is dominated by parsing and the heterogeneity expansion, not by differentiation.

1.15.5. Guarantee

For each copy, the derivative is the template’s derivative with the same renaming applied; this holds exactly at every order, because a renaming that maps distinct symbols to distinct symbols never merges two partial derivatives, and derivatives across two copies are zero. Splitting an equation into its additive terms is exact as well. The only difference from the standard path is the order in which floating-point sums are formed: derivatives agree to rounding (relative differences of order \(10^{-16}\)), and solutions and impulse responses agree.

The unit tests models/dsge/template_diff (RISE-unit-tests) lock this on loop-generated and hand-written models, on HANK models, and on regime-switching HANK models with constant and time-varying transition probabilities, at orders 1 and 2, in explicit and disk mode.

1.15.6. Limits

  • The option is off by default.

  • It pays off when each template has many copies. On a small model the fixed cost per template can exceed the saving: on a regime-switching HANK model with a 2 x 2 grid (4 copies per template, 6 regimes) the templated derivatives take about twice as many rows as the standard ones, and the model builds more slowly with the option on. The derivatives are the same either way; switch the option on for models with tens of copies or more.

  • Only the dynamic model’s derivatives are templated; the steady-state (static) derivatives use the standard path.

  • It does not reduce parsing: on very large heterogeneous-agent models the parser and the expansion remain the dominant costs (see Very large models).

  • Terms with non-elementwise or user-defined (alien) functions are differentiated the standard way.

1.15.7. How it works

  1. Each equation is split into signed additive terms (a sign is distributed over a fully parenthesized sum; products are never expanded).

  2. Each term gets a structural key: its text with every variable and parameter replaced by a placeholder numbered by order of first appearance, plus which placeholders are differentiation variables. Terms with equal keys are the same expression up to a renaming.

  3. Each group with at least two members is written once with fresh symbols and differentiated once, all groups in a single call to the symbolic differentiator. The remaining terms are differentiated as usual.

  4. Each derivative is emitted as one vectorized row for all copies of its template: varying symbols are gathered into index vectors, operators become elementwise, and the row’s coordinates list every copy’s equation and variable. Entries of the same equation and variable coming from different terms are summed when the sparse Jacobian is assembled.