🇬🇧 English · 🇪🇸 Español
Non-Linear Transition Dynamics for HANK Models
puremacro.models.hank_sequence_space.solve_nonlinear_transition implements non-linear general equilibrium simulation for Heterogeneous-Agent New Keynesian (HANK) models in sequence space, following the pioneering framework of Auclert, Bardóczy, Rognlie, and Straub (2021, Econometrica).
While first-order sequence-space Jacobian methods (the "Fake News" algorithm) provide rapid solutions for marginal innovations, macroeconomic policy analysis frequently confronts large MIT shocks—such as emergency fiscal transfers, major monetary policy rate hikes, or sovereign spread spikes—where non-linear precautionary savings behaviors, asymmetric borrowing constraints, and non-linear Phillips curve dynamics render linear approximations inaccurate.
solve_nonlinear_transition computes the exact non-linear transition path of all aggregate and distributional variables in general equilibrium using a specialized Broyden Quasi-Newton method with Sherman-Morrison rank-1 inverse Jacobian updates.
1. Sequence-Space Equilibrium Framework
1.1 Non-Linear Sequence-Space Representation
Consider a simulation horizon \(t = 0, \dots, T-1\) with \(T\) sufficiently large such that the economy returns to its deterministic steady state by \(T\).
Let \(\mathbf{Z} = (Z_0, \dots, Z_{T-1})'\) denote a sequence of exogenous shocks (e.g., policy interest rate innovations or government spending paths) and \(\mathbf{U} = (U_0, \dots, U_{T-1})'\) denote the sequence of endogenous target variables (such as aggregate output deviations \(dY_t\)).
General equilibrium is characterized by a system of \(T\) non-linear market-clearing conditions:
In canonical one-asset HANK models, the goods market clearing condition at each date \(t\) is:
where aggregate consumption \(C_t\) is obtained by non-linearly integrating over the time-varying distribution of heterogeneous households: $\(C_t = \int c_t(a, s) \, dD_t(a, s)\)$
The household block is solved non-linearly over the transition horizon: 1. Backward Policy Function Iteration: Individual consumption and saving policies \(c_t(a, s)\) and \(a_t(a, s)\) are solved backwards from steady state at \(t = T\) to \(t = 0\) using the Endogenous Grid Method (EGM). 2. Forward Distribution Simulation: The joint wealth-income distribution \(D_t(a, s)\) is pushed forward from \(D_0 = D_{ss}\) using the time-varying Markov transition matrices generated by the policy rules.
1.2 The Sequence-Space Broyden Solver
Solving \(\mathbf{H}(\mathbf{U}, \mathbf{Z}) = \mathbf{0}\) directly via full Newton-Raphson requires recomputing the \(T \times T\) household Jacobian matrix at every iteration, which is computationally prohibitive.
Instead, Auclert et al. (2021) deploy Broyden's Quasi-Newton method with Sherman-Morrison rank-1 updates:
- Initialization:
The initial inverse Jacobian \(B_0 \approx J_{ss}^{-1}\) is set to the inverse of the linear steady-state sequence-space Jacobian computed via the Fake News algorithm: $\(J_{ss} = \left. \frac{\partial \mathbf{H}}{\partial \mathbf{U}} \right|_{ss}\)$ - Quasi-Newton Step:
At iteration \(k\), the proposed update for endogenous variables is: $\(\Delta \mathbf{U}_k = - B_k \mathbf{H}(\mathbf{U}_k, \mathbf{Z})\)$ - Backtracking Line Search:
An Armijo-type backtracking search ensures monotone contraction of the residual norm: $\(\|\mathbf{H}(\mathbf{U}_k + \alpha \Delta \mathbf{U}_k, \mathbf{Z})\|_\infty < \|\mathbf{H}(\mathbf{U}_k, \mathbf{Z})\|_\infty\)$ - Sherman-Morrison Rank-1 Inverse Update:
Let \(\Delta \mathbf{H}_k = \mathbf{H}_{k+1} - \mathbf{H}_k\). The inverse Jacobian approximation is updated analytically without matrix inversion: $\(B_{k+1} = B_k + \frac{(\Delta \mathbf{U}_k - B_k \Delta \mathbf{H}_k) (\Delta \mathbf{U}_k^T B_k)}{\Delta \mathbf{U}_k^T B_k \Delta \mathbf{H}_k}\)$ - Convergence Criterion:
The algorithm terminates when the maximum market-clearing residual satisfies \(\|\mathbf{H}\|_\infty < \text{tol}\) (typically \(10^{-6}\)).
2. Linear vs Non-Linear Transition Dynamics
Non-linear sequence-space transitions uncover critical macroeconomic phenomena absent in linearized models: - Asymmetric Multipliers: Large contractionary interest rate shocks produce sharper contractions than predicted by linear models, as households hit borrowing constraints. - Precautionary Savings Spirals: In large recessions, heightened income uncertainty intensifies self-insurance motives, depressing aggregate demand beyond the linear prediction. - State-Dependent Persistence: The duration of recovery from large fiscal or monetary interventions differs markedly depending on initial wealth distributions.
3. Basic & Advanced Usage
Simulating a Large Monetary Policy Shock
import numpy as np
from puremacro.models.hank_sequence_space import (
solve_hank_sequence_space,
solve_nonlinear_transition,
)
# 1. Solve Steady-State HANK Model and Jacobians
ss_model = solve_hank_sequence_space(
T=300,
beta=0.985,
gamma=1.0,
r_ss=0.01,
phi_pi=1.5,
kappa=0.1,
)
# 2. Specify a Large MIT Monetary Policy Shock (150 bps rate hike)
T_sim = 100
shock_seq = 0.015 * (0.75 ** np.arange(T_sim))
# 3. Solve Non-Linear General Equilibrium Transition Path
res_trans = solve_nonlinear_transition(
ss_model=ss_model,
shock_seq=shock_seq,
shock_var="r",
horizon=T_sim,
max_iter=50,
tol=1e-6,
backtracking=True,
)
# 4. Verify Convergence & Solution Metrics
print(res_trans.summary())
print(f"Converged : {res_trans.converged}")
print(f"Broyden Iterations : {res_trans.iterations}")
print(f"Final Residual Norm : {np.max(np.abs(res_trans.residuals)):.2e}")
# 5. Compare Linear vs Non-Linear Output Responses
print("Max Output Drop (Linear) :", np.min(res_trans.irf_output_linear))
print("Max Output Drop (Non-linear):", np.min(res_trans.irf_output_nonlinear))
# 6. Plot Impulse Responses Comparing Linear vs Non-Linear Trajectories
fig = res_trans.plot()
Simulating an MIT Fiscal Spending Shock
# Fiscal shock: 2% of GDP initial expansion, decaying at 0.8
fiscal_shock = 0.02 * (0.8 ** np.arange(T_sim))
res_fiscal = solve_nonlinear_transition(
ss_model=ss_model,
shock_seq=fiscal_shock,
shock_var="G",
horizon=T_sim,
)
# Inspect Fiscal Multipliers
linear_multiplier = res_fiscal.irf_output_linear[0] / fiscal_shock[0]
nonlinear_multiplier = res_fiscal.irf_output_nonlinear[0] / fiscal_shock[0]
print(f"Impact Multiplier (Linear) : {linear_multiplier:.3f}")
print(f"Impact Multiplier (Non-linear): {nonlinear_multiplier:.3f}")
4. Full API Specification
solve_nonlinear_transition
solve_nonlinear_transition(
ss_model: SequenceSpaceHANKResult | Mapping[str, Any] | None = None,
shock_seq: Sequence[float] | np.ndarray | None = None,
shock_var: str = "r",
horizon: int = 300,
max_iter: int = 100,
tol: float = 1e-6,
backtracking: bool = True,
**kwargs: Any,
) -> NonlinearHANKResult
Parameters:
ss_model: Pre-solved steady-stateSequenceSpaceHANKResultobject or parameter dictionary. IfNone, steady state is solved automatically.shock_seq: Sequence of exogenous MIT shock innovations of length \(T\).shock_var: Shock identity:'r'(monetary policy rate) or'G'(fiscal spending).horizon: Simulation horizon \(T\) in quarters (default300).max_iter: Maximum Broyden Quasi-Newton iterations (default100).tol: Convergence tolerance on \(\|\mathbf{H}\|_\infty\) (default1e-6).backtracking: Whether to employ line search to ensure norm contraction (defaultTrue).
5. Result Interface
NonlinearHANKResult provides structured paths and presentation methods:
- Attributes:
U/nonlinear_path: Solved non-linear sequence of endogenous target variables (output deviations \(dY\)).linear_path: Baseline general equilibrium path from linearized sequence-space model.residuals: Final market-clearing residual sequence \(H_t(U, Z)\) over horizon \(T\).iterations: Iteration count to convergence.converged: Boolean indicating whether \(\|\mathbf{H}\|_\infty < \text{tol}\).norm_history: Residual norm history across iterations.irf_output_linear,irf_output_nonlinear: Linear and non-linear output IRFs.irf_consumption_linear,irf_consumption_nonlinear: Consumption paths.irf_rate_linear,irf_rate_nonlinear: Real interest rate paths.irf_inflation_linear,irf_inflation_nonlinear: Inflation paths.- Methods:
.plot(): Multi-panel Matplotlib figure comparing linear vs non-linear paths across output, consumption, real rate, and inflation..summary(): Detailed diagnostic report of convergence, shock characteristics, and peak response comparisons..to_markdown(),.to_latex(),.to_typst(): Formatted comparison tables for publications.