What counts as a replication
A replication here uses the paper's equations and calibration and compares the
result with a published number or a closed-form solution. Each block is executed by
tools/check_site_examples.py.
Dynare's teaching examples (Collard, Pfeifer) are in the validation table on the package page. They are tutorial files, and the comparison there is against Dynare's solution, variable by variable.
Heutel (2012), Review of Economic Dynamics
Garth Heutel, How should environmental policy respond to business cycles? Optimal policy
under persistent productivity shocks, Review of Economic Dynamics 15, 244–264,
10.1016/j.red.2011.05.002. The port is
in dsgelab.examples.heutel and in docs/heutel.md.
The solved system is the linear one in the author's MATLAB code, with the package's Klein/QZ in
the place of Anderson–Moore. The nonlinear model, which would allow second order and perfect
foresight, is not in this example.
Table 2 and the 1% impulse
Table 2, p. 251, gives α = 0.36, β = 0.98267, δ = 0.025, ρ = 0.95, σε = 0.007, η = 0.9979, θ₁ = 0.05607, θ₂ = 2.8 and 1 − γ = 0.696. The text on p. 250 prints β = 0.98627, and the example follows the table and the scripts. Section 4.1 simulates a 1% innovation and, in two consecutive sentences, describes consumption peaking around period 15 and capital peaking “around period 40 (year 6)”. In a quarterly model the sixth year corresponds to horizon 24. The solved series reaches its capital peak at horizon 25 and its consumption peak at 15. This system does not produce a peak at period 40, and the example does not shift the series to match it.
The scalar algebra of the port is translated from Heutel's MATLAB files, which carry no
licence, so the package does not distribute it. Running heutel.fetch() once downloads
the public copy from Georgia State University's repository, checks each file against the SHA-256
of the files the port was validated on, and writes the translation to a cache directory.
import numpy as np
from dsgelab.examples import heutel
heutel.fetch() # once per machine: download, check and translate Heutel's files
p = heutel.Params()
assert p.alpha == 0.36 and p.beta == 0.98267 and p.delta == 0.025
assert p.rho == 0.95 and p.sd == 0.007 and p.eta == 0.9979
assert p.theta1 == 0.05607 and p.theta2 == 2.8
assert abs((1 - p.gamma) - 0.696) < 1e-12
ss = heutel.steady_levels("tax", p)
assert abs(ss["lambda"]) < 1e-10 # Ramsey multiplier at the steady state
assert 0 < ss["mu"] < 1 and ss["c"] > 0 and ss["e"] > 0
sol = heutel.solve("tax", p)
irf = sol.irf("eps_a", size=0.01, periods=100, percent=False)
assert np.max(np.abs(irf["a"] - 0.01 * p.rho ** np.arange(100))) < 1e-12
gap = ss["c"]*irf["c"] + ss["i"]*irf["i"] + ss["z"]*irf["z"] - ss["y"]*irf["y"]
assert np.max(np.abs(gap)) < 1e-10 # resources along the impulse
assert int(np.argmax(irf["c"])) == 15
assert int(np.argmax(irf["k"])) == 25
print(ss["k"], ss["y"], ss["mu"], int(np.argmax(irf["k"])))
Lagged information, p. 262
When the government chooses the instrument before it observes the state, the paper replaces the first-order condition with τt = d · yt−1 and qt = d · yt−1. The paper publishes d = 1.415 for the tax and 0.658 for the quota, and the scripts have 1.4151 and 0.6580. Because lagged output is still at the steady state in the period of the shock, the instrument does not move in that period.
tax = heutel.Params.source("tax_asym")
quota = heutel.Params.source("quota_asym")
assert round(tax.policy_slope, 3) == 1.415
assert round(quota.policy_slope, 3) == 0.658
irf_tax = heutel.solve("tax_asym", tax).irf("eps_a", size=0.01, periods=100, percent=False)
assert abs(irf_tax["tau"][0]) < 1e-10
assert np.max(np.abs(irf_tax["tau"][1:] - tax.policy_slope * irf_tax["y"][:-1])) < 1e-10
irf_q = heutel.solve("quota_asym", quota).irf("eps_a", size=0.01, periods=100, percent=False)
assert abs(irf_q["q"][0]) < 1e-10
assert np.max(np.abs(irf_q["q"][1:] - quota.policy_slope * irf_q["y"][:-1])) < 1e-10
assert np.max(np.abs(irf_q["e"] - irf_q["q"])) < 1e-10
print(tax.policy_slope, quota.policy_slope)
The planner's literal calibration in the scripts, θ₂ = 0.1 and γ = 0.8, is
the sensitivity case of p. 258, and it does not produce an admissible steady state, so
heutel.solve("planner") raises heutel.SteadyStateError, which is
defined in dsgelab.examples.heutel and differs from dsgelab.SteadyStateError. For the Table 2
baseline, call heutel.solve("planner", heutel.Params()).
Stochastic growth with a closed-form solution
Brock and Mirman (1972, Journal of Economic Theory) set up optimal growth under uncertainty. With log utility and full depreciation the one-sector rule is exact, k′ = αβ a kα, and the log-linear solution is P = [[α, 1], [0, ρ]], F = [α, 1]. Long and Plosser (1983, Journal of Political Economy) wrote the multisector version, with the same utility and the same depreciation, and the example is the one-sector case.
For the process log a′ = ρ log a + ε, the second-order coefficient on technology, hσσ, equals σ², and the correction it adds to the rule, σ²/2, is the Jensen term that the approximation of Schmitt-Grohé and Uribe (2004, Journal of Economic Dynamics and Control) must return. Because capital follows the exact rule in every state, its coefficient is zero. The numerical tables of that paper belong to a different model.
import numpy as np
import dsgelab as dsg
from dsgelab.examples import rbc
model, params, guess = rbc.build()
sol = dsg.solve(model, params, guess=guess)
exact = rbc.closed_form(params)
assert np.allclose(sol.P, exact["P"]) and np.allclose(sol.F, exact["F"])
sigma = 0.007
so = dsg.solve_second_order(sol, cov={"eps_a": sigma})
i_a = model.states.index("a")
i_k = model.states.index("k")
assert abs(so.h_ss[i_a] - sigma ** 2) < 1e-8
assert abs(so.h_ss[i_k]) < 1e-8
print(sol.P, so.h_ss[i_a])
Taylor principle
Clarida, Galí and Gertler (2000, Quarterly Journal of Economics 115, 147–180) show that, under
a forward-looking interest-rate rule, a determinate equilibrium requires the response to expected
inflation to exceed one. The example uses a contemporaneous version of the rule,
i = φπ π + φx x, in the three-equation model with φπ = 1.5,
φx = 0.125 and β = 0.99, for which the equilibrium is determinate. With
φπ = 0.8 the same system is rejected with BlanchardKahnError. In this
version a positive φx puts the boundary slightly below 1, at about 0.9875, and 0.8
lies on the indeterminate side of it. The check is on this threshold, and the paper's table of
estimated coefficients is not reproduced.
from dataclasses import replace
import dsgelab as dsg
from dsgelab.examples import nk
model, params, guess = nk.build()
assert params.phi_pi == 1.5 and params.phi_x == 0.125 and params.beta == 0.99
sol_nk = dsg.solve(model, params, guess=guess)
assert sol_nk.klein.n_stable == model.n_states
below = replace(params, phi_pi=0.8)
try:
dsg.solve(model, below, guess=guess)
raised = False
except dsg.BlanchardKahnError:
raised = True
assert raised
print(sol_nk.klein.n_stable, raised)
Not on this page
| Paper | Why it is not here |
|---|---|
| Smets and Wouters (2007), American Economic Review | The package has the likelihood, the Kalman filter and Bayesian estimation, and the replication has not been done yet. |
| Schmitt-Grohé and Uribe (2003), small open economy | The model is not in the package yet. The 2004 paper appears on this page only through the σ² term of the lognormal AR(1). |