|
| 1 | +--- |
| 2 | +author_profile: false |
| 3 | +categories: |
| 4 | +- Mathematical Economics |
| 5 | +classes: wide |
| 6 | +date: '2020-07-26' |
| 7 | +excerpt: A guide to solving DSGE models numerically, focusing on perturbation techniques |
| 8 | + and finite difference methods used in economic modeling. |
| 9 | +header: |
| 10 | + image: /assets/images/data_science_18.jpg |
| 11 | + og_image: /assets/images/data_science_18.jpg |
| 12 | + overlay_image: /assets/images/data_science_18.jpg |
| 13 | + show_overlay_excerpt: false |
| 14 | + teaser: /assets/images/data_science_18.jpg |
| 15 | + twitter_image: /assets/images/data_science_18.jpg |
| 16 | +keywords: |
| 17 | +- Dsge models |
| 18 | +- Numerical methods |
| 19 | +- Perturbation techniques |
| 20 | +- Finite difference methods |
| 21 | +- Economic modeling |
| 22 | +- Economics |
| 23 | +- Quantitative analysis |
| 24 | +- Computational methods |
| 25 | +- Python |
| 26 | +- Fortran |
| 27 | +- C |
| 28 | +seo_description: Explore numerical methods for solving DSGE models, including perturbation |
| 29 | + techniques and finite difference methods, essential tools in quantitative economics. |
| 30 | +seo_title: 'Solving DSGE Models: Perturbation and Finite Difference Methods' |
| 31 | +seo_type: article |
| 32 | +summary: This article covers numerical techniques for solving DSGE models, particularly |
| 33 | + perturbation and finite difference methods, essential in analyzing economic dynamics. |
| 34 | +tags: |
| 35 | +- Dsge models |
| 36 | +- Numerical methods |
| 37 | +- Perturbation techniques |
| 38 | +- Finite difference methods |
| 39 | +- Economics |
| 40 | +- Quantitative analysis |
| 41 | +- Computational methods |
| 42 | +- Python |
| 43 | +- Fortran |
| 44 | +- C |
| 45 | +title: 'Solving DSGE Models Numerically: Perturbation Techniques and Finite Difference |
| 46 | + Methods' |
| 47 | +--- |
| 48 | + |
| 49 | +Dynamic Stochastic General Equilibrium (DSGE) models are powerful tools for analyzing the effects of economic shocks and policy changes over time. Because DSGE models are inherently nonlinear and involve complex dynamic relationships, analytical solutions are often not feasible. Instead, numerical methods are used to approximate solutions to these models. Among the most popular techniques are **perturbation methods** and **finite difference methods**, each offering unique approaches to handling DSGE models' nonlinearity and time dependency. |
| 50 | + |
| 51 | +This article explores these numerical methods in-depth, examining how perturbation and finite difference techniques work and how they apply to solving DSGE models. |
| 52 | + |
| 53 | +## Perturbation Techniques for Solving DSGE Models |
| 54 | + |
| 55 | +### Linearization and Higher-Order Approximations |
| 56 | + |
| 57 | +**Perturbation methods** are among the most popular numerical techniques for solving DSGE models. These methods approximate the solution by expanding it around a known steady state, providing a series expansion that represents the model’s behavior. Perturbation methods start with a **first-order linearization** around the steady state and can be extended to **second-order or higher-order** terms to capture nonlinear effects. |
| 58 | + |
| 59 | +1. **First-Order Approximation**: The model is linearized around its steady state, capturing the immediate effects of shocks but not the nonlinearities of the model. |
| 60 | +2. **Second-Order Approximation**: Adds a quadratic term to the expansion, allowing the model to capture some nonlinear effects such as risk premia and the effect of uncertainty on decision-making. |
| 61 | +3. **Higher-Order Approximations**: Higher-order terms can further refine the approximation, capturing more complex dynamic interactions and stochastic volatility. |
| 62 | + |
| 63 | +The general approach for perturbation techniques is: |
| 64 | + |
| 65 | +1. **Identify the Steady State**: Determine the values of variables where the system is in equilibrium. |
| 66 | +2. **Expand the System Around the Steady State**: Use Taylor expansions to approximate the equations of the model. |
| 67 | +3. **Solve the System of Approximated Equations**: The resulting equations provide an approximate solution near the steady state. |
| 68 | + |
| 69 | +#### Example: First-Order Perturbation |
| 70 | + |
| 71 | +Consider a simple DSGE model with a representative agent optimizing utility, where the Euler equation in the steady state is: |
| 72 | + |
| 73 | +\[ |
| 74 | +E_t \left[ u'(c_t) = \beta u'(c_{t+1}) \right] |
| 75 | +\] |
| 76 | + |
| 77 | +A first-order perturbation would linearize this equation around the steady state values of \( c_t \) and \( c_{t+1} \), resulting in a system of linear equations that approximate the dynamics of the economy in response to small shocks. |
| 78 | + |
| 79 | +### Advantages and Limitations of Perturbation Methods |
| 80 | + |
| 81 | +Perturbation techniques have several advantages: |
| 82 | + |
| 83 | +- **Computational Efficiency**: First-order approximations are computationally inexpensive, making them suitable for large models or policy simulations. |
| 84 | +- **Flexibility in Extensions**: Higher-order approximations allow for a more accurate representation of nonlinear effects, albeit with increased computational costs. |
| 85 | + |
| 86 | +However, perturbation methods also have limitations: |
| 87 | + |
| 88 | +- **Local Accuracy**: These methods are only accurate near the steady state and may perform poorly for large shocks or highly nonlinear models. |
| 89 | +- **Complexity in High-Order Terms**: Higher-order perturbations add complexity and can become difficult to interpret or implement. |
| 90 | + |
| 91 | +## Comparing Perturbation and Finite Difference Approaches |
| 92 | + |
| 93 | +Perturbation and finite difference methods each have unique advantages and are suitable for different types of DSGE models: |
| 94 | + |
| 95 | +| Feature | Perturbation Methods | Finite Difference Methods | |
| 96 | +|-----------------------------|--------------------------------------------|-------------------------------------------| |
| 97 | +| **Model Suitability** | Best for models near steady state | Useful for models with strong nonlinearity| |
| 98 | +| **Computational Efficiency**| Generally faster, especially at first-order| Can be computationally intensive | |
| 99 | +| **Handling of Nonlinearity**| Captures local nonlinearity at higher order| Suitable for global nonlinear dynamics | |
| 100 | +| **Ease of Implementation** | Straightforward for low-order expansions | Requires careful grid setup and stability | |
| 101 | + |
| 102 | +The choice between these methods depends on the model's characteristics, the desired level of approximation, and computational resources. |
| 103 | + |
| 104 | +## Conclusion: Choosing the Right Method for DSGE Models |
| 105 | + |
| 106 | +Both perturbation techniques and finite difference methods offer valuable approaches to solving DSGE models. Perturbation methods are ideal for scenarios where a model operates near its steady state, providing computational efficiency with moderate accuracy. In contrast, finite difference methods provide a more global perspective, capturing non-linear dynamics and making them suitable for highly complex or constrained models. |
| 107 | + |
| 108 | +The selection of a numerical method depends on the model’s complexity, the type of economic analysis, and the computational resources available, allowing economists to adapt their approach to best understand dynamic economic relationships. |
| 109 | + |
| 110 | +## Appendix: Python Code Examples for Solving DSGE Models Using Perturbation and Finite Difference Methods |
| 111 | + |
| 112 | +```python |
| 113 | +import numpy as np |
| 114 | +from scipy.optimize import fsolve |
| 115 | + |
| 116 | +# Example DSGE model parameters |
| 117 | +beta = 0.96 |
| 118 | +alpha = 0.36 |
| 119 | +delta = 0.08 |
| 120 | +rho = 0.9 |
| 121 | +sigma = 0.02 |
| 122 | + |
| 123 | +# Steady State Calculation for a Simple DSGE Model |
| 124 | +def steady_state(): |
| 125 | + k_ss = ((1 / beta - (1 - delta)) / alpha) ** (1 / (alpha - 1)) |
| 126 | + c_ss = k_ss ** alpha - delta * k_ss |
| 127 | + return k_ss, c_ss |
| 128 | + |
| 129 | +k_ss, c_ss = steady_state() |
| 130 | + |
| 131 | +# Perturbation Method: First-Order Linearization |
| 132 | +def first_order_perturbation(k, k_next): |
| 133 | + c = k ** alpha - delta * k |
| 134 | + c_next = k_next ** alpha - delta * k_next |
| 135 | + return beta * (c_next / c) * (alpha * k_next ** (alpha - 1) + 1 - delta) - 1 |
| 136 | + |
| 137 | +# Solve DSGE Model Using First-Order Perturbation |
| 138 | +def solve_dsge_perturbation(k0, num_periods=50): |
| 139 | + k_path = [k0] |
| 140 | + for t in range(num_periods): |
| 141 | + k_next = fsolve(first_order_perturbation, k_path[-1], args=(k_path[-1]))[0] |
| 142 | + k_path.append(k_next) |
| 143 | + return np.array(k_path) |
| 144 | + |
| 145 | +# Initial capital and compute path |
| 146 | +k0 = k_ss * 0.9 |
| 147 | +k_path = solve_dsge_perturbation(k0) |
| 148 | +print("Capital Path (Perturbation):", k_path) |
| 149 | + |
| 150 | +# Finite Difference Method: Discrete Derivatives for a Simple DSGE Model |
| 151 | +def finite_difference_method(k_values, h=1e-4): |
| 152 | + derivs = [] |
| 153 | + for k in k_values: |
| 154 | + fwd_diff = (k ** alpha - (k + h) ** alpha) / h |
| 155 | + derivs.append(fwd_diff) |
| 156 | + return np.array(derivs) |
| 157 | + |
| 158 | +# Compute finite difference approximation |
| 159 | +k_values = np.linspace(k0, k_ss, 100) |
| 160 | +finite_diffs = finite_difference_method(k_values) |
| 161 | +print("Finite Differences:", finite_diffs) |
| 162 | +``` |
| 163 | + |
| 164 | +## Appendix: Fortran Code Examples for Solving DSGE Models Using Perturbation and Finite Difference Methods |
| 165 | + |
| 166 | +```fortran |
| 167 | +program DSGE_Model |
| 168 | + implicit none |
| 169 | + integer, parameter :: num_periods = 50 |
| 170 | + real(8) :: beta, alpha, delta, rho, sigma |
| 171 | + real(8) :: k_ss, c_ss, k0, h |
| 172 | + real(8), dimension(num_periods + 1) :: k_path |
| 173 | + integer :: i |
| 174 | +
|
| 175 | + ! Model parameters |
| 176 | + beta = 0.96 |
| 177 | + alpha = 0.36 |
| 178 | + delta = 0.08 |
| 179 | + rho = 0.9 |
| 180 | + sigma = 0.02 |
| 181 | + h = 1.0e-4 |
| 182 | +
|
| 183 | + ! Steady-state calculation |
| 184 | + call steady_state(k_ss, c_ss) |
| 185 | + print *, "Steady State Capital:", k_ss |
| 186 | + print *, "Steady State Consumption:", c_ss |
| 187 | +
|
| 188 | + ! Perturbation method: Initial condition and solving for capital path |
| 189 | + k0 = 0.9 * k_ss |
| 190 | + k_path(1) = k0 |
| 191 | + do i = 1, num_periods |
| 192 | + k_path(i + 1) = solve_dsge_perturbation(k_path(i)) |
| 193 | + end do |
| 194 | + print *, "Capital Path (Perturbation):", k_path |
| 195 | +
|
| 196 | + ! Finite difference approximation |
| 197 | + call finite_difference_method(k_path, h) |
| 198 | +
|
| 199 | +contains |
| 200 | +
|
| 201 | + subroutine steady_state(k_ss, c_ss) |
| 202 | + real(8), intent(out) :: k_ss, c_ss |
| 203 | + k_ss = ((1.0 / beta - (1.0 - delta)) / alpha) ** (1.0 / (alpha - 1.0)) |
| 204 | + c_ss = k_ss ** alpha - delta * k_ss |
| 205 | + end subroutine steady_state |
| 206 | +
|
| 207 | + function solve_dsge_perturbation(k) result(k_next) |
| 208 | + real(8), intent(in) :: k |
| 209 | + real(8) :: k_next, f, f_prime |
| 210 | + integer :: iter |
| 211 | + real(8), parameter :: tol = 1.0e-6 |
| 212 | + k_next = k |
| 213 | + iter = 0 |
| 214 | +
|
| 215 | + do while (abs(f) > tol .and. iter < 100) |
| 216 | + f = first_order_perturbation(k, k_next) |
| 217 | + f_prime = derivative_first_order_perturbation(k, k_next) |
| 218 | + k_next = k_next - f / f_prime |
| 219 | + iter = iter + 1 |
| 220 | + end do |
| 221 | + end function solve_dsge_perturbation |
| 222 | +
|
| 223 | + function first_order_perturbation(k, k_next) result(f) |
| 224 | + real(8), intent(in) :: k, k_next |
| 225 | + real(8) :: f, c, c_next |
| 226 | + c = k ** alpha - delta * k |
| 227 | + c_next = k_next ** alpha - delta * k_next |
| 228 | + f = beta * (c_next / c) * (alpha * k_next ** (alpha - 1) + 1 - delta) - 1.0 |
| 229 | + end function first_order_perturbation |
| 230 | +
|
| 231 | + function derivative_first_order_perturbation(k, k_next) result(f_prime) |
| 232 | + real(8), intent(in) :: k, k_next |
| 233 | + real(8) :: f_prime, epsilon |
| 234 | + epsilon = 1.0e-6 |
| 235 | + f_prime = (first_order_perturbation(k, k_next + epsilon) - & |
| 236 | + first_order_perturbation(k, k_next)) / epsilon |
| 237 | + end function derivative_first_order_perturbation |
| 238 | +
|
| 239 | + subroutine finite_difference_method(k_values, h) |
| 240 | + real(8), intent(in) :: k_values(:) |
| 241 | + real(8), intent(in) :: h |
| 242 | + real(8) :: fwd_diff |
| 243 | + integer :: i, n |
| 244 | + n = size(k_values) |
| 245 | +
|
| 246 | + print *, "Finite Differences:" |
| 247 | + do i = 1, n - 1 |
| 248 | + fwd_diff = (k_values(i + 1) ** alpha - k_values(i) ** alpha) / h |
| 249 | + print *, fwd_diff |
| 250 | + end do |
| 251 | + end subroutine finite_difference_method |
| 252 | +
|
| 253 | +end program DSGE_Model |
| 254 | +``` |
| 255 | + |
| 256 | +## Appendix: C Code Examples for Solving DSGE Models Using Perturbation and Finite Difference Methods |
| 257 | + |
| 258 | +```c |
| 259 | +#include <stdio.h> |
| 260 | +#include <math.h> |
| 261 | + |
| 262 | +#define NUM_PERIODS 50 |
| 263 | +#define TOL 1e-6 |
| 264 | +#define H 1e-4 |
| 265 | + |
| 266 | +/* Parameters for the DSGE model */ |
| 267 | +const double beta = 0.96; |
| 268 | +const double alpha = 0.36; |
| 269 | +const double delta = 0.08; |
| 270 | + |
| 271 | +/* Steady-state calculation */ |
| 272 | +void steady_state(double *k_ss, double *c_ss) { |
| 273 | + *k_ss = pow((1.0 / beta - (1.0 - delta)) / alpha, 1.0 / (alpha - 1.0)); |
| 274 | + *c_ss = pow(*k_ss, alpha) - delta * (*k_ss); |
| 275 | +} |
| 276 | + |
| 277 | +/* Perturbation Method: First-Order Linearization */ |
| 278 | +double first_order_perturbation(double k, double k_next) { |
| 279 | + double c = pow(k, alpha) - delta * k; |
| 280 | + double c_next = pow(k_next, alpha) - delta * k_next; |
| 281 | + return beta * (c_next / c) * (alpha * pow(k_next, alpha - 1) + 1 - delta) - 1.0; |
| 282 | +} |
| 283 | + |
| 284 | +/* Derivative for Newton-Raphson Method */ |
| 285 | +double derivative_first_order_perturbation(double k, double k_next) { |
| 286 | + double epsilon = 1e-6; |
| 287 | + return (first_order_perturbation(k, k_next + epsilon) - first_order_perturbation(k, k_next)) / epsilon; |
| 288 | +} |
| 289 | + |
| 290 | +/* Solve DSGE Model Using Perturbation */ |
| 291 | +double solve_dsge_perturbation(double k) { |
| 292 | + double k_next = k, f, f_prime; |
| 293 | + int iter = 0; |
| 294 | + |
| 295 | + do { |
| 296 | + f = first_order_perturbation(k, k_next); |
| 297 | + f_prime = derivative_first_order_perturbation(k, k_next); |
| 298 | + k_next -= f / f_prime; |
| 299 | + iter++; |
| 300 | + } while (fabs(f) > TOL && iter < 100); |
| 301 | + |
| 302 | + return k_next; |
| 303 | +} |
| 304 | + |
| 305 | +/* Finite Difference Method */ |
| 306 | +void finite_difference_method(double k_values[], int n) { |
| 307 | + printf("Finite Differences:\n"); |
| 308 | + for (int i = 0; i < n - 1; i++) { |
| 309 | + double fwd_diff = (pow(k_values[i + 1], alpha) - pow(k_values[i], alpha)) / H; |
| 310 | + printf("%f\n", fwd_diff); |
| 311 | + } |
| 312 | +} |
| 313 | + |
| 314 | +int main() { |
| 315 | + double k_ss, c_ss, k0; |
| 316 | + double k_path[NUM_PERIODS + 1]; |
| 317 | + |
| 318 | + /* Calculate steady state */ |
| 319 | + steady_state(&k_ss, &c_ss); |
| 320 | + printf("Steady State Capital: %f\n", k_ss); |
| 321 | + printf("Steady State Consumption: %f\n", c_ss); |
| 322 | + |
| 323 | + /* Perturbation method: Initial condition and solving for capital path */ |
| 324 | + k0 = 0.9 * k_ss; |
| 325 | + k_path[0] = k0; |
| 326 | + for (int i = 0; i < NUM_PERIODS; i++) { |
| 327 | + k_path[i + 1] = solve_dsge_perturbation(k_path[i]); |
| 328 | + } |
| 329 | + printf("Capital Path (Perturbation):\n"); |
| 330 | + for (int i = 0; i <= NUM_PERIODS; i++) { |
| 331 | + printf("%f\n", k_path[i]); |
| 332 | + } |
| 333 | + |
| 334 | + /* Finite difference approximation */ |
| 335 | + finite_difference_method(k_path, NUM_PERIODS + 1); |
| 336 | + |
| 337 | + return 0; |
| 338 | +} |
| 339 | +``` |
0 commit comments