├── .gitattributes ├── Documentation.pdf ├── 1 - Base Model ├── Outputs │ ├── Policy_Function_plot.png │ └── Value_Function_plot.png ├── Julia.jl ├── Python.py ├── Matlab.m ├── R.R ├── cpp.cpp └── fortran.f08 ├── 2 - Stochastic Growth ├── Outputs │ ├── Policy Function plot.png │ └── Value Function plot.png ├── Python │ ├── __pycache__ │ │ └── custom_functions.cpython-39.pyc │ ├── Inputs │ │ ├── z_values.csv │ │ └── z_probs.csv │ ├── main.py │ └── custom_functions.py ├── R │ ├── Inputs │ │ ├── z_values.csv │ │ └── z_probs.csv │ ├── custom_functions.R │ └── main.R ├── c++ │ ├── Inputs │ │ ├── z_values.csv │ │ └── z_probs.csv │ ├── custom_functions.h │ ├── main.cpp │ └── custom_functions.cpp ├── Fortran │ ├── Inputs │ │ ├── z_values.csv │ │ └── z_probs.csv │ ├── main.f08 │ └── custom_functions.f08 ├── Julia │ ├── Inputs │ │ ├── z_values.csv │ │ └── z_probs.csv │ ├── custom_functions.jl │ └── main.jl └── Matlab │ ├── Inputs │ ├── z_values.csv │ └── z_probs.csv │ ├── Solve_HH_Problem_v2.m │ ├── Solve_HH_Problem_v1.m │ └── main.m ├── 3 - Idiosyncratic Endowment ├── Outputs │ ├── Policy Function.png │ ├── Policy Function 2.png │ ├── Credit Distribution.png │ ├── Credit Distribution 2.png │ └── Figure 1 from Huggett 1993.png ├── Python │ ├── __pycache__ │ │ └── custom_functions.cpython-39.pyc │ └── main.py ├── C++ │ ├── custom_functions.h │ └── main.cpp ├── Matlab │ ├── Solve_HH_Problem_v2.m │ ├── Get_Population_Distribution.m │ ├── Solve_HH_Problem_v1.m │ ├── Solve_Value_Function.m │ └── main.m ├── R │ └── main.R ├── Julia │ └── main.jl └── Fortran │ └── main.f08 ├── Extra content ├── Fortran project template │ ├── Inputs │ │ ├── z_values.csv │ │ └── z_probs.csv │ ├── .vscode │ │ └── launch.json │ ├── Makefile │ └── src │ │ ├── main.f08 │ │ └── custom_functions.f08 ├── Julia performance profiling │ ├── 2 - Stochastic Growth │ │ ├── Inputs │ │ │ ├── z_values.csv │ │ │ └── z_probs.csv │ │ ├── custom_functions.jl │ │ └── main.jl │ ├── 1 - Base Model │ │ └── base_model.jl │ └── 3 - Idiosyncratic Endowment │ │ └── main.jl ├── C++ implementation using C-style base arrays │ ├── 2 - Stochastric Growth │ │ ├── custom_functions.h │ │ ├── main.cpp │ │ └── custom_functions.cpp │ ├── 3 - Idiosyncratic Endowment │ │ ├── custom_functions.h │ │ └── main.cpp │ └── 1 - Base Model │ │ └── main.cpp ├── Python numpy and numba benchmarking │ ├── benchmarking.py │ ├── benchmarking_parallel.py │ └── custom_functions.py └── C++ multi-threading implementation │ └── main.cpp └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/Documentation.pdf -------------------------------------------------------------------------------- /1 - Base Model/Outputs/Policy_Function_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/1 - Base Model/Outputs/Policy_Function_plot.png -------------------------------------------------------------------------------- /1 - Base Model/Outputs/Value_Function_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/1 - Base Model/Outputs/Value_Function_plot.png -------------------------------------------------------------------------------- /2 - Stochastic Growth/Outputs/Policy Function plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/2 - Stochastic Growth/Outputs/Policy Function plot.png -------------------------------------------------------------------------------- /2 - Stochastic Growth/Outputs/Value Function plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/2 - Stochastic Growth/Outputs/Value Function plot.png -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Outputs/Policy Function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/3 - Idiosyncratic Endowment/Outputs/Policy Function.png -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Outputs/Policy Function 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/3 - Idiosyncratic Endowment/Outputs/Policy Function 2.png -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Outputs/Credit Distribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/3 - Idiosyncratic Endowment/Outputs/Credit Distribution.png -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Outputs/Credit Distribution 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/3 - Idiosyncratic Endowment/Outputs/Credit Distribution 2.png -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Outputs/Figure 1 from Huggett 1993.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/3 - Idiosyncratic Endowment/Outputs/Figure 1 from Huggett 1993.png -------------------------------------------------------------------------------- /2 - Stochastic Growth/Python/__pycache__/custom_functions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/2 - Stochastic Growth/Python/__pycache__/custom_functions.cpython-39.pyc -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Python/__pycache__/custom_functions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RC416/DSGE-models/HEAD/3 - Idiosyncratic Endowment/Python/__pycache__/custom_functions.cpython-39.pyc -------------------------------------------------------------------------------- /2 - Stochastic Growth/R/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/c++/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Fortran/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Julia/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Matlab/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Python/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /Extra content/Fortran project template/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /Extra content/Julia performance profiling/2 - Stochastic Growth/Inputs/z_values.csv: -------------------------------------------------------------------------------- 1 | 0.934957856 2 | 0.947618712 3 | 0.960451018 4 | 0.973457093 5 | 0.986639292 6 | 1 7 | 1.013541633 8 | 1.027266643 9 | 1.041177511 10 | 1.055276755 11 | 1.069566926 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DSGE-models 2 | 3 | In this project I solved 3 simple macroeconomic models in 6 (relatively) common programming languages: Python, R, Matlab, Julia, C++ and Fortran. The purpose was to practice these languages and to serve as a template for future work. The models are a basic growth model, a stochastic growth model, and a model with idiosyncratic endowments. I show some basic performance benchmarking and document my subjective experience across the languages. 4 | -------------------------------------------------------------------------------- /Extra content/Fortran project template/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Launches the debugger from GDB Debug extension. 3 | // Must point to gdb.exe debugger file in mingw install. 4 | // Must point to the right file to debug (usually compiled main) 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "cppdbg", 9 | "request": "launch", 10 | "name": "Launch(gdb)", 11 | "program": "${workspaceRoot}/build.exe", 12 | "cwd": "${workspaceRoot}", 13 | "miDebuggerPath" : "C:/msys64/mingw64/bin/gdb.exe" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /2 - Stochastic Growth/c++/custom_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Define vector-based type aliases for arrays. 6 | using std::vector; 7 | template 8 | using Array2D = vector>; 9 | template 10 | using Array3D = vector>>; 11 | 12 | // Data structure to store parameters. 13 | struct Parameters 14 | { 15 | double alpha, beta, delta; 16 | const int number_of_k_values, number_of_z_values; 17 | vector k_values; 18 | vector z_values; 19 | Array2D z_probs; 20 | }; 21 | 22 | // Function to solve the household's problem for a given starting state. 23 | void Solve_HH_Problem(Array3D& Value_Function, Array3D& Policy_Function, 24 | int iteration, int kt0_index, int zt_index, Parameters& params); 25 | 26 | // Functions to read and write arrays. 27 | void WriteArrayToCSV(Array2D Array, int n_rows, int n_cols, const char* file_name); 28 | vector ReadVectorFromCSV(std::string path); 29 | Array2D ReadArrayFromCSV(std::string path); -------------------------------------------------------------------------------- /2 - Stochastic Growth/R/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/c++/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /Extra content/C++ implementation using C-style base arrays/2 - Stochastric Growth/custom_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // Data structure to store parameters. 6 | struct Parameters 7 | { 8 | double alpha, beta, delta; 9 | const int number_of_k_values, number_of_z_values; 10 | double* k_values; 11 | double* z_values; 12 | double** z_probs; 13 | }; 14 | 15 | // Function to solve Household's problem for given starting states. 16 | void Solve_HH_Problem(double*** Value_Function, double*** Policy_Function, int iteration, int kt0_index, int zt_index, Parameters params); 17 | 18 | // Functions to initialize, deallocate, read and write arrays. 19 | double*** InitializeArray3D(int size_dim_1, int size_dim_2, int size_dim_3); 20 | double** InitializeArray2D(int n_rows, int n_cols); 21 | void DeleteArray3D(double*** Array3D, int size_dim_1, int size_dim_2, int size_dim_3); 22 | void DeleteArray2D(double** Array2D, int n_rows, int n_cols); 23 | void WriteArrayToCSV(double** Array2D, int n_rows, int n_cols, const char* file_name); 24 | double** ReadArrayFromCSV(std::string path); 25 | double* ReadVectorFromCSV(std::string path); -------------------------------------------------------------------------------- /2 - Stochastic Growth/Fortran/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Julia/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Matlab/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Python/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /Extra content/Fortran project template/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /Extra content/Julia performance profiling/2 - Stochastic Growth/Inputs/z_probs.csv: -------------------------------------------------------------------------------- 1 | 0.684522979,0.307322435,0.008146906,7.68E-06,2.12E-10,1.11E-16,0,0,0,0,0 2 | 0.089300267,0.628548041,0.275906868,0.006239878,4.95E-06,1.14E-10,1.11E-16,0,0,0,0 3 | 0.000760786,0.105071824,0.64354684,0.245878276,0.004739118,3.16E-06,6.09E-11,0,0,0,0 4 | 2.93E-07,0.001054125,0.123416637,0.654468037,0.217489945,0.003568966,2.00E-06,3.22E-11,0,0,0 5 | 4.51E-12,4.79E-07,0.001448386,0.143842115,0.661105097,0.19093767,0.002665,1.25E-06,1.69E-11,0,0 6 | 2.65E-18,8.76E-12,7.78E-07,0.001973098,0.166360308,0.663331632,0.166360308,0.001973098,7.78E-07,8.76E-12,0 7 | 5.78E-26,6.11E-18,1.69E-11,1.25E-06,0.002665,0.19093767,0.661105097,0.143842115,0.001448386,4.79E-07,4.51E-12 8 | 4.65E-35,1.59E-25,1.40E-17,3.22E-11,2.00E-06,0.003568966,0.217489945,0.654468037,0.123416637,0.001054125,2.93E-07 9 | 1.36E-45,1.52E-34,4.33E-25,3.17E-17,6.09E-11,3.16E-06,0.004739118,0.245878276,0.64354684,0.105071824,0.000760786 10 | 1.45E-57,5.31E-45,4.93E-34,1.17E-24,7.13E-17,1.14E-10,4.95E-06,0.006239878,0.275906868,0.628548041,0.089300267 11 | 5.60E-71,6.73E-57,2.05E-44,1.58E-33,3.12E-24,1.59E-16,2.12E-10,7.68E-06,0.008146906,0.307322435,0.684522979 12 | -------------------------------------------------------------------------------- /2 - Stochastic Growth/Matlab/Solve_HH_Problem_v2.m: -------------------------------------------------------------------------------- 1 | % Function to solve the household's problem for a given starting state. 2 | % Two different versions with increasing levels of performance. 3 | % Each version has identical inputs and outputs. 4 | % This version uses Matlab's vectorized log function. 5 | % 6 | % Input: 7 | % - Current value function 8 | % - Starting capital and productivity level 9 | % 10 | % Output: 11 | % - Next value function value 12 | % - Optimal choice of next period capital 13 | % 14 | % Version 15 | % v1: using only base functions + for-loops 16 | % v2: using broadcast/vectorized calculation instead of for-loop 17 | 18 | function [v_max, kt1_optimal] = Solve_HH_Problem_v2(Value_Function, kt0_index, zt_index, params) 19 | 20 | % Unpack utility parameters and grids. 21 | alpha = params.alpha; 22 | beta = params.beta; 23 | delta = params.delta; 24 | k_values = params.k_values; 25 | z_values = params.z_values; 26 | z_probs = params.z_probs; 27 | 28 | % Get capital and productivity values from index. 29 | kt0 = k_values(kt0_index); 30 | zt = z_values(zt_index); 31 | 32 | % Calculate array of value function values for all next period capital choices. 33 | V_max_values = log(zt*(kt0^alpha) + (1-delta)*kt0 - k_values) + beta*(Value_Function*z_probs(zt_index,:)'); 34 | 35 | % Get the optimal Value Function and Policy Function values. 36 | [v_max, kt1_index_optimal] = max(V_max_values); 37 | kt1_optimal = k_values(kt1_index_optimal); 38 | end -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/C++/custom_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // Containers for dynamic arrays. 9 | using std::vector; 10 | template using Array2D = vector>; 11 | 12 | // Data structure to store parameters. 13 | struct Parameters 14 | { 15 | double sigma, beta; 16 | const int number_of_a_values, number_of_e_values; 17 | vector a_grid; 18 | vector e_grid; 19 | Array2D e_probs; 20 | }; 21 | 22 | // Functions to solve the household's problem, Value Function, and Population Distribution. 23 | void Solve_HH_Problem(double q, int a_start_index, int e_start_index, Array2D& Value_Function, 24 | Parameters& params, double& V, double& g, int& g_index); 25 | void Solve_Value_Function(double q, Parameters& params, 26 | Array2D& Value_Function, Array2D& Policy_Function, Array2D& Policy_Function_Index); 27 | void Get_Population_Distribution(Array2D& Policy_Function_Index, Parameters& params, 28 | Array2D& Population_Distribution); 29 | double Calculate_Market_Clearing_Condition(Array2D& Population_Distribution, Array2D& Policy_Function); 30 | 31 | // Functions to get distance, copy, and write arrays. 32 | double GetDistanceArray2D(Array2D& Array1, Array2D& Array2); 33 | template void DeepCopyArray2D(Array2D& Array_Original, Array2D& Array_Copy); 34 | template void WriteArrayToCSV(Array2D& Array, const char* file_name); -------------------------------------------------------------------------------- /Extra content/C++ implementation using C-style base arrays/3 - Idiosyncratic Endowment/custom_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // Data structure to store parameters. 9 | struct Parameters 10 | { 11 | double sigma, beta; 12 | const int number_of_a_values, number_of_e_values; 13 | double* a_grid; 14 | double* e_grid; 15 | double* e_probs; 16 | }; 17 | 18 | // Functions to solve the household's problem, Value Function, and Population Distribution. 19 | void Solve_HH_Problem(double q, int a_start_index, int e_start_index, 20 | double* Value_Function, Parameters& params, 21 | double& V, double& g, int& g_index); 22 | 23 | void Solve_Value_Function(double q, Parameters& params, 24 | double* Value_Function, double* Policy_Function, int* Policy_Function_Index, 25 | double* Value_Function_New, double* Policy_Function_New, int* Policy_Function_Index_New); 26 | 27 | void Get_Population_Distribution(int* Policy_Function_Index, Parameters& params, 28 | double* Population_Distribution, double* Population_Distribution_New); 29 | 30 | double Calculate_Market_Clearing_Condition( 31 | double* Population_Distribution, 32 | double* Policy_Function, 33 | int n_rows, int n_cols); 34 | 35 | double GetDistanceArray2D( 36 | double* Array1, 37 | double* Array2, 38 | int n_rows, int n_cols); 39 | 40 | // Functions to copy and write arrays. 41 | template 42 | void DeepCopyArray2D( 43 | number_type* Array_Original, 44 | number_type* Array_Copy, 45 | int n_rows, int n_cols); 46 | 47 | template void WriteArrayToCSV(number_type* Array, const char* file_name, int n_rows, int n_cols); 48 | template void WriteArrayToCSV(number_type* Array, const char* file_name, int n_rows, int n_cols); -------------------------------------------------------------------------------- /2 - Stochastic Growth/Matlab/Solve_HH_Problem_v1.m: -------------------------------------------------------------------------------- 1 | % Function to solve the household's problem for a given starting state. 2 | % Two different versions with increasing levels of performance. 3 | % Each version has identical inputs and outputs. 4 | % This version uses only for-loops. 5 | % 6 | % Input: 7 | % - Current value function 8 | % - Starting capital and productivity level 9 | % 10 | % Output: 11 | % - Next value function value 12 | % - Optimal choice of next period capital 13 | % 14 | % Version 15 | % v1: using only base functions + for-loops 16 | % v2: using broadcast/vectorized calculation instead of for-loop 17 | 18 | function [v_max, kt1_optimal] = Solve_HH_Problem_v1(Value_Function, kt0_index, zt_index, params) 19 | 20 | % Unpack utility parameters and grids. 21 | alpha = params.alpha; 22 | beta = params.beta; 23 | delta = params.delta; 24 | k_values = params.k_values; 25 | z_values = params.z_values; 26 | z_probs = params.z_probs; 27 | 28 | % Get starting capital and productivity values from index. 29 | kt0 = k_values(kt0_index); 30 | zt = z_values(zt_index); 31 | 32 | % Variables to store candidate optimal values for the Value Function and Policy Function. 33 | v_max = -Inf; 34 | kt1_optimal = 0.0; 35 | 36 | % Check all possible next period capital choices. 37 | for kt1_index = 1:size(k_values,1) 38 | 39 | % Get capital value from index. 40 | kt1 = k_values(kt1_index); 41 | 42 | % Calculate the Value Function for given starting capital and next period capital choice. 43 | new_v_max = log(zt * (kt0 ^ alpha) + (1 - delta) * kt0 - kt1) + ... 44 | beta * dot(Value_Function(kt1_index, :), z_probs(zt_index, :)); 45 | 46 | % Check if this capital choice gives the highest Value Function value. 47 | if new_v_max > v_max 48 | 49 | % Update candidate values. 50 | v_max = new_v_max; 51 | kt1_optimal = kt1; 52 | end 53 | end -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Matlab/Solve_HH_Problem_v2.m: -------------------------------------------------------------------------------- 1 | % Function 1: Solve Household Problem (version 2) 2 | % 3 | % Function to find the next iteration of the Value Function and Policy Function 4 | % by solving the household's problem for a given starting state. 5 | % Two different versions with increasing levels of performance. 6 | % Each version has identical inputs and outputs. 7 | % 8 | % Input: 9 | % - Current Value Function 10 | % - Market price for bond 11 | % - Starting wealth and endowment level 12 | % 13 | % Output: 14 | % - Next value function value 15 | % - Optimal choice of savings/borrowing for next period 16 | % 17 | % Version 18 | % v1: using only for-loops 19 | % v2: using arrays / broadcast instead of for-loop 20 | 21 | function [v_max, a_next_optimal, a_next_optimal_index] = ... 22 | Solve_HH_Problem_v2(q, a_start_index, e_start_index, Value_Function, params) 23 | 24 | % Unpack utility parameters and grids. 25 | sigma = params.sigma; 26 | beta = params.beta; 27 | a_grid = params.a_grid; 28 | e_grid = params.e_grid; 29 | e_probs = params.e_probs; 30 | 31 | % Get value of state variables. 32 | a_start = a_grid(a_start_index); 33 | e_start = e_grid(e_start_index); 34 | 35 | % Vector of consumption values dictated by possible next period borrowing choices. 36 | Consumption = a_start + e_start - q*a_grid; 37 | valid_indices = (Consumption > 0); 38 | 39 | % Calculate the Value Function values. 40 | V_max_values = (Consumption(valid_indices).^(1-sigma))./(1-sigma) + beta*(Value_Function(valid_indices,:)*e_probs(e_start_index,:)')'; 41 | 42 | % Get the value and index of optimal value. 43 | [v_max, optimal_subindex] = max(V_max_values); 44 | 45 | % Get the values and original index of optimal value. 46 | a_grid_valid = a_grid(valid_indices); 47 | a_next_optimal = a_grid_valid(optimal_subindex); 48 | a_next_optimal_index = find(a_grid == a_next_optimal); 49 | end -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Matlab/Get_Population_Distribution.m: -------------------------------------------------------------------------------- 1 | % Function 3: Get Population Distribution. 2 | % 3 | % Solves for the steady-state distribution over credit and endowment states given 4 | % a policy function (with index values). 5 | % Search parameters (max iterations, tolerance, etc.) are defined in the function. 6 | % 7 | % Input: 8 | % - Policy Function (with index values) 9 | % 10 | % Output: 11 | % - Steady-state population distribution 12 | 13 | function Population_Distribution = ... 14 | Get_Population_Distribution(Policy_Function_Index, params) 15 | 16 | % Unpack relevant parameters. 17 | e_probs = params.e_probs; 18 | number_of_a_values = params.number_of_a_values; 19 | number_of_e_values = params.number_of_e_values; 20 | 21 | % Arrays to store 2 iterations of finding the population distribution. 22 | Population_Distribution = ones(number_of_a_values, number_of_e_values) ./ (number_of_a_values * number_of_e_values); 23 | New_Distribution = Population_Distribution; 24 | 25 | % Iteration parameters. 26 | dist = Inf; 27 | iteration_count = 0; 28 | max_iterations = 5000; 29 | tolerance = 1e-10; 30 | 31 | % Solve for the steady-state Population Distribution. 32 | while (dist > tolerance) & (iteration_count < max_iterations) 33 | 34 | % Get "inflow" to each credit-endowment state in the next period. 35 | for a_index = 1:number_of_a_values 36 | for e_index = 1:number_of_e_values 37 | 38 | % Sum distribution-weighted inflow into the given state. 39 | inflow = sum( (Population_Distribution .* (Policy_Function_Index == a_index)) * e_probs(:,e_index) ); 40 | New_Distribution(a_index, e_index) = inflow; 41 | end 42 | end 43 | 44 | % Update search parameters. 45 | dist = sum(abs(Population_Distribution - New_Distribution), 'all'); 46 | iteration_count = iteration_count + 1; 47 | 48 | % Update the Population Distribution. 49 | Population_Distribution = New_Distribution; 50 | 51 | % Print warning if convergence is not achieved. 52 | if iteration_count >= max_iterations 53 | fprintf("Warning: population distribution did not converge after %d iterations \n", iteration_count); 54 | end 55 | end 56 | end -------------------------------------------------------------------------------- /Extra content/Fortran project template/Makefile: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | ####################### Makefile Template ############################## 3 | ######################################################################## 4 | 5 | # Compiler settings - Can be customized. 6 | CC = gfortran 7 | CPP = gfortran -cpp 8 | #CXXFLAGS = -g -O0 -Wall -fopenmp -pg # debug mode 9 | CXXFLAGS = -O3 -fopenmp # release mode 10 | #CXXFLAGS = -O3 -fopenmp -pg # release mode with profiling 11 | LDFLAGS = 12 | 13 | # Makefile settings - Can be customized. 14 | APPNAME = build 15 | EXT = .f08 16 | SRCDIR = src 17 | OBJDIR = obj 18 | 19 | ############## Do not change anything from here downwards! ############# 20 | SRC = $(wildcard $(SRCDIR)/*$(EXT)) 21 | OBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)/%.o) 22 | DEP = $(OBJ:$(OBJDIR)/%.o=%.d) 23 | # UNIX-based OS variables & settings 24 | RM = rm 25 | DELOBJ = $(OBJ) 26 | # Windows OS variables & settings 27 | DEL = del 28 | EXE = .exe 29 | WDELOBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)\\%.o) 30 | 31 | ######################################################################## 32 | ####################### Targets beginning here ######################### 33 | ######################################################################## 34 | 35 | all: $(APPNAME) 36 | 37 | # Builds the app 38 | $(APPNAME): $(OBJ) 39 | $(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) 40 | 41 | # Creates the dependecy rules 42 | %.d: $(SRCDIR)/%$(EXT) 43 | @$(CPP) $(CFLAGS) $< -MM -MT $(@:%.d=$(OBJDIR)/%.o) >$@ 44 | 45 | # Includes all .h files 46 | -include $(DEP) 47 | 48 | # Building rule for .o files and its .c/.cpp in combination with all .h 49 | $(OBJDIR)/%.o: $(SRCDIR)/%$(EXT) 50 | $(CC) $(CXXFLAGS) -o $@ -c $< 51 | 52 | ################### Cleaning rules for Unix-based OS ################### 53 | # Cleans complete project 54 | .PHONY: clean 55 | clean: 56 | $(RM) $(DELOBJ) $(DEP) $(APPNAME) 57 | 58 | # Cleans only all files with the extension .d 59 | .PHONY: cleandep 60 | cleandep: 61 | $(RM) $(DEP) 62 | 63 | #################### Cleaning rules for Windows OS ##################### 64 | # Cleans complete project 65 | .PHONY: cleanw 66 | cleanw: 67 | $(DEL) $(WDELOBJ) $(DEP) $(APPNAME)$(EXE) 68 | 69 | # Cleans only all files with the extension .d 70 | .PHONY: cleandepw 71 | cleandepw: 72 | $(DEL) $(DEP) 73 | -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Matlab/Solve_HH_Problem_v1.m: -------------------------------------------------------------------------------- 1 | % Function 1: Solve Household Problem (version 1) 2 | % 3 | % Function to find the next iteration of the Value Function and Policy Function 4 | % by solving the household's problem for a given starting state. 5 | % Two different versions with increasing levels of performance. 6 | % Each version has identical inputs and outputs. 7 | % 8 | % Input: 9 | % - Current Value Function 10 | % - Market price for bond 11 | % - Starting wealth and endowment level 12 | % 13 | % Output: 14 | % - Next value function value 15 | % - Optimal choice of savings/borrowing for next period 16 | % 17 | % Version 18 | % v1: using only for-loops 19 | % v2: using arrays / broadcast instead of for-loop 20 | 21 | function [v_max, a_next_optimal, a_next_optimal_index] = ... 22 | Solve_HH_Problem_v1(q, a_start_index, e_start_index, Value_Function, params) 23 | 24 | % Unpack utility parameters and grids. 25 | sigma = params.sigma; 26 | beta = params.beta; 27 | a_grid = params.a_grid; 28 | e_grid = params.e_grid; 29 | e_probs = params.e_probs; 30 | number_of_a_values = params.number_of_a_values; 31 | 32 | % Get value of state variables. 33 | a_start = a_grid(a_start_index); 34 | e_start = e_grid(e_start_index); 35 | 36 | % Variables to store candidate optimal values for the Value Function and Policy Function. 37 | v_max = -Inf; 38 | a_next_optimal = 0.0; 39 | a_next_optimal_index = 0; 40 | 41 | % Search over possible next period borrowing choices. 42 | for a_next_index = 1:number_of_a_values 43 | 44 | % Get next credit value and the value of consumption implied by the budget constraint. 45 | a_next = a_grid(a_next_index); 46 | consumption = a_start + e_start - q*a_next; 47 | 48 | % Check budget constraint: if consumption is negative, skip this value. 49 | if (consumption <= 0); break; end 50 | 51 | % Calculate the Value Function value. 52 | new_v_max = ((consumption) ^ (1 - sigma)) / (1 - sigma) + beta * dot(Value_Function(a_next_index, :), e_probs(e_start_index, :)); 53 | 54 | % Check if this capital choice gives the highest Value Function value. 55 | if new_v_max > v_max 56 | 57 | % Update candidate values. 58 | v_max = new_v_max; 59 | a_next_optimal = a_next; 60 | a_next_optimal_index = a_next_index; 61 | end 62 | end 63 | end -------------------------------------------------------------------------------- /Extra content/Python numpy and numba benchmarking/benchmarking.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Benchmarking the performance of the various versions of Iterate_Value_Function 4 | used to solve the stochastic growth model. 5 | 6 | Using 1000 iterations takes approximately 20 minutes to run. 7 | """ 8 | 9 | import numpy as np 10 | from datetime import datetime 11 | 12 | # Import parameter values and struct. 13 | from main import (alpha, beta, delta, k_values, number_of_k_values, z_values, z_probs, 14 | number_of_z_values, Parameters) 15 | params = Parameters(alpha, beta, delta, k_values, z_values, z_probs) 16 | 17 | # Assign additional parameter values. 18 | number_of_iterations = 1000 19 | 20 | # Initialize Value Function and Policy Function (as arrays). 21 | Value_Function = np.zeros((number_of_iterations, number_of_k_values, number_of_z_values)) 22 | Policy_Function = np.zeros((number_of_iterations, number_of_k_values, number_of_z_values)) 23 | 24 | # Load the various versions of the key value function iteration function. 25 | from custom_functions import (Solve_HH_Problem_v1, Solve_HH_Problem_v2, 26 | Solve_HH_Problem_v3, Solve_HH_Problem_v4) 27 | 28 | functions = [("base", Solve_HH_Problem_v1), 29 | ("numpy", Solve_HH_Problem_v2), 30 | ("numba precompiled", Solve_HH_Problem_v3), 31 | ("numba precompiled + numpy", Solve_HH_Problem_v4)] 32 | 33 | # Solve model with each version of the function. 34 | for (version, Solve_HH_Problem) in functions: 35 | 36 | # Part 1 - implement value function iteration without parallel processing. 37 | start = datetime.now() 38 | 39 | # Perform value function iteration. 40 | for iteration in range(1,number_of_iterations): 41 | 42 | # Loop over all possible starting states. 43 | for kt0 in enumerate(k_values): 44 | for zt in enumerate(z_values): 45 | 46 | # Solve Value Function and Policy Function and update values 47 | V, g = Solve_HH_Problem(Value_Function[iteration-1, :, :], kt0, zt, params) 48 | 49 | Value_Function[iteration, kt0[0], zt[0]] = V 50 | Policy_Function[iteration, kt0[0], zt[0]] = g 51 | 52 | end = datetime.now() 53 | 54 | # Display results. 55 | print(version) 56 | print("Single-core implementation:") 57 | print(" start: ", start.strftime("%H:%M:%S")) 58 | print(" stop: ", end.strftime("%H:%M:%S")) 59 | print(" seconds: ", (end-start).seconds) 60 | print(" minutes: ", (round((end-start).seconds/60,2))) -------------------------------------------------------------------------------- /1 - Base Model/Julia.jl: -------------------------------------------------------------------------------- 1 | # Base Model implementation in Julia. 2 | 3 | # Assign parameter values. 4 | α = 0.400; 5 | β = 0.987; 6 | δ = 1.000; 7 | number_of_iterations = 1000; 8 | 9 | # Calculate the steady-state level of capital. 10 | k_steady = ((1 - β * (1 - δ)) / (α * β)) ^ (1 / (α - 1)) 11 | 12 | # Create a grid of capital values around steady-state (+/- 50%). 13 | number_of_k_values = 201; 14 | k_low_pct = 0.50; 15 | k_high_pct = 1.50; 16 | k_values = range(k_low_pct * k_steady, k_high_pct * k_steady, length=number_of_k_values); 17 | 18 | # Initialize the Value Function and Policy Function (as arrays). 19 | Value_Function = zeros(number_of_iterations, number_of_k_values); 20 | Policy_Function = zeros(number_of_iterations, number_of_k_values); 21 | 22 | # Solve the household's problem for each possible starting state. 23 | for iteration in 2:number_of_iterations 24 | 25 | for kt0_index in eachindex(k_values) 26 | 27 | # Variables to store candidate optimal values. 28 | v_max = -Inf; 29 | kt1_optimal = 0; 30 | 31 | # Check all possible next period capital choices. 32 | for kt1_index in eachindex(k_values) 33 | 34 | # Get capital values from index. 35 | kt0 = k_values[kt0_index]; 36 | kt1 = k_values[kt1_index]; 37 | 38 | # Calculate the Value Function for given starting capital and next period capital choice. 39 | new_value_function_value = log(kt0 ^ α + (1 - δ) * kt0 - kt1) + β * Value_Function[iteration - 1, kt1_index]; 40 | 41 | # Check if this capital choice gives the highest Value Function value. 42 | if new_value_function_value > v_max 43 | 44 | # Update candidate values. 45 | v_max = new_value_function_value; 46 | kt1_optimal = kt1; 47 | end 48 | end 49 | 50 | # Update the Value Function and Policy function with optimal values. 51 | Value_Function[iteration, kt0_index] = v_max; 52 | Policy_Function[iteration, kt0_index] = kt1_optimal; 53 | end 54 | end 55 | 56 | # Plot various iterations of the Value Function. 57 | using Plots 58 | Figure1 = plot(k_values, Value_Function[1, :], label="1") 59 | for iteration = number_of_iterations / 10 : number_of_iterations / 10 : number_of_iterations 60 | plot!(k_values, Value_Function[Int(iteration), :], label=string(Int(iteration))) 61 | end 62 | xlabel!("k") 63 | ylabel!("V(k)") 64 | title!("Value Function") 65 | display(Figure1) 66 | 67 | # Plot the final Policy Function. 68 | Figure2 = plot(k_values, Policy_Function[number_of_iterations, :], label="g(k)", legend=:topleft) 69 | plot!(k_values,k_values, label="45-degree line", color=:black) 70 | xlabel!("k") 71 | ylabel!("g(k)") 72 | title!("Policy Function") 73 | display(Figure2) -------------------------------------------------------------------------------- /1 - Base Model/Python.py: -------------------------------------------------------------------------------- 1 | # Base Model implementation in Python. 2 | 3 | # Load packages. 4 | import numpy as np 5 | from math import log 6 | 7 | # Assign parameter values. 8 | alpha = 0.400 9 | beta = 0.987 10 | delta = 1.000 11 | number_of_iterations = 1000 12 | 13 | # Calculate the steady-state level of capital. 14 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ** (1 / (alpha - 1)) 15 | 16 | # Create a grid of capital values around the steady-state (+/- 50%). 17 | number_of_k_values = 201 18 | k_low_pct = 0.50 19 | k_high_pct = 1.50 20 | k_values = np.linspace(k_low_pct * k_steady, k_high_pct * k_steady, num=number_of_k_values) 21 | 22 | # Initialize the Value Function and Policy Function (as arrays). 23 | Value_Function = np.zeros((number_of_iterations, number_of_k_values)) 24 | Policy_Function = np.zeros((number_of_iterations, number_of_k_values)) 25 | 26 | # Solve the household's problem for each possible starting state. 27 | for iteration in range(1, number_of_iterations): 28 | 29 | for kt0 in enumerate(k_values): 30 | 31 | # Variables to store candidate optimal values. 32 | v_max = float('-inf') 33 | kt1_optimal = 0.0 34 | 35 | # Check all possible next period capital choices. 36 | for kt1 in enumerate(k_values): 37 | 38 | # Calculate the Value Function for given starting capital and next period capital choice. 39 | new_value_function_value = (log((kt0[1] ** alpha) - kt1[1] + (1 - delta) * kt0[1]) 40 | + beta * Value_Function[iteration - 1, kt1[0]]) 41 | 42 | # Check if this capital choice gives the highest Value Function value. 43 | if new_value_function_value > v_max: 44 | 45 | # Update candidate values. 46 | v_max = new_value_function_value 47 | kt1_optimal = kt1[1] 48 | 49 | # Update the Value Function and Policy Function with optimal values. 50 | Value_Function[iteration, kt0[0]] = v_max 51 | Policy_Function[iteration, kt0[0]] = kt1_optimal 52 | 53 | # Plot various iterations of the Value Function. 54 | import matplotlib.pyplot as plt 55 | fig, ax = plt.subplots() 56 | for iteration in range(0,number_of_iterations, int(number_of_iterations / 10)): 57 | ax.plot(k_values, Value_Function[iteration, ]) 58 | ax.set(xlabel='k', ylabel='V(k)', title="Value Function") 59 | ax.legend(range(1, number_of_iterations + 1, int(number_of_iterations / 10)), loc='right') 60 | plt.show() 61 | 62 | # Plot the final Policy Function. 63 | fig, ax = plt.subplots() 64 | ax.plot(k_values, Policy_Function[-1,]) 65 | ax.plot(k_values, k_values, '--', color='k', linewidth=0.8) 66 | ax.set(xlabel='k', ylabel='g(k)', title="Policy Function") 67 | ax.legend(["g(k)", "45-degree line"]) 68 | plt.show() 69 | -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Matlab/Solve_Value_Function.m: -------------------------------------------------------------------------------- 1 | % Function 2: Solve Value Function 2 | % 3 | % Solves for the Value Function and Policy Function using value function iteration. 4 | % Applies the Solve Household Problem function to all possible starting states for each iteration. 5 | % Search parameters (max iterations, tolerance, etc.) are defined in the function. 6 | % 7 | % Input: 8 | % - Market price for bond 9 | % 10 | % Output: 11 | % - Value Function 12 | % - Policy Function 13 | % - Policy Function (with indices instead of values) 14 | 15 | function [Value_Function, Policy_Function, Policy_Function_Index] = ... 16 | Solve_Value_Function(q, params) 17 | 18 | % Unpack relevant parameters. 19 | number_of_a_values = params.number_of_a_values; 20 | number_of_e_values = params.number_of_e_values; 21 | 22 | % Arrays to hold 2 value function iterations. 23 | Value_Function = zeros(number_of_a_values, number_of_e_values); 24 | Policy_Function = zeros(number_of_a_values, number_of_e_values); 25 | Policy_Function_Index = zeros(number_of_a_values, number_of_e_values); 26 | 27 | Value_Function_New = zeros(number_of_a_values, number_of_e_values); 28 | Policy_Function_New = zeros(number_of_a_values, number_of_e_values); 29 | Policy_Function_Index_New = zeros(number_of_a_values, number_of_e_values); 30 | 31 | % Iteration parameters. 32 | dist = Inf; 33 | iteration_count = 0; 34 | max_iterations = 5000; 35 | tolerance = 1e-6; 36 | 37 | % Solve for the Value Function and Policy Function. 38 | while (dist > tolerance) & (iteration_count < max_iterations) 39 | 40 | % Loop over all possible starting states. 41 | for a_start_index = 1:number_of_a_values 42 | for e_start_index = 1:number_of_e_values 43 | 44 | % Solve the Value Function and Policy Function and update values. 45 | [V, g, g_index] = Solve_HH_Problem_v1(q, a_start_index, e_start_index, Value_Function, params); 46 | %[V, g, g_index] = Solve_HH_Problem_v2(q, a_start_index, e_start_index, Value_Function, params); 47 | 48 | Value_Function_New(a_start_index, e_start_index) = V; 49 | Policy_Function_New(a_start_index, e_start_index) = g; 50 | Policy_Function_Index_New(a_start_index, e_start_index) = g_index; 51 | end 52 | end 53 | 54 | % Update search parameters. 55 | dist = max(abs(Value_Function - Value_Function_New), [], 'all'); 56 | iteration_count = iteration_count + 1; 57 | 58 | % Update the Value Function and Policy Function. 59 | Value_Function = Value_Function_New; 60 | Policy_Function = Policy_Function_New; 61 | Policy_Function_Index = Policy_Function_Index_New; 62 | 63 | % Print warning if convergence is not achieved. 64 | if iteration_count >= max_iterations 65 | fprintf("Warning: value function did not converge after %d iterations \n", iteration_count); 66 | end 67 | end 68 | end -------------------------------------------------------------------------------- /1 - Base Model/Matlab.m: -------------------------------------------------------------------------------- 1 | % Base Model implementation in Matlab. 2 | 3 | % Assign parameter values. 4 | alpha = 0.400; 5 | beta = 0.987; 6 | delta = 1.000; 7 | number_of_iterations = 1000; 8 | 9 | % Calculate the steady-state level of capital. 10 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ^ (1 / (alpha - 1)); 11 | 12 | % Create a grid of capital values around steady-state (+/- 50%). 13 | number_of_k_values = 201; 14 | k_low_pct = 0.50; 15 | k_high_pct = 1.50; 16 | k_values = linspace(k_low_pct * k_steady, k_high_pct * k_steady, number_of_k_values); 17 | 18 | % Initialize the Value Function and Policy Function (as arrays). 19 | Value_Function = zeros(number_of_iterations, number_of_k_values); 20 | Policy_Function = zeros(number_of_iterations, number_of_k_values); 21 | 22 | % Solve the household's problem for each possible starting state. 23 | for iteration = 2:(number_of_iterations) 24 | 25 | for kt0_index = 1:number_of_k_values 26 | 27 | % Variables to store candidate optimal values. 28 | v_max = -inf; 29 | kt1_optimal = 0; 30 | 31 | % Check all possible next period capital choices. 32 | for kt1_index = 1:number_of_k_values 33 | 34 | % Get capital values from index. 35 | kt0 = k_values(kt0_index); 36 | kt1 = k_values(kt1_index); 37 | 38 | % Calculate theValue Function for given starting capital and next period capital choice. 39 | new_value_function_value = log((kt0 ^ alpha) + (1 - delta) * kt0 - kt1)... 40 | + beta * Value_Function(iteration - 1, kt1_index); 41 | 42 | % Check if this capital choice gives highest Value Function value. 43 | if new_value_function_value > v_max 44 | 45 | % Update candidate values. 46 | v_max = new_value_function_value; 47 | kt1_optimal = kt1; 48 | end 49 | end 50 | 51 | % Update the Value Function and Policy Function with optimal values. 52 | Value_Function(iteration, kt0_index) = v_max; 53 | Policy_Function(iteration, kt0_index) = kt1_optimal; 54 | end 55 | end 56 | 57 | % Plot various iterations of the Value Function. 58 | figure(1) 59 | plot(k_values, Value_Function(1,:)) 60 | hold on 61 | for iteration = number_of_iterations / 10 : number_of_iterations / 10 : number_of_iterations 62 | plot(k_values, Value_Function(number_of_iterations, :)) 63 | end 64 | hold off 65 | xlabel('k') 66 | ylabel('V(k)') 67 | title('Value Function') 68 | legend(["1", string(number_of_iterations / 10 : number_of_iterations / 10 : number_of_iterations)]) 69 | 70 | % Plot the final Policy Function. 71 | figure(2) 72 | hold on 73 | plot(k_values,Policy_Function(number_of_iterations, :)) 74 | plot(k_values, k_values, '--', Color='k') 75 | hold off 76 | xlabel('k') 77 | ylabel('g(k)') 78 | title('Policy Function') 79 | legend('g(k)','45^o Line', 'Location', 'northwest') 80 | -------------------------------------------------------------------------------- /1 - Base Model/R.R: -------------------------------------------------------------------------------- 1 | # Base Model implementation in R. 2 | 3 | # Assign parameter values. 4 | alpha = 0.400 5 | beta = 0.987 6 | delta = 1.000 7 | number_of_iterations = 1000 8 | 9 | # Calculate the steady-state level of capital. 10 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ^ (1 / (alpha - 1)) 11 | 12 | # Create a grid of capital values around the steady-state (+/- 50%). 13 | number_of_k_values = 201 14 | k_low_pct = 0.50 15 | k_high_pct = 1.50 16 | k_values = seq(k_low_pct * k_steady, k_high_pct * k_steady, length.out=number_of_k_values) 17 | 18 | # Initialize the Value Function and Policy Function (as arrays). 19 | Value_Function = array(0, c(number_of_iterations, number_of_k_values)) 20 | Policy_Function = array(0, c(number_of_iterations, number_of_k_values)) 21 | 22 | # Solve the household's problem for each possible starting state. 23 | for (iteration in 2:number_of_iterations) 24 | { 25 | for (kt0_index in 1:number_of_k_values) 26 | { 27 | # Variables to store candidate optimal values. 28 | v_max = -Inf 29 | kt1_optimal = 0 30 | 31 | # Check all possible next period capital choices. 32 | for (kt1_index in 1:number_of_k_values) 33 | { 34 | # Get capital values from index. 35 | kt0 = k_values[kt0_index] 36 | kt1 = k_values[kt1_index] 37 | 38 | # Calculate the Value Function for given starting capital and next period capital choice. 39 | new_value_function_value = log((kt0 ^ alpha) + (1 - delta) * kt0 - kt1) + beta * Value_Function[iteration - 1, kt1_index] 40 | 41 | # Check if this capital choice gives the highest Value Function value. 42 | if (new_value_function_value > v_max) 43 | { 44 | # Update candidate values. 45 | v_max = new_value_function_value 46 | kt1_optimal = kt1 47 | } 48 | } 49 | 50 | # Update the Value Function and Policy Function with optimal values. 51 | Value_Function[iteration, kt0_index] = v_max 52 | Policy_Function[iteration, kt0_index] = kt1_optimal 53 | } 54 | } 55 | 56 | # Plot various iterations of the Value Function. 57 | plot(c(min(k_values), max(k_values)), c(min(Value_Function), max(Value_Function)), type="l", col="white", # hidden values to establish plot size 58 | main = "Value Function", xlab="k", ylab="V(k)") 59 | lines(k_values, Value_Function[1, ]) 60 | for (iteration in seq(number_of_iterations / 10,number_of_iterations, number_of_iterations / 10)) 61 | { 62 | lines(k_values, Value_Function[iteration, ]) 63 | } 64 | legend("right", legend = c(1, seq(number_of_iterations / 10,number_of_iterations, number_of_iterations / 10))) 65 | 66 | # Plot the final Policy Function. 67 | plot(k_values, k_values, type="l", lty=2, col="black", 68 | main="Policy Function", xlab="k", ylab="g(k)") 69 | lines(k_values, Policy_Function[number_of_iterations,], col="blue") 70 | legend("topleft", legend=c("g(k)", "45-degree line"), col=c("blue", "black"), lty=c(1, 2)) 71 | -------------------------------------------------------------------------------- /Extra content/Julia performance profiling/1 - Base Model/base_model.jl: -------------------------------------------------------------------------------- 1 | # Base Model implementation in Julia. 2 | 3 | function main() 4 | 5 | # Assign parameter values. 6 | α = 0.400; 7 | β = 0.987; 8 | δ = 1.000; 9 | number_of_iterations = 1000; 10 | 11 | # Calculate the steady-state level of capital. 12 | k_steady = ((1 - β * (1 - δ)) / (α * β)) ^ (1 / (α - 1)) 13 | 14 | # Create a grid of capital values around steady-state (+/- 50%). 15 | number_of_k_values = 201; 16 | k_low_pct = 0.50; 17 | k_high_pct = 1.50; 18 | k_values = range(k_low_pct * k_steady, k_high_pct * k_steady, length=number_of_k_values); 19 | 20 | # Initialize the Value Function and Policy Function (as arrays). 21 | Value_Function = zeros(number_of_iterations, number_of_k_values); 22 | Policy_Function = zeros(number_of_iterations, number_of_k_values); 23 | 24 | # Solve the household's problem for each possible starting state. 25 | for iteration in 2:number_of_iterations 26 | 27 | for kt0_index in eachindex(k_values) 28 | 29 | # Variables to store candidate optimal values. 30 | v_max = -Inf; 31 | kt1_optimal = 0; 32 | 33 | # Check all possible next period capital choices. 34 | for kt1_index in eachindex(k_values) 35 | 36 | # Get capital values from index. 37 | kt0 = k_values[kt0_index]; 38 | kt1 = k_values[kt1_index]; 39 | 40 | # Calculate the Value Function for given starting capital and next period capital choice. 41 | new_value_function_value = log(kt0 ^ α + (1 - δ) * kt0 - kt1) + β * Value_Function[iteration - 1, kt1_index]; 42 | 43 | # Check if this capital choice gives the highest Value Function value. 44 | if new_value_function_value > v_max 45 | 46 | # Update candidate values. 47 | v_max = new_value_function_value; 48 | kt1_optimal = kt1; 49 | end 50 | end 51 | 52 | # Update the Value Function and Policy function with optimal values. 53 | Value_Function[iteration, kt0_index] = v_max; 54 | Policy_Function[iteration, kt0_index] = kt1_optimal; 55 | end 56 | end 57 | 58 | 59 | # Plot various iterations of the Value Function. 60 | Figure1 = plot(k_values, Value_Function[1, :], label="1") 61 | for iteration = number_of_iterations / 10 : number_of_iterations / 10 : number_of_iterations 62 | plot!(k_values, Value_Function[Int(iteration), :], label=string(Int(iteration))) 63 | end 64 | xlabel!("k") 65 | ylabel!("V(k)") 66 | title!("Value Function") 67 | display(Figure1) 68 | 69 | # Plot the final Policy Function. 70 | Figure2 = plot(k_values, Policy_Function[number_of_iterations, :], label="g(k)", legend=:topleft) 71 | plot!(k_values,k_values, label="45-degree line", color=:black) 72 | xlabel!("k") 73 | ylabel!("g(k)") 74 | title!("Policy Function") 75 | display(Figure2) 76 | 77 | end 78 | 79 | using Plots 80 | using Profile 81 | using BenchmarkTools 82 | 83 | @btime main() 84 | @profview main() 85 | # https://www.julia-vscode.org/docs/dev/userguide/profiler/ -------------------------------------------------------------------------------- /Extra content/Python numpy and numba benchmarking/benchmarking_parallel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Benchmarking the performance of the various versions of Solve_HH_Problem 4 | used to solve the stochastic growth model. 5 | 6 | This file runs the loop over states in parallel. Due to the model features, 7 | only the base for-loop (version 1) function runs faster in parallel. 8 | 9 | Using 1000 iterations takes approximately 20 minutes to run. 10 | """ 11 | 12 | import numpy as np 13 | from datetime import datetime 14 | 15 | # Import parameter values and struct. 16 | from main import (alpha, beta, delta, k_values, number_of_k_values, z_values, z_probs, 17 | number_of_z_values, Parameters) 18 | params = Parameters(alpha, beta, delta, k_values, z_values, z_probs) 19 | 20 | # Assign additional parameter values. 21 | number_of_iterations = 1000 22 | 23 | # Initialize Value Function and Policy Function (as arrays). 24 | Value_Function = np.zeros((number_of_iterations, number_of_k_values, number_of_z_values)) 25 | Policy_Function = np.zeros((number_of_iterations, number_of_k_values, number_of_z_values)) 26 | 27 | # Load the various versions of the key value function iteration function. 28 | from custom_functions import (Solve_HH_Problem_v1, Solve_HH_Problem_v2, 29 | Solve_HH_Problem_v3, Solve_HH_Problem_v4) 30 | 31 | functions = [("base", Solve_HH_Problem_v1), 32 | ("numpy", Solve_HH_Problem_v2), 33 | ("numba precompiled", Solve_HH_Problem_v3), 34 | ("numba precompiled + numpy", Solve_HH_Problem_v4)] 35 | 36 | 37 | # Solve model with each version of the function. 38 | for (version, Solve_HH_Problem) in functions: 39 | 40 | start = datetime.now() 41 | 42 | import os 43 | from joblib import Parallel, delayed 44 | num_threads = os.cpu_count() 45 | 46 | if __name__ == "__main__": 47 | 48 | for iteration in range(1, number_of_iterations): 49 | 50 | # Get list of Value Function and Policy Function values for each starting state (kt0, zt). 51 | processed_list = Parallel(n_jobs=num_threads)(delayed(Solve_HH_Problem) 52 | (Value_Function[iteration-1, : :], kt0, zt, params) 53 | for kt0 in enumerate(k_values) for zt in enumerate(z_values)) 54 | 55 | # Reshape to arrays in the same shape as the Value Function and Policy Function. 56 | new_values = np.reshape(processed_list, (number_of_k_values, number_of_z_values, 2)) 57 | 58 | # Update values. 59 | Value_Function[iteration,:,:] = new_values[:, :, 0] 60 | Policy_Function[iteration,:,:] = new_values[:, :, 1] 61 | 62 | end = datetime.now() 63 | 64 | # Display results. 65 | print(version) 66 | print(" start: ", start.strftime("%H:%M:%S")) 67 | print(" stop: ", end.strftime("%H:%M:%S")) 68 | print(" seconds: ", (end-start).seconds) 69 | print(" minutes: ", round((end-start).seconds/60,2)) 70 | print("\n") -------------------------------------------------------------------------------- /2 - Stochastic Growth/Matlab/main.m: -------------------------------------------------------------------------------- 1 | % Stochastic Growth model implemented in Matlab. 2 | % 3 | % Steps: 4 | % 1 - Define utility parameters, grids, and parameter struct. 5 | % 2 - Perform value function iteration. 6 | % 3 - Plot results. 7 | 8 | %% 1 - Define utility parameters, grids, and parameter struct. 9 | 10 | % Assign parameter values. 11 | alpha = 0.400; 12 | beta = 0.987; 13 | delta = 0.012; 14 | number_of_iterations = 1000; 15 | 16 | % Calculate the steady-state level of capital. 17 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ^ (1 / (alpha - 1)); 18 | 19 | % Create a range of capital values around the steady-state (+/- 2%). 20 | number_of_k_values = 201; 21 | k_low_pct = 0.98; 22 | k_high_pct = 1.02; 23 | k_values = linspace(k_low_pct * k_steady, k_high_pct * k_steady, number_of_k_values)'; 24 | 25 | % Get productivity levels and transition probabilities. 26 | z_probs = readmatrix("Inputs\z_probs.csv"); 27 | z_values = readmatrix("Inputs\z_values.csv"); 28 | number_of_z_values = size(z_values, 1); 29 | 30 | % Initialize the Value Function and Policy Function (as arrays). 31 | Value_Function = zeros(number_of_k_values, number_of_z_values, number_of_iterations); 32 | Policy_Function = zeros(number_of_k_values, number_of_z_values, number_of_iterations); 33 | 34 | % Store utility parameters and capital/productivity grids in a struct for passing to a function. 35 | params = struct( ... 36 | alpha=alpha, beta=beta, delta=delta, ... 37 | k_values=k_values, z_values=z_values, ... 38 | z_probs=z_probs); 39 | 40 | %% 2 - Perform value function iteration. 41 | 42 | for iteration = 2:number_of_iterations 43 | 44 | % Loop over all possible starting states. 45 | for kt0_index = 1:number_of_k_values 46 | for zt_index = 1:number_of_z_values 47 | 48 | % Solve the Value Function and Policy Function and update values. 49 | [V, g] = Solve_HH_Problem_v1(Value_Function(:, :, iteration - 1), kt0_index, zt_index, params); 50 | %[V, g] = Solve_HH_Problem_v2(Value_Function(:, :, iteration - 1), kt0_index, zt_index, params); 51 | 52 | Value_Function(kt0_index, zt_index, iteration) = V; 53 | Policy_Function( kt0_index, zt_index, iteration) = g; 54 | end 55 | end 56 | end 57 | 58 | %% 3 - Plot results. 59 | 60 | % Plot the Value Function for different starting states. 61 | figure(1) 62 | hold on 63 | for zt_index = 1:number_of_z_values 64 | plot(k_values,Value_Function(:, zt_index, number_of_iterations)) 65 | end 66 | hold off 67 | xlabel('k') 68 | ylabel('V(k,z)') 69 | title('Value Function') 70 | lgd = legend([string(round(flip(z_values), 2))]); 71 | lgd.Title.String = "z values"; 72 | 73 | % Plot the final Policy Function for certain productivity values. 74 | figure(2) 75 | z_indices = [1, 4, 6, 8, 11]; 76 | hold on 77 | for z_index = 1:size(z_indices, 2) 78 | plot(k_values,Policy_Function(:, z_indices(z_index), number_of_iterations)') 79 | end 80 | plot(k_values, k_values, '--', Color='k') 81 | hold off 82 | xlabel('k') 83 | ylabel('g(k,z)') 84 | title('Policy Function') 85 | lgd = legend([string(round(z_values(z_indices), 2))], 'Location', 'northwest'); 86 | lgd.Title.String = "z values"; -------------------------------------------------------------------------------- /2 - Stochastic Growth/R/custom_functions.R: -------------------------------------------------------------------------------- 1 | # Function to solve the household's problem for a given starting state. 2 | # Two different versions with increasing levels of performance. 3 | # Each version has identical inputs and outputs. 4 | # 5 | # Input: 6 | # - Current value function 7 | # - Starting capital and productivity level 8 | # 9 | # Output: 10 | # - Next value function value 11 | # - Optimal choice of next period capital 12 | # 13 | # Version 14 | # v1: using only base functions + for-loops 15 | # v2: using broadcast/vectorized calculation instead of for-loop 16 | 17 | # ----------------------------------------------------------------------------------------------------- 18 | # Version 1 - using only base functions + for-loops. 19 | # ----------------------------------------------------------------------------------------------------- 20 | Solve_HH_Problem_v1 = function(Value_Function, kt0_index, zt_index, params) 21 | { 22 | # Unpack utility parameters and grids. 23 | alpha = params$alpha 24 | beta = params$beta 25 | delta = params$delta 26 | k_values = params$k_values 27 | z_values = params$z_values 28 | z_probs = params$z_probs 29 | 30 | # Get starting capital and productivity values from index. 31 | kt0 = k_values[kt0_index] 32 | zt = z_values[zt_index] 33 | 34 | # Variables to store candidate optimal values for Value Function and Policy Function. 35 | v_max = -Inf 36 | kt1_optimal = 0 37 | 38 | for (kt1_index in 1:number_of_k_values) 39 | { 40 | # Get capital value from index. 41 | kt1 = k_values[kt1_index] 42 | 43 | # Calculate value function for given choice of next period capital. 44 | #new_value_function_value = log(zt * (kt0 ^ alpha) + (1 - delta) * kt0 - kt1) 45 | # + beta*(Value_Function[kt1_index, ] %*% z_probs[zt_index, ]) 46 | new_value_function_value = log(zt * (kt0 ^ alpha) + (1 - delta) * kt0 - kt1) 47 | + beta * sum(Value_Function[kt1_index, ] * z_probs[zt_index, ]) 48 | 49 | # Check if this capital choice gives the highest Value Function value. 50 | if (new_value_function_value > v_max) 51 | { 52 | # Update candidate values. 53 | v_max = new_value_function_value 54 | kt1_optimal = kt1 55 | } 56 | } 57 | return(list(v_max=v_max, kt1_optimal=kt1_optimal)) 58 | } 59 | 60 | # ----------------------------------------------------------------------------------------------------- 61 | # Version 2 - using broadcast/vectorized calculation instead of for-loop. 62 | # ----------------------------------------------------------------------------------------------------- 63 | Iterate_Value_Function_v2 = function(Previous_Value_Function, kt0_index, zt_index, params) 64 | { 65 | # Unpack utility parameters and grids. 66 | alpha = params$alpha 67 | beta = params$beta 68 | delta = params$delta 69 | k_values = params$k_values 70 | z_values = params$z_values 71 | z_probs = params$z_probs 72 | 73 | # Get capital and productivity values from index. 74 | kt0 = k_values[kt0_index] 75 | zt = z_values[zt_index] 76 | 77 | # Calculate array of value function values for all next period capital choices. 78 | V_max_values = log(zt * (kt0 ^ alpha) + (1 - delta) * kt0 - k_values) + 79 | beta * drop(Previous_Value_Function %*% z_probs[zt_index, ]) 80 | 81 | # Get the index for the optimal capital choice. 82 | kt1_index_optimal = which.max(V_max_values) 83 | 84 | # Get the optimal Value Function and Policy Function values. 85 | kt1_optimal = k_values[kt1_index_optimal] 86 | v_max = V_max_values[kt1_index_optimal] 87 | 88 | return(list(v_max=v_max, kt1_optimal=kt1_optimal)) 89 | } -------------------------------------------------------------------------------- /2 - Stochastic Growth/Julia/custom_functions.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Function to solve the household's problem for a given starting state. 3 | Two different versions with increasing levels of performance. 4 | Each version has identical inputs and outputs. 5 | 6 | Input: 7 | - Current value function 8 | - Starting capital and productivity level 9 | 10 | Output: 11 | - Next value function value 12 | - Optimal choice of next period capital 13 | 14 | Version 15 | v1: using only base functions + for-loops 16 | v2: using broadcast/vectorized calculation instead of for-loop 17 | =# 18 | 19 | module iteration_functions 20 | export Solve_HH_Problem_v1, Solve_HH_Problem_v2 21 | using LinearAlgebra 22 | 23 | # ----------------------------------------------------------------------------------------------------- 24 | # Version 1 - using only base functions + for-loops. 25 | # ----------------------------------------------------------------------------------------------------- 26 | function Solve_HH_Problem_v1(Value_Function, kt0_index, zt_index, params) 27 | 28 | # Unpack utility parameters and grids. 29 | α, β, δ = params.α, params.β, params.δ; 30 | k_values = params.k_values; 31 | z_values = params.z_values; 32 | z_probs = params.z_probs; 33 | 34 | # Get starting capital and productivity values from index. 35 | kt0 = k_values[kt0_index]; 36 | zt = z_values[zt_index]; 37 | 38 | # Variables to store candidate optimal values for the Value Function and Policy Function. 39 | v_max = -Inf; 40 | kt1_optimal = 0.0; 41 | 42 | # Check all possible next period capital choices. 43 | for kt1_index in eachindex(k_values) 44 | 45 | # Get capital value from index. 46 | kt1 = k_values[kt1_index]; 47 | 48 | # Calculate the Value Function for given starting capital and next period capital choice. 49 | @views new_v_max = log(zt * (kt0 ^ α) + (1 - δ) * kt0 - kt1) + β * dot(Value_Function[kt1_index, :], z_probs[zt_index, :]); 50 | 51 | # Check if this capital choice gives the highest Value Function value. 52 | if new_v_max > v_max 53 | 54 | # Update candidate values. 55 | v_max = new_v_max; 56 | kt1_optimal = kt1; 57 | end 58 | end 59 | 60 | return v_max, kt1_optimal; 61 | end 62 | 63 | # ----------------------------------------------------------------------------------------------------- 64 | # Version 2 - using broadcast/vectorized calculation instead of for-loop. 65 | # ----------------------------------------------------------------------------------------------------- 66 | function Solve_HH_Problem_v2(Value_Function, kt0_index, zt_index, params) 67 | 68 | # Unpack utility parameters and grids. 69 | α,β,δ = params.α, params.β, params.δ; 70 | k_values = params.k_values; 71 | z_values = params.z_values; 72 | z_probs = params.z_probs; 73 | 74 | # Get capital and productivity values from index. 75 | kt0 = k_values[kt0_index]; 76 | zt = z_values[zt_index]; 77 | 78 | # Calculate array of value function values for all next period capital choices. 79 | @views V_max_values = log.(zt * (kt0 ^ α) + (1 - δ) * kt0 .- k_values) + β * (Value_Function * z_probs[zt_index, :]); 80 | 81 | # Get index for the optimal capital choice. 82 | kt1_index_optimal = argmax(V_max_values); 83 | 84 | # Get the optimal Value Function and Policy Function values. 85 | kt1_optimal = k_values[kt1_index_optimal]; 86 | v_max = V_max_values[kt1_index_optimal]; 87 | 88 | return v_max, kt1_optimal; 89 | end 90 | 91 | 92 | # Benchmarking 93 | #using BenchmarkTools 94 | #@btime Solve_HH_Problem_v1(Value_Function, kt0_index, zt_index, params); # 49.3 μs 95 | #@btime Solve_HH_Problem_v2(Value_Function, kt0_index, zt_index, params); # 6.1 μs 96 | 97 | end # end module -------------------------------------------------------------------------------- /Extra content/Julia performance profiling/2 - Stochastic Growth/custom_functions.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Function to solve the household's problem for a given starting state. 3 | Two different versions with increasing levels of performance. 4 | Each version has identical inputs and outputs. 5 | 6 | Input: 7 | - Current value function 8 | - Starting capital and productivity level 9 | 10 | Output: 11 | - Next value function value 12 | - Optimal choice of next period capital 13 | 14 | Version 15 | v1: using only base functions + for-loops 16 | v2: using broadcast/vectorized calculation instead of for-loop 17 | =# 18 | 19 | module custom_functions 20 | export Solve_HH_Problem_v1, Solve_HH_Problem_v2 21 | using LinearAlgebra 22 | 23 | # ----------------------------------------------------------------------------------------------------- 24 | # Version 1 - using only base functions + for-loops. 25 | # ----------------------------------------------------------------------------------------------------- 26 | function Solve_HH_Problem_v1(Value_Function, kt0_index, zt_index, params) 27 | 28 | # Unpack utility parameters and grids. 29 | α, β, δ = params.α, params.β, params.δ; 30 | k_values = params.k_values; 31 | z_values = params.z_values; 32 | z_probs = params.z_probs; 33 | 34 | # Get starting capital and productivity values from index. 35 | kt0 = k_values[kt0_index]; 36 | zt = z_values[zt_index]; 37 | 38 | # Variables to store candidate optimal values for the Value Function and Policy Function. 39 | v_max = -Inf; 40 | kt1_optimal = 0.0; 41 | 42 | # Check all possible next period capital choices. 43 | for kt1_index in eachindex(k_values) 44 | 45 | # Get capital value from index. 46 | kt1 = k_values[kt1_index]; 47 | 48 | # Calculate the Value Function for given starting capital and next period capital choice. 49 | @views new_v_max = log(zt * (kt0 ^ α) + (1 - δ) * kt0 - kt1) + 50 | β * dot(Value_Function[kt1_index, :], z_probs[zt_index, :]); 51 | 52 | # Check if this capital choice gives the highest Value Function value. 53 | if new_v_max > v_max 54 | 55 | # Update candidate values. 56 | v_max = new_v_max; 57 | kt1_optimal = kt1; 58 | end 59 | end 60 | 61 | return v_max, kt1_optimal; 62 | end 63 | 64 | # ----------------------------------------------------------------------------------------------------- 65 | # Version 2 - using broadcast/vectorized calculation instead of for-loop. 66 | # ----------------------------------------------------------------------------------------------------- 67 | function Solve_HH_Problem_v2(Value_Function, kt0_index, zt_index, params) 68 | 69 | # Unpack utility parameters and grids. 70 | α,β,δ = params.α, params.β, params.δ; 71 | k_values = params.k_values; 72 | z_values = params.z_values; 73 | z_probs = params.z_probs; 74 | 75 | # Get capital and productivity values from index. 76 | kt0 = k_values[kt0_index]; 77 | zt = z_values[zt_index]; 78 | 79 | # Calculate array of value function values for all next period capital choices. 80 | @views V_max_values = log.((zt * (kt0 ^ α) + (1 - δ) * kt0) .- k_values) + β * (Value_Function * z_probs[zt_index, :]); 81 | 82 | # Get index for the optimal capital choice. 83 | kt1_index_optimal = argmax(V_max_values); 84 | 85 | # Get the optimal Value Function and Policy Function values. 86 | kt1_optimal = k_values[kt1_index_optimal]; 87 | v_max = V_max_values[kt1_index_optimal]; 88 | 89 | return v_max, kt1_optimal; 90 | end 91 | 92 | 93 | # Benchmarking 94 | #using BenchmarkTools 95 | #@btime Solve_HH_Problem_v1(Value_Function, kt0_index, zt_index, params); # 49.3 μs 96 | #@btime Solve_HH_Problem_v2(Value_Function, kt0_index, zt_index, params); # 6.1 μs 97 | 98 | end # end module -------------------------------------------------------------------------------- /2 - Stochastic Growth/c++/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stochastic Growth Model implemented in C++. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Perform value function iteration. 7 | 3 - Display results, save results to file, clean up. 8 | */ 9 | 10 | #include "custom_functions.h" 11 | #include 12 | #include 13 | #include 14 | 15 | int main() 16 | { 17 | // Assign parameter values. 18 | double alpha = 0.400; 19 | double beta = 0.987; 20 | double delta = 0.012; 21 | int const number_of_iterations = 1000; 22 | 23 | // Calculate the steady-state level of capital. 24 | double k_steady = pow(((1 - beta * (1 - delta)) / (alpha * beta)), (1 / (alpha - 1))); 25 | 26 | // Create a grid of capital values around the steady-state (+/- 2%). 27 | int const number_of_k_values = 201; 28 | double k_low_pct = 0.98; 29 | double k_high_pct = 1.02; 30 | vector k_values(number_of_k_values); 31 | 32 | for (int i = 0; i < number_of_k_values; i++) 33 | { 34 | k_values[i] = k_low_pct * k_steady + (double(i) / (double(number_of_k_values) - 1)) * ((k_high_pct - k_low_pct) * k_steady); 35 | } 36 | 37 | // Get productivity levels and transition probabilities from csv files (as vector arrays). 38 | std::string directory = "C:/Users/Ray/Documents/GitHub/DSGE-models/2 - Stochastic Growth/c++/Inputs/"; 39 | Array2D z_probs = ReadArrayFromCSV(directory + "z_probs.csv"); 40 | vector z_values = ReadVectorFromCSV(directory + "z_values.csv"); 41 | int number_of_z_values = z_values.size(); 42 | 43 | // Initialize the Value Function and Policy Function (as arrays). 44 | Array3D Value_Function(number_of_iterations, vector>(number_of_k_values, vector (number_of_z_values))); 45 | Array3D Policy_Function(number_of_iterations, vector>(number_of_k_values, vector(number_of_z_values))); 46 | 47 | // Assign value of 0 to first iteration. 48 | for (int i = 0; i < number_of_k_values; i++) 49 | { 50 | for (int j = 0; j < number_of_z_values; j++) 51 | { 52 | Value_Function[0][i][j] = 0.0; 53 | Policy_Function[0][i][j] = 0.0; 54 | } 55 | } 56 | 57 | // Store utility parameters and capital/productivity grids in a struct for passing to a function. 58 | Parameters params = { alpha, beta, delta, number_of_k_values, number_of_z_values, k_values, z_values, z_probs }; 59 | 60 | // Perform value function iteration. 61 | for (int iteration = 1; iteration < number_of_iterations; iteration++) 62 | { 63 | // Run the following for-loop in parallel if OpenMP is enabled. 64 | #pragma omp parallel for 65 | 66 | // Loop over all possible starting states. 67 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 68 | { 69 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 70 | { 71 | // Solve the Value Function and Policy Function. 72 | Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params); 73 | } 74 | } 75 | } 76 | 77 | // Get slice of Value Function and Policy Function for final iteration. 78 | Array2D Final_Value_Function(number_of_k_values, vector(number_of_z_values)); 79 | Array2D Final_Policy_Function(number_of_k_values, vector(number_of_z_values)); 80 | 81 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 82 | { 83 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 84 | { 85 | Final_Value_Function[kt0_index][zt_index] = Value_Function[number_of_iterations - 1][kt0_index][zt_index]; 86 | Final_Policy_Function[kt0_index][zt_index] = Policy_Function[number_of_iterations - 1][kt0_index][zt_index]; 87 | } 88 | } 89 | 90 | // Write final Value Function and Policy Function to csv files. 91 | WriteArrayToCSV(Final_Value_Function, number_of_k_values, number_of_z_values, "Value_Function.csv"); 92 | WriteArrayToCSV(Final_Policy_Function, number_of_k_values, number_of_z_values, "Policy_Function.csv"); 93 | 94 | // Display a subset of results: the final Value Function for certain capital and prodcutivity values. 95 | for (int kt0_index = 0; kt0_index < 10; kt0_index++) 96 | { 97 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 98 | { 99 | std::cout << Value_Function[number_of_iterations - 1][kt0_index][zt_index] << "\t"; 100 | } 101 | std::cout << "\n"; 102 | } 103 | 104 | std::cin.get(); 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Matlab/main.m: -------------------------------------------------------------------------------- 1 | % Idiosyncratic Endowment model implemented in Matlab. 2 | % 3 | % Steps: 4 | % 1 - Define utility parameters, grids, and parameter struct. 5 | % 2 - Solve model and get market bond price using binary search. 6 | % - Guess bond price 7 | % - Solve for the Value Function and Policy Function 8 | % - Get the distribution of credit and productivity levels 9 | % - Check the market clearing condition and update bond price guess 10 | % 3 - Plot results. 11 | 12 | %% 1 - Define utility parameters, grids, and parameter struct. 13 | tic 14 | % Endowment parameters. 15 | e_high = 1.0; % high endowment 16 | e_low = 0.1; % low endowment 17 | e_grid = [e_low, e_high]; % endowment grid 18 | number_of_e_values = 2; 19 | e_probs = [0.500 0.500 ; 0.075 0.925]; % transition probabilities 20 | 21 | % Utility parameters. 22 | sigma = 1.5; % risk aversion coefficient 23 | beta = 0.99322; % discount factor 24 | 25 | % Credit parameters. 26 | a_high = 4; % upper credit limit 27 | a_low = -2; % lower credit limit / borrowing constraint 28 | number_of_a_values = 100; % credit grid size 29 | a_grid = linspace(a_low, a_high, number_of_a_values); % credit grid 30 | 31 | % Store parameters in a struct for passing to a function. 32 | params = struct(... 33 | sigma=sigma, beta=beta, ... 34 | a_grid=a_grid, e_grid=e_grid, e_probs=e_probs, ... 35 | number_of_a_values=number_of_a_values, ... 36 | number_of_e_values=number_of_e_values); 37 | 38 | %% 2 - Solve model and get market bond price using binary search. 39 | 40 | % Range of bond price values to search. 41 | q_min = 0.985; 42 | q_max = 1.100; 43 | 44 | % Optional: floor for q_min such that those at credit limit can still afford positive consumption. 45 | q_min = (a_low + e_low) / a_low; 46 | 47 | % Placeholder for the market clearing condition. 48 | mcc = Inf; 49 | 50 | % Iteration parameters. 51 | dist = Inf; 52 | iteration_count = 0; 53 | max_iterations = 20; 54 | tolerance = 1e-3; 55 | 56 | % Solve for market price q. 57 | while (dist > tolerance) & (iteration_count < max_iterations) 58 | 59 | % Get value of q from middle of range. 60 | q = (q_min + q_max)/2; 61 | 62 | % Solve for the Value Function and Policy Function. 63 | [Value_Function, Policy_Function, Policy_Function_Index] = Solve_Value_Function(q, params); 64 | 65 | % Get the Population Distribution. 66 | Population_Distribution = Get_Population_Distribution(Policy_Function_Index, params); 67 | 68 | % Check the market clearing condition. 69 | mcc = sum(Policy_Function .* Population_Distribution, 'all'); 70 | 71 | % Update search parameters. 72 | dist = abs(mcc); 73 | iteration_count = iteration_count + 1; 74 | 75 | % Update range of q according to the sign of the market clearing condition. 76 | if mcc > 0; q_min = q; end 77 | if mcc < 0; q_max = q; end 78 | 79 | % Print results. 80 | fprintf("Iteration %d: q=%f, mcc=%f \n", iteration_count, round(q,6), round(mcc,6)); 81 | if iteration_count >= max_iterations; fprintf("Warning: search for q did not converge after %d iterations \n", iteration_count); end 82 | end 83 | 84 | %% Plot Results 85 | 86 | % Policy functions (Figure 1. from Hugget 1993). 87 | figure(1) 88 | hold on 89 | plot(a_grid, Policy_Function(:, 2)) 90 | plot(a_grid, Policy_Function(:, 1)) 91 | plot(a_grid, a_grid, '--', Color='k') 92 | hold off 93 | xlabel("starting credit level") 94 | ylabel("optimal new credit level") 95 | title("Policy Function") 96 | legend(["high endowment", "low endowment", "45-degree line"], 'Location', 'southeast') 97 | 98 | % Distribution of credit levels (Figure 2. from Huggett 1993). 99 | figure(2) 100 | hold on 101 | plot(a_grid, cumsum(Population_Distribution(:, 2))) 102 | plot(a_grid, cumsum(Population_Distribution(:, 1))) 103 | hold off 104 | xlim([-2, 1]) 105 | ylim([0, 1]) 106 | xlabel("starting credit level") 107 | title("Cumulative Distribution Function for Credit Level") 108 | legend(["high endowment", "low endowment"], 'Location', 'northwest') 109 | 110 | toc -------------------------------------------------------------------------------- /Extra content/Fortran project template/src/main.f08: -------------------------------------------------------------------------------- 1 | ! Stochastic Growth Model implemented in Fortran (2008). 2 | 3 | ! Steps: 4 | ! 1 - Define utility parameters, grids, and parameter struct. 5 | ! 2 - Perform value function iteration. 6 | ! 3 - Display results, save results to file, clean up. 7 | 8 | program main 9 | 10 | use custom_functions 11 | implicit none 12 | 13 | ! --------------------------------------------------------------------------------------------------- 14 | ! Declaration section. 15 | 16 | ! Double precision parameter values. 17 | real(8), parameter :: alpha = 0.400 18 | real(8), parameter :: beta = 0.987 19 | real(8), parameter :: delta = 0.012 20 | real(8) :: k_steady, k_pct_low, k_pct_high 21 | 22 | ! Integer variables. 23 | integer, parameter :: number_of_iterations = 1000 24 | integer, parameter :: number_of_k_values = 201 25 | integer, parameter :: number_of_z_values = 11 26 | integer :: i, iteration, kt0_index, zt_index 27 | 28 | ! Value Function, Policy Function, and other arrays. 29 | real(8), allocatable :: Value_Function(:,:,:), Policy_Function(:,:,:) 30 | real(8), dimension(number_of_k_values) :: k_values 31 | real(8), dimension(number_of_z_values) :: z_values 32 | real(8), dimension(number_of_z_values, number_of_z_values) :: z_probs 33 | 34 | ! Struct to store utility parameters and capital/productivity grids for passing to a function. 35 | type(Parameters) :: params 36 | 37 | ! Allocate memory for allocatable arrays. 38 | allocate(Value_Function(number_of_z_values, number_of_k_values, number_of_iterations)) 39 | allocate(Policy_Function(number_of_z_values, number_of_k_values, number_of_iterations)) 40 | 41 | ! --------------------------------------------------------------------------------------------------- 42 | ! Execution section. 43 | 44 | ! Calculate the steady-state level of capital. 45 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ** (1 / (alpha - 1)) 46 | 47 | ! Create a grid of capital values around the steady-state (+/- 2%). 48 | k_pct_low = 0.98 49 | k_pct_high = 1.02 50 | 51 | do i = 1, number_of_k_values 52 | k_values(i) = k_steady * (k_pct_low + ((real(i, 8) - 1) / real(number_of_k_values, 8) * (k_pct_high - k_pct_low))) 53 | end do 54 | 55 | ! Assign value of 0 to first value function iteration. 56 | where (Value_Function /= 0.0) Value_Function = 0 57 | where (Policy_Function /= 0.0) Policy_Function = 0 58 | 59 | ! Get productivity levels and transition probabilities from csv files. 60 | call ReadVectorFromCSV("Inputs\z_values.csv", number_of_z_values, z_values) 61 | call ReadArrayFromCSV("Inputs\z_probs.csv", number_of_z_values, number_of_z_values, z_probs) 62 | 63 | ! Store utility parameters and capital/productivity grids in a struct for passing to a function. 64 | params = Parameters(alpha, beta, delta, number_of_k_values, number_of_z_values, k_values, z_values, z_probs) 65 | 66 | ! Perform value function iteration. 67 | do iteration = 2, number_of_iterations 68 | 69 | ! Loop over all possible starting states. 70 | do kt0_index = 1, number_of_k_values 71 | do zt_index = 1, number_of_z_values 72 | 73 | ! Solve the Value Function and Policy Function. 74 | call Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params) 75 | end do 76 | end do 77 | end do 78 | 79 | ! Write the final Value Function and Policy Function to csv files. 80 | call WriteArrayToCSV(transpose(Value_Function(:,:,number_of_iterations)), & 81 | number_of_k_values, number_of_z_values, "Value_Function.csv") 82 | call WriteArrayToCSV(transpose(Policy_Function(:,:,number_of_iterations)), & 83 | number_of_k_values, number_of_z_values, "Policy_Function.csv") 84 | 85 | ! Display a subset of results: the final Value Function for certain capital and productivity values. 86 | do kt0_index = 1, 10 87 | do zt_index = 1, 10 88 | write(*, '(4x, f7.3)', advance='no') Value_Function(zt_index, kt0_index, number_of_iterations) 89 | end do 90 | write(*,*) NEW_LINE('A') 91 | end do 92 | call sleep(100) 93 | 94 | end program 95 | 96 | ! Compilier instructions. 97 | ! debug mode: gfortran src/custom_functions.f08 src/main.f08 -g -O0 -Wall -o start build.exe 98 | ! release mode: gfortran src/custom_functions.f08 src/main.f08 -O3 -o start build.exe 99 | ! run program: start build -------------------------------------------------------------------------------- /1 - Base Model/cpp.cpp: -------------------------------------------------------------------------------- 1 | // Base Model implementation in C++. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Declarations. 11 | using std::vector; 12 | void WriteArrayToCSV(vector> Array2D, const char* file_name); 13 | 14 | int main() 15 | { 16 | // Assign parameter values. 17 | double alpha = 0.400; 18 | double beta = 0.987; 19 | double delta = 1.000; 20 | int const number_of_iterations = 1000; 21 | 22 | // Calculate the steady-state level of capital. 23 | double k_steady = pow(((1 - beta * (1 - delta)) / (alpha * beta)), (1 / (alpha - 1))); // pow(base, exponent) = base^exponent 24 | 25 | // Create grid of capital values around the steady-state (+/- 50%). 26 | int const number_of_k_values = 201; 27 | double k_low_pct = 0.50; 28 | double k_high_pct = 1.50; 29 | double k_values[number_of_k_values]; 30 | 31 | for (int i = 0; i < number_of_k_values; i++) 32 | { 33 | k_values[i] = k_steady * (k_low_pct + ((double(i) / (double(number_of_k_values) - 1)) * (k_high_pct - k_low_pct))); 34 | } 35 | 36 | // Initialize the Value Function and Policy Function (as arrays). 37 | vector> Value_Function(number_of_iterations, vector(number_of_k_values, 0)); 38 | vector> Policy_Function(number_of_iterations, vector(number_of_k_values, 0)); 39 | 40 | // Solve the household's problem for each possible starting state. 41 | for (int iteration = 1; iteration < number_of_iterations; iteration++) 42 | { 43 | for (int kt0_ind = 0; kt0_ind < number_of_k_values; kt0_ind++) 44 | { 45 | // Variables to store candidate optimal values. 46 | double v_max = -DBL_MAX; 47 | double kt1_optimal = 0.0; 48 | double new_value_function_value; 49 | 50 | for (int kt1_ind = 0; kt1_ind < number_of_k_values; kt1_ind++) 51 | { 52 | // Calculate the Value Function for given starting capital and next period capital choice. 53 | new_value_function_value = log(pow(k_values[kt0_ind], alpha) - k_values[kt1_ind] + (1 - delta) * k_values[kt0_ind]) + 54 | + beta * Value_Function[iteration - 1][kt1_ind]; 55 | 56 | // Check if this capital choice gives highest Value Function value. 57 | if (new_value_function_value > v_max) 58 | { 59 | // Update candidate values. 60 | v_max = new_value_function_value; 61 | kt1_optimal = k_values[kt1_ind]; 62 | } 63 | } 64 | 65 | // Update the Value Function and Policy Function with optimal values. 66 | Value_Function[iteration][kt0_ind] = v_max; 67 | Policy_Function[iteration][kt0_ind] = kt1_optimal; 68 | } 69 | } 70 | 71 | // Write Value Function and Policy Function to csv files. 72 | WriteArrayToCSV(Value_Function, "Value_Function.csv"); 73 | WriteArrayToCSV(Policy_Function, "Policy_Function.csv"); 74 | 75 | // Display the first and last 5 values of the Value Function and Policy Function. 76 | for (int i = 0; i < 5; i++) 77 | { 78 | if (i == 0) { std::cout << "Value Function V(k):" << "\n"; }; 79 | std::cout << "V(" << k_values[i] << ") = " << Value_Function[number_of_iterations - 1][i] << "\n"; 80 | } 81 | std::cout << "..." << "\n"; 82 | for (int i = number_of_k_values - 5; i < number_of_k_values; i++) 83 | { 84 | std::cout << "V(" << k_values[i] << ") = " << Value_Function[number_of_iterations - 1][i] << "\n"; 85 | } 86 | 87 | for (int i = 0; i < 5; i++) 88 | { 89 | if (i == 0) { std::cout << "\n" << "Policy Function g(k):" << "\n"; }; 90 | std::cout << "g(" << k_values[i] << ") = " << Policy_Function[number_of_iterations - 1][i] << "\n"; 91 | } 92 | std::cout << "..." << "\n"; 93 | for (int i = number_of_k_values - 5; i < number_of_k_values; i++) 94 | { 95 | std::cout << "g(" << k_values[i] << ") = " << Policy_Function[number_of_iterations - 1][i] << "\n"; 96 | } 97 | 98 | // Leave window open after program terminates. 99 | std::cin.get(); 100 | return 0; 101 | } 102 | 103 | // Function to write a 2-dimensional array to csv file. 104 | void WriteArrayToCSV(vector> Array2D, const char* file_name) 105 | { 106 | int n_rows = Array2D.size(); 107 | int n_cols = Array2D[0].size(); 108 | 109 | std::ofstream write_output(file_name); 110 | assert(write_output.is_open()); 111 | 112 | for (int i = 0; i < n_rows; i++) 113 | { 114 | for (int j = 0; j < n_cols; j++) 115 | { 116 | write_output << Array2D[i][j] << ","; 117 | } 118 | write_output << "\n"; 119 | } 120 | write_output.close(); 121 | } 122 | -------------------------------------------------------------------------------- /Extra content/C++ implementation using C-style base arrays/2 - Stochastric Growth/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stochastic Growth Model implemented in c++. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Perform value function iteration. 7 | 3 - Display results, save results to file, clean up. 8 | 9 | Relies on Solve_Value_Function and helper functions in custom_funcions file. 10 | */ 11 | 12 | #include "custom_functions.h" 13 | #include 14 | #include 15 | #include 16 | 17 | int main() 18 | { 19 | // Assign parameter values. 20 | double alpha = 0.400; 21 | double beta = 0.987; 22 | double delta = 0.012; 23 | int const number_of_iterations = 1000; 24 | 25 | // Calculate the steady-state level of capital. 26 | double k_steady = pow(((1 - beta * (1 - delta)) / (alpha * beta)), (1 / (alpha - 1))); 27 | 28 | // Create a grid of capital values around steady-state (+/- 2%). 29 | int const number_of_k_values = 201; 30 | double k_low_pct = 0.98; 31 | double k_high_pct = 1.02; 32 | double k_values[number_of_k_values]; 33 | 34 | for (int i = 0; i < number_of_k_values; i++) 35 | { 36 | k_values[i] = k_low_pct * k_steady + (double(i) / (double(number_of_k_values) - 1)) * ((k_high_pct - k_low_pct) * k_steady); 37 | } 38 | 39 | // Get productivity levels and transition probabilities from csv files (as vector arrays). 40 | std::string directory = "C:/Users/Ray/Documents/GitHub/DSGE-models/2 - Stochastic Growth/c++/Inputs/"; 41 | double* z_values = ReadVectorFromCSV(directory + "z_values.csv"); 42 | double** z_probs = ReadArrayFromCSV(directory + "z_probs.csv"); 43 | int const number_of_z_values = 11; 44 | 45 | // Initialize Value Function and Policy Function (as arrays). 46 | double*** Value_Function = InitializeArray3D(number_of_iterations, number_of_k_values, number_of_z_values); 47 | double*** Policy_Function = InitializeArray3D(number_of_iterations, number_of_k_values, number_of_z_values); 48 | 49 | // Assign value of 0 to first iteration. 50 | for (int i = 0; i < number_of_k_values; i++) 51 | { 52 | for (int j = 0; j < number_of_z_values; j++) 53 | { 54 | Value_Function[0][i][j] = 0.0; 55 | Policy_Function[0][i][j] = 0.0; 56 | } 57 | } 58 | 59 | // Store utility parameters and capital/productivity grids in a struct for passing to a function. 60 | Parameters params = { alpha, beta, delta, number_of_k_values, number_of_z_values, k_values, z_values, z_probs }; 61 | 62 | // Perform value function iteration. 63 | for (int iteration = 1; iteration < number_of_iterations; iteration++) 64 | { 65 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 66 | { 67 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 68 | { 69 | // Solve Value Function and Policy Function. 70 | Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params); 71 | } 72 | } 73 | } 74 | 75 | // Get slice of Value Function and Policy Function for final iteration. 76 | double** Final_Value_Function = InitializeArray2D(number_of_k_values, number_of_z_values); 77 | double** Final_Policy_Function = InitializeArray2D(number_of_k_values, number_of_z_values); 78 | 79 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 80 | { 81 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 82 | { 83 | Final_Value_Function[kt0_index][zt_index] = Value_Function[number_of_iterations - 1][kt0_index][zt_index]; 84 | Final_Policy_Function[kt0_index][zt_index] = Policy_Function[number_of_iterations - 1][kt0_index][zt_index]; 85 | } 86 | } 87 | 88 | // Write final Value Function and Policy Function to csv files. 89 | WriteArrayToCSV(Final_Value_Function, number_of_k_values, number_of_z_values, "Value_Function.csv"); 90 | WriteArrayToCSV(Final_Policy_Function, number_of_k_values, number_of_z_values, "Policy_Function.csv"); 91 | 92 | // Display subset of results: final Value Function for certain capital and prodcutivity values. 93 | for (int kt0_index = 0; kt0_index < 10; kt0_index++) 94 | { 95 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 96 | { 97 | std::cout << Value_Function[number_of_iterations - 1][kt0_index][zt_index] << "\t"; 98 | } 99 | std::cout << "\n"; 100 | } 101 | 102 | // Remove arrays from memory. 103 | DeleteArray3D(Value_Function, number_of_iterations, number_of_k_values, number_of_z_values); 104 | DeleteArray3D(Policy_Function, number_of_iterations, number_of_k_values, number_of_z_values); 105 | DeleteArray2D(Final_Value_Function, number_of_k_values, number_of_z_values); 106 | DeleteArray2D(Final_Policy_Function, number_of_k_values, number_of_z_values); 107 | std::cin.get(); 108 | return 0; 109 | } -------------------------------------------------------------------------------- /Extra content/Julia performance profiling/2 - Stochastic Growth/main.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Stochastic Growth model implemented in Julia. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Create a function to solve the household's problem for a given starting state. 7 | 3 - Perform value function iteration. 8 | 4 - Plot results. 9 | =# 10 | 11 | # Import modules and declare struct. 12 | using DelimitedFiles 13 | using Plots 14 | cd("C:\\Users\\Ray\\Documents\\GitHub\\DSGE-models\\Extra content\\Julia performance profiling\\2 - Stochastic Growth") 15 | include("custom_functions.jl") 16 | using .custom_functions 17 | 18 | # Store utility parameters and capital/productivity grids in a struct for passing to a function. 19 | struct Parameters 20 | α::Float64 21 | β::Float64 22 | δ::Float64 23 | k_values::Array{Float64, 1} # == Vector{Float64} 24 | z_values::Array{Float64, 1} # == Vector{Float64} 25 | z_probs::Array{Float64, 2} # == Matrix{Float64} 26 | end 27 | 28 | 29 | function main() 30 | # ----------------------------------------------------------------------------------------------------- 31 | # 1 - Define utility parameters, grids, and parameter struct. 32 | # ----------------------------------------------------------------------------------------------------- 33 | # Assign parameter values. 34 | α = 0.400; 35 | β = 0.987; 36 | δ = 0.012; 37 | number_of_iterations = 1000; 38 | 39 | # Calculate the steady-state level of capital. 40 | k_steady = ((1 - β * (1 - δ)) / (α * β)) ^ (1 / (α - 1)) 41 | 42 | # Create a range of capital values around the steady-state (+/- 50%). 43 | number_of_k_values = 201; 44 | k_low_pct = 0.98; 45 | k_high_pct = 1.02; 46 | k_values = collect(range(k_low_pct * k_steady, k_high_pct * k_steady, length=number_of_k_values)); 47 | 48 | # Get productivity levels and transition probabilities. 49 | z_probs = readdlm("Inputs\\z_probs.csv", ',', Float64); 50 | z_values = readdlm("Inputs\\z_values.csv", ',', Float64)[:, 1]; 51 | number_of_z_values = size(z_values, 1); 52 | 53 | # Initialize the Value Function and Policy Function (as arrays). 54 | Value_Function = zeros(number_of_iterations, number_of_k_values, number_of_z_values); 55 | Policy_Function = zeros(number_of_iterations, number_of_k_values, number_of_z_values); 56 | 57 | params = Parameters(α, β, δ, k_values, z_values, z_probs); 58 | 59 | # ----------------------------------------------------------------------------------------------------- 60 | # 3 - Perform value function iteration. 61 | # ----------------------------------------------------------------------------------------------------- 62 | for iteration in 2:number_of_iterations 63 | 64 | # Loop over all possible starting states. 65 | #for kt0_index in eachindex(k_values), zt_index in eachindex(z_values) # single-thread implementation 66 | Threads.@threads for zt_index in eachindex(z_values) # multi-thread implementation 67 | for kt0_index in eachindex(k_values) # multi-thread implementation 68 | 69 | # Solve the Value Function and Policy Function and update values. 70 | @views V, g = Solve_HH_Problem_v1(Value_Function[iteration-1, :, :], kt0_index, zt_index, params); 71 | #@views V, g = Solve_HH_Problem_v2(Value_Function[iteration-1, :, :], kt0_index, zt_index, params); 72 | 73 | Value_Function[iteration, kt0_index, zt_index] = V; 74 | Policy_Function[iteration, kt0_index, zt_index] = g; 75 | end 76 | end 77 | end 78 | 79 | # ----------------------------------------------------------------------------------------------------- 80 | # 4 - Plot results. 81 | # ----------------------------------------------------------------------------------------------------- 82 | # Plot the Value Function for different starting states. 83 | Figure1 = plot(legendtitle="z value") 84 | for zt_index in eachindex(z_values) 85 | plot!(k_values, Value_Function[number_of_iterations, :, zt_index], label=round(z_values[zt_index], digits=2)) 86 | end 87 | xlabel!("k") 88 | ylabel!("V(k,z)") 89 | title!("Value Function") 90 | display(Figure1) 91 | 92 | # Plot the final Policy Function for certain productivity values. 93 | z_indices = [1,4,6,8,11] 94 | Figure2 = plot(k_values, Policy_Function[number_of_iterations, :, z_indices], label=round.(z_values[z_indices], digits=2)', legend=:topleft, legendtitle="z value") 95 | plot!(k_values,k_values, linestyle=:dash, label="45-degree line", color=:black) 96 | xlabel!("k") 97 | ylabel!("g(k,z)") 98 | title!("Policy Function") 99 | display(Figure2) 100 | 101 | end 102 | 103 | # Benchmarking and profiling. 104 | using Profile 105 | using BenchmarkTools 106 | 107 | @btime main() 108 | @profview main() 109 | # https://www.julia-vscode.org/docs/dev/userguide/profiler/ -------------------------------------------------------------------------------- /2 - Stochastic Growth/Fortran/main.f08: -------------------------------------------------------------------------------- 1 | ! Stochastic Growth Model implemented in Fortran (2008). 2 | 3 | ! Steps: 4 | ! 1 - Define utility parameters, grids, and parameter struct. 5 | ! 2 - Perform value function iteration. 6 | ! 3 - Display results, save results to file, clean up. 7 | 8 | program main 9 | 10 | use custom_functions 11 | implicit none 12 | 13 | ! --------------------------------------------------------------------------------------------------- 14 | ! Declaration section. 15 | 16 | ! Double precision parameter values. 17 | real(8), parameter :: alpha = 0.400 18 | real(8), parameter :: beta = 0.987 19 | real(8), parameter :: delta = 0.012 20 | real(8) :: k_steady, k_pct_low, k_pct_high 21 | 22 | ! Integer variables. 23 | integer, parameter :: number_of_iterations = 1000 24 | integer, parameter :: number_of_k_values = 201 25 | integer, parameter :: number_of_z_values = 11 26 | integer :: i, iteration, kt0_index, zt_index 27 | 28 | ! Value Function, Policy Function, and other arrays. 29 | real(8), allocatable :: Value_Function(:,:,:), Policy_Function(:,:,:) 30 | real(8), dimension(number_of_k_values) :: k_values 31 | real(8), dimension(number_of_z_values) :: z_values 32 | real(8), dimension(number_of_z_values, number_of_z_values) :: z_probs 33 | 34 | ! Struct to store utility parameters and capital/productivity grids for passing to a function. 35 | type(Parameters) :: params 36 | 37 | ! Allocate memory for allocatable arrays. 38 | allocate(Value_Function(number_of_z_values, number_of_k_values, number_of_iterations)) 39 | allocate(Policy_Function(number_of_z_values, number_of_k_values, number_of_iterations)) 40 | 41 | ! --------------------------------------------------------------------------------------------------- 42 | ! Execution section. 43 | 44 | ! Calculate the steady-state level of capital. 45 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ** (1 / (alpha - 1)) 46 | 47 | ! Create a grid of capital values around the steady-state (+/- 2%). 48 | k_pct_low = 0.98 49 | k_pct_high = 1.02 50 | 51 | do i = 1, number_of_k_values 52 | k_values(i) = k_steady * (k_pct_low + ((real(i, 8) - 1) / real(number_of_k_values, 8) * (k_pct_high - k_pct_low))) 53 | end do 54 | 55 | ! Assign value of 0 to first value function iteration. 56 | where (Value_Function /= 0.0) Value_Function = 0 57 | where (Policy_Function /= 0.0) Policy_Function = 0 58 | 59 | ! Get productivity levels and transition probabilities from csv files. 60 | call ReadVectorFromCSV("Inputs\z_values.csv", number_of_z_values, z_values) 61 | call ReadArrayFromCSV("Inputs\z_probs.csv", number_of_z_values, number_of_z_values, z_probs) 62 | 63 | ! Store utility parameters and capital/productivity grids in a struct for passing to a function. 64 | params = Parameters(alpha, beta, delta, number_of_k_values, number_of_z_values, k_values, z_values, z_probs) 65 | 66 | ! Perform value function iteration. 67 | do iteration = 2, number_of_iterations 68 | 69 | ! Run the following do-loop in parallel if OpenMP is enabled. 70 | !$OMP parallel do 71 | 72 | ! Loop over all possible starting states. 73 | do kt0_index = 1, number_of_k_values 74 | do zt_index = 1, number_of_z_values 75 | 76 | ! Solve the Value Function and Policy Function. 77 | call Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params) 78 | end do 79 | end do 80 | 81 | ! Run the above do-loop in parallel if OpenMP is enabled. 82 | !$OMP end parallel do 83 | end do 84 | 85 | ! Write the final Value Function and Policy Function to csv files. 86 | call WriteArrayToCSV(transpose(Value_Function(:,:,number_of_iterations)), & 87 | number_of_k_values, number_of_z_values, "Value_Function.csv") 88 | call WriteArrayToCSV(transpose(Policy_Function(:,:,number_of_iterations)), & 89 | number_of_k_values, number_of_z_values, "Policy_Function.csv") 90 | 91 | ! Display a subset of results: the final Value Function for certain capital and productivity values. 92 | do kt0_index = 1, 10 93 | do zt_index = 1, 10 94 | write(*, '(4x, f7.3)', advance='no') Value_Function(zt_index, kt0_index, number_of_iterations) 95 | end do 96 | write(*,*) NEW_LINE('A') 97 | end do 98 | call sleep(100) 99 | 100 | end program 101 | 102 | ! Compilier instructions. 103 | ! debug mode: gfortran src/custom_functions.f08 src/main.f08 -g -O0 -Wall -fopenmp -o build.exe 104 | ! release mode: gfortran src/custom_functions.f08 src/main.f08 -O3 -fopenmp -o build.exe 105 | ! run program: start build -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/R/main.R: -------------------------------------------------------------------------------- 1 | # Idiosyncratic Endowment model implemented in R. 2 | 3 | # Steps: 4 | # 1 - Define utility parameters, grids, and parameter struct. 5 | # 2 - Solve model and get market bond price using binary search. 6 | # - Guess bond price 7 | # - Solve for the Value Function and Policy Function 8 | # - Get the distribution of credit and productivity levels 9 | # - Check the market clearing condition and update bond price guess 10 | # 3 - Plot results. 11 | 12 | source("custom_functions.R") 13 | 14 | # Endowment parameters. 15 | e_high = 1.0 # high endowment 16 | e_low = 0.1 # low endowment 17 | e_grid = c(e_low, e_high) # endowment grid 18 | number_of_e_values = 2 19 | e_probs = matrix(c(0.500, 0.500, 0.075, 0.925), 20 | byrow=T, ncol=2) # transition probabilities 21 | 22 | # Utility parameters. 23 | sigma = 1.5 # risk aversion coefficient 24 | beta = 0.99322 # discount factor 25 | 26 | # Credit parameters. 27 | a_high = 4 # upper credit limit 28 | a_low = -2 # lower credit limit / borrowing constraint 29 | number_of_a_values = 100 # credit grid size 30 | a_grid = seq(a_low, a_high, length.out=number_of_a_values) # credit grid 31 | 32 | # Store parameters in a named list for passing to a function. 33 | params = list(sigma = sigma, 34 | beta = beta, 35 | a_grid = a_grid, 36 | e_grid = e_grid, 37 | e_probs = e_probs, 38 | number_of_a_values = number_of_a_values, 39 | number_of_e_values = number_of_e_values) 40 | 41 | # ----------------------------------------------------------------------------------------------------- 42 | # 2 - Solve model and get market bond price using binary search. 43 | # ----------------------------------------------------------------------------------------------------- 44 | 45 | # Range of bond price values to search. 46 | q_min = 0.985 47 | q_max = 1.100 48 | 49 | # Optional: floor for q_min such that those at credit limit can still afford positive consumption. 50 | q_min = (a_low + e_low) / a_low 51 | 52 | # Placeholder for the market clearing condition. 53 | mcc = Inf; 54 | 55 | # Iteration parameters. 56 | dist = Inf 57 | iteration_count = 0 58 | max_iterations = 20 59 | tolerance = 1e-3 60 | 61 | # Solve for market price q. 62 | while ((dist > tolerance) & (iteration_count < max_iterations)) 63 | { 64 | # Get value of q from middle of range. 65 | q = (q_min + q_max)/2 66 | 67 | # Solve for the Value Function and Policy Function. 68 | vf_result = Solve_Value_Function(q, params) 69 | 70 | # Get the Population Distribution. 71 | Population_Distribution = Get_Population_Distribution(vf_result$Policy_Function_Index, params) 72 | 73 | # Check the market clearing condition. 74 | mcc = sum(vf_result$Policy_Function * Population_Distribution) 75 | 76 | # Update search parameters. 77 | dist = abs(mcc) 78 | iteration_count = iteration_count + 1 79 | 80 | # Update range of q according to the sign of the market clearing condition. 81 | if (mcc > 0) { q_min = q } 82 | if (mcc < 0) { q_max = q } 83 | 84 | # Print results. 85 | print(sprintf("Iteration %s: q=%f, mcc=%f", iteration_count, round(q, digits=6), round(mcc, digits=6))) 86 | if (iteration_count >= max_iterations) 87 | { 88 | print(sprintf("Warning: search for q did not converge after %s iterations", iteration_count)) 89 | } 90 | } 91 | 92 | # ----------------------------------------------------------------------------------------------------- 93 | # 3 - Plot results. 94 | # ----------------------------------------------------------------------------------------------------- 95 | 96 | # Policy functions (Figure 1. from Huggett 1993). 97 | plot(c(-2, 1),c(-2, 1), type="l", col="white", 98 | main="Policy Function", xlab="starting credit level", ylab="optimal new credit level") 99 | lines(a_grid, vf_result$Policy_Function[ , 2], col="blue") 100 | lines(a_grid, vf_result$Policy_Function[ , 1], col="green") 101 | lines(a_grid, a_grid, lty=2, col="black") 102 | legend("bottomright", legend = c("high endowment", "low endowment", "45-degree line")) 103 | 104 | # Distribution of credit levels (Figure 2. from Huggett 1993). 105 | plot(c(-2, 1),c(0, 1), type="l", col="white", 106 | main="Cumulative Distribution Function for Credit Level", xlab="starting credit level", ylab="") 107 | lines(a_grid, cumsum(Population_Distribution[ , 2]), col="blue") 108 | lines(a_grid, cumsum(Population_Distribution[ , 1]), col="green") 109 | legend("topleft", legend=c("high endowment", "low endowment"), col=c("blue","green")) -------------------------------------------------------------------------------- /2 - Stochastic Growth/Python/main.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stochastic Growth model implemented in Python. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Create a function to solve the household's problem for a given starting state. 7 | 3 - Perform value function iteration. 8 | 4 - Plot results. 9 | """ 10 | 11 | import numpy as np 12 | 13 | # ----------------------------------------------------------------------------------------------------- 14 | # 1 - Define utility parameters, grids, and parameter struct. 15 | # ----------------------------------------------------------------------------------------------------- 16 | # Assign parameter values. 17 | alpha = 0.400 18 | beta = 0.987 19 | delta = 0.012 20 | number_of_iterations = 1000 21 | 22 | # Calculate the steady-state level of capital. 23 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ** (1 / (alpha - 1)) 24 | 25 | # Create a grid of capital values around the steady-state (+/- 2%). 26 | number_of_k_values = 201 27 | k_low_pct = 0.98 28 | k_high_pct = 1.02 29 | k_values = np.linspace(k_low_pct * k_steady, k_high_pct * k_steady, num=number_of_k_values) 30 | 31 | # Get productivity levels and transition probabilities. 32 | z_probs = np.genfromtxt("Inputs\z_probs.csv", delimiter=",") 33 | z_values = np.genfromtxt("Inputs\z_values.csv", delimiter=",") 34 | number_of_z_values = len(z_values) 35 | 36 | # Initialize the Value Function and Policy Function (as arrays). 37 | Value_Function = np.zeros((number_of_iterations, number_of_k_values, number_of_z_values)) 38 | Policy_Function = np.zeros((number_of_iterations, number_of_k_values, number_of_z_values)) 39 | 40 | # Store utility parameters and capital/productivity grids in a struct for passing to a function. 41 | from typing import NamedTuple # could also use dataclass from dataclasses module 42 | 43 | class Parameters(NamedTuple): 44 | alpha: float 45 | beta: float 46 | delta: float 47 | k_values: float 48 | z_values: float 49 | z_probs: float 50 | 51 | params = Parameters(alpha, beta, delta, k_values, z_values, z_probs) 52 | 53 | # ----------------------------------------------------------------------------------------------------- 54 | # 2 - Create a function to solve the household's problem for a given starting state. 55 | # ----------------------------------------------------------------------------------------------------- 56 | def Solve_HH_Problem(Value_Function, kt0, zt, params): 57 | 58 | # Unpack utility parameters and grids. 59 | alpha, beta, delta = params.alpha, params.beta, params.delta 60 | k_values = params.k_values 61 | z_probs = params.z_probs 62 | 63 | # Calculate array of value function values for all capital values. 64 | V_max_values = (np.log( zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - k_values) 65 | + beta * np.dot(Value_Function, z_probs[zt[0], :])) 66 | 67 | # Get the index for the optimal capital choice. 68 | kt1_index_optimal = np.argmax(V_max_values) 69 | 70 | # Get the Value Function and Policy Function values. 71 | kt1_optimal = k_values[kt1_index_optimal] 72 | v_max = V_max_values[kt1_index_optimal] 73 | 74 | return v_max, kt1_optimal 75 | 76 | # ----------------------------------------------------------------------------------------------------- 77 | # 3 - Perform value function iteration. 78 | # ----------------------------------------------------------------------------------------------------- 79 | for iteration in range(1, number_of_iterations): 80 | 81 | # Loop over all possible starting states. 82 | for kt0 in enumerate(k_values): 83 | for zt in enumerate(z_values): 84 | 85 | # Solve the Value Function and Policy Function and update values. 86 | V, g = Solve_HH_Problem(Value_Function[iteration-1, :, :], kt0, zt, params) 87 | 88 | Value_Function[iteration, kt0[0], zt[0]] = V 89 | Policy_Function[iteration, kt0[0], zt[0]] = g 90 | 91 | # ----------------------------------------------------------------------------------------------------- 92 | # 4 - Plot results. 93 | # ----------------------------------------------------------------------------------------------------- 94 | # Plot the Value Function for different starting states. 95 | import matplotlib.pyplot as plt 96 | fig, ax = plt.subplots() 97 | for zt in enumerate(z_values): 98 | ax.plot(k_values, Value_Function[number_of_iterations-1, : ,zt[0]]) 99 | ax.set(xlabel='k', ylabel='V(k,z)', title="Value Function") 100 | ax.legend(np.flip(z_values).round(2), loc='right', title="z value") 101 | plt.show() 102 | 103 | # Plot the final Policy Function for certain productivity values. 104 | z_indices = [0,3,5,7,10] 105 | fig, ax = plt.subplots() 106 | for z_ind in z_indices: 107 | ax.plot(k_values, Policy_Function[number_of_iterations-1,:,z_ind]) 108 | ax.plot(k_values,k_values, '--', color='k', linewidth=0.8) 109 | ax.set(xlabel='k', ylabel='g(k,z)', title="Policy Function") 110 | ax.legend(np.flip(z_values[z_indices]).round(2), loc='right', title="z value") 111 | plt.show() 112 | -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Julia/main.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Idiosyncratic Endowment model implemented in Julia. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Solve model and get market bond price using binary search. 7 | - Guess bond price 8 | - Solve for the Value Function and Policy Function 9 | - Get the distribution of credit and productivity levels 10 | - Check the market clearing condition and update bond price guess 11 | 3 - Plot results. 12 | =# 13 | 14 | include("custom_functions.jl") 15 | using .custom_functions 16 | 17 | # ----------------------------------------------------------------------------------------------------- 18 | # 1 - Define utility parameters, grids, and parameter struct. 19 | # ----------------------------------------------------------------------------------------------------- 20 | 21 | # Endowment parameters. 22 | e_high = 1.0; # high endowment 23 | e_low = 0.1; # low endowment 24 | e_grid = [e_low, e_high]; # endowment grid 25 | number_of_e_values = 2; 26 | e_probs = [0.500 0.500 ; 0.075 0.925]; # transition probabilities 27 | 28 | # Utility parameters. 29 | σ = 1.5; # risk aversion coefficient 30 | β = 0.99322; # discount factor 31 | 32 | # Credit parameters. 33 | a_high = 4; # upper credit limit 34 | a_low = -2; # lower credit limit / borrowing constraint 35 | number_of_a_values = 100; # credit grid size 36 | a_grid = LinRange(a_low, a_high, number_of_a_values); # credit grid 37 | 38 | # Store parameters in a struct for passing to a function. 39 | struct Parameters 40 | σ::Float64 41 | β::Float64 42 | a_grid::Array{Float64, 1} 43 | e_grid::Array{Float64, 1} 44 | e_probs::Array{Float64, 2} 45 | number_of_a_values::Int64 46 | number_of_e_values::Int64 47 | end 48 | 49 | params = Parameters(σ, β, a_grid, e_grid, e_probs, number_of_a_values, number_of_e_values); 50 | 51 | # ----------------------------------------------------------------------------------------------------- 52 | # 2 - Solve model and get market bond price using binary search. 53 | # ----------------------------------------------------------------------------------------------------- 54 | 55 | # Range of bond price values to search. 56 | global q_min = 0.985; 57 | global q_max = 1.100; 58 | 59 | # Optional: floor for q_min such that those at credit limit can still afford positive consumption. 60 | q_min = (a_low + e_low) / a_low; 61 | 62 | # Placeholder for the market clearing condition. 63 | global mcc = Inf; 64 | 65 | # Iteration parameters. 66 | global dist = Inf; 67 | global iteration_count = 0; 68 | global max_iterations = 20; 69 | global tolerance = 1e-3; 70 | 71 | # Solve for market price q. 72 | while (dist > tolerance) & (iteration_count < max_iterations) 73 | 74 | # Get value of q from middle of range. 75 | q = (q_min + q_max)/2; 76 | 77 | # Solve for the Value Function and Policy Function. 78 | global Value_Function, Policy_Function, Policy_Function_Index = Solve_Value_Function(q, params); 79 | 80 | # Get the Population Distribution. 81 | global Population_Distribution = Get_Population_Distribution(Policy_Function_Index, params); 82 | 83 | # Check the market clearing condition. 84 | global mcc = sum(Policy_Function .* Population_Distribution); 85 | 86 | # Update search parameters. 87 | global dist = abs(mcc); 88 | global iteration_count += 1; 89 | 90 | # Update range of q according to the sign of the market clearing condition. 91 | if mcc > 0; global q_min = q; end 92 | if mcc < 0; global q_max = q; end 93 | 94 | # Print results. 95 | println("Iteration $iteration_count: q=$(round(q, digits=6)), mcc=$(round(mcc,digits=6))"); 96 | if iteration_count >= max_iterations; println("Warning: search for q did not converge after $iteration_count iterations"); end 97 | 98 | end 99 | 100 | # ----------------------------------------------------------------------------------------------------- 101 | # 3 - Plot results. 102 | # ----------------------------------------------------------------------------------------------------- 103 | using Plots 104 | 105 | # Policy functions (Figure 1. from Huggett 1993). 106 | Figure1 = plot(legend=:bottomright) 107 | plot!(a_grid, Policy_Function[:, 2], label="high entitlement") 108 | plot!(a_grid, Policy_Function[:, 1], label="low entitlement") 109 | plot!(a_grid, a_grid, linestyle=:dash, label="45-degree line", color=:black) 110 | xlabel!("starting credit level") 111 | ylabel!("optimal new credit level") 112 | title!("Policy Function") 113 | display(Figure1) 114 | 115 | # Distribution of credit levels (Figure 2. from Huggett 1993). 116 | Figure2 = plot(xlim=[-2, 1], ylim=[0, 1], legend=:topleft) 117 | plot!(a_grid, cumsum(Population_Distribution[:, 2]), label="high entitlement") 118 | plot!(a_grid, cumsum(Population_Distribution[:, 1]), label="low entitlement") 119 | xlabel!("starting credit level") 120 | title!("Cumulative Distribution Function for Credit Level") -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Python/main.py: -------------------------------------------------------------------------------- 1 | """ 2 | Idiosyncratic Endowment model implemented in Python. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Solve model and get market bond price using binary search. 7 | - Guess bond price 8 | - Solve model and get market bond price using binary search. 9 | - Get the distribution of credit and productivity levels 10 | - Check the market clearing condition and update bond price guess 11 | 3 - Plot results. 12 | """ 13 | 14 | import numpy as np 15 | from custom_functions import Solve_Value_Function, Get_Population_Distribution 16 | 17 | # ----------------------------------------------------------------------------------------------------- 18 | # 1 - Define utility parameters, grids, and parameter struct. 19 | # ----------------------------------------------------------------------------------------------------- 20 | 21 | # Endowment parameters. 22 | e_high = 1.0 # high endowment 23 | e_low = 0.1 # low endowment 24 | e_grid = np.array([e_low, e_high]) # endowment grid 25 | number_of_e_values = 2 26 | e_probs = np.array([[0.500, 0.500], [0.075, 0.925]]) # transition probabilities 27 | 28 | # Utility parameters. 29 | sigma = 1.5 # risk aversion coefficient 30 | beta = 0.99322 # discount factor 31 | 32 | # Credit parameters. 33 | a_high = 4 # upper credit limit 34 | a_low = -2 # lower credit limit / borrowing constraint 35 | number_of_a_values = 100 # credit grid size 36 | a_grid = np.linspace(a_low, a_high, number_of_a_values) # credit grid 37 | 38 | # Store parameters in a struct for passing to a function. 39 | from typing import NamedTuple # could also use dataclass from dataclasses module 40 | 41 | class Parameters(NamedTuple): 42 | sigma: float 43 | beta: float 44 | a_grid: float 45 | e_grid: float 46 | e_probs: float 47 | number_of_a_values: int 48 | number_of_e_values: int 49 | 50 | params = Parameters(sigma, beta, a_grid, e_grid, e_probs, number_of_a_values, number_of_e_values) 51 | 52 | # ----------------------------------------------------------------------------------------------------- 53 | # 2 - Solve model and get market bond price using binary search. 54 | # ----------------------------------------------------------------------------------------------------- 55 | 56 | # Range of bond price values to search. 57 | q_min = 0.985 58 | q_max = 1.100 59 | 60 | # Optional: floor for q_min such that those at credit limit can still afford positive consumption. 61 | q_min = (a_low + e_low) / a_low 62 | 63 | # Placeholder for the market clearing condition. 64 | mcc = np.Inf 65 | 66 | # Iteration parameters. 67 | dist = np.Inf 68 | iteration_count = 0 69 | max_iterations = 20 70 | tolerance = 1e-3 71 | 72 | # Solve for market price q. 73 | while (dist > tolerance) & (iteration_count < max_iterations): 74 | 75 | # Get value of q from middle of range. 76 | q = (q_min + q_max)/2 77 | 78 | # Solve for the Value Function and Policy Function. 79 | Value_Function, Policy_Function, Policy_Function_Index = Solve_Value_Function(q, params) 80 | 81 | # Get the Population Distribution. 82 | Population_Distribution = Get_Population_Distribution(Policy_Function_Index, params) 83 | 84 | # Check the market clearing condition. 85 | mcc = (Policy_Function * Population_Distribution).sum() 86 | 87 | # Update search parameters. 88 | dist = abs(mcc) 89 | iteration_count += 1 90 | 91 | # Update the range of q according to the sign of the market clearing condition. 92 | if mcc > 0: q_min = q 93 | if mcc < 0: q_max = q 94 | 95 | # Print results. 96 | print(f"Iteration {iteration_count}: q={round(q,6)}, mcc={round(mcc,6)}") 97 | if iteration_count >= max_iterations: print(f"Warning: search for q did not converge after {iteration_count} iterations") 98 | 99 | # ----------------------------------------------------------------------------------------------------- 100 | # 3 - Plot results. 101 | # ----------------------------------------------------------------------------------------------------- 102 | 103 | # Policy functions (Figure 1. from Huggett 1993). 104 | import matplotlib.pyplot as plt 105 | fig, ax = plt.subplots() 106 | ax.plot(a_grid, Policy_Function[:, 1]) 107 | ax.plot(a_grid, Policy_Function[:, 0]) 108 | ax.plot(a_grid, a_grid, '--', color='k', linewidth=0.8) 109 | ax.set(xlabel="starting credit level", ylabel="optimal new credit level", title="Policy Function") 110 | ax.legend(["high endowment", "low endowment", "45-degree line"], loc='lower right') 111 | plt.show() 112 | 113 | # Distribution of credit levels (Figure 2. from Huggett 1993). 114 | fig, ax = plt.subplots() 115 | ax.plot(a_grid, Population_Distribution[:,1].cumsum()) 116 | ax.plot(a_grid, Population_Distribution[:,0].cumsum()) 117 | ax.set(xlim=[-2, 1], ylim=[0, 1], xlabel="starting credit level", title="Cumulative Distribution Function for Credit Level") 118 | ax.legend(["high endowment", "low endowment"], loc='upper left') 119 | plt.show() -------------------------------------------------------------------------------- /2 - Stochastic Growth/R/main.R: -------------------------------------------------------------------------------- 1 | # Stochastic Growth model implemented in R. 2 | # 3 | # Steps: 4 | # 1 - Define utility parameters, grids, and parameter struct. 5 | # 2 - Create a function to solve the household's problem for a given starting state. 6 | # 3 - Perform value function iteration. 7 | # 4 - Plot results. 8 | 9 | # ----------------------------------------------------------------------------------------------------- 10 | # 1 - Define utility parameters, grids, and parameter struct. 11 | # ----------------------------------------------------------------------------------------------------- 12 | # Assign parameter values. 13 | alpha = 0.400 14 | beta = 0.987 15 | delta = 0.012 16 | number_of_iterations = 1000 17 | 18 | # Calculate the steady-state level of capital. 19 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ^ (1 / (alpha - 1)) 20 | 21 | # Create a range of capital values around steady-state (+/- 2%). 22 | number_of_k_values = 201 23 | k_low_pct = 0.98 24 | k_high_pct = 1.02 25 | k_values = seq(k_low_pct * k_steady, k_high_pct * k_steady, length.out=number_of_k_values) 26 | 27 | # Get productivity levels and transition probabilities. 28 | z_probs = as.matrix(read.csv("Inputs/z_probs.csv", sep=",", header=FALSE)) 29 | z_values = as.matrix(read.csv("Inputs/z_values.csv", sep=",", header=FALSE)) 30 | number_of_z_values = dim(z_values)[1] 31 | 32 | # Initialize the Value Function and Policy Function (as arrays). 33 | Value_Function = array(0, c(number_of_iterations, number_of_k_values, number_of_z_values)) 34 | Policy_Function = array(0, c(number_of_iterations, number_of_k_values, number_of_z_values)) 35 | 36 | # Store utility parameters and capital/productivity grids in a list for passing to a function. 37 | params = list(alpha=alpha, beta=beta, delta=delta, 38 | k_values=k_values, z_values=z_values, z_probs=z_probs) 39 | 40 | # ----------------------------------------------------------------------------------------------------- 41 | # 2 - Create a function to solve Value Function for given starting states. 42 | # ----------------------------------------------------------------------------------------------------- 43 | Solve_HH_Problem = function(Value_Function, kt0_index, zt_index, params){ 44 | 45 | # Unpack utility parameters and grids. 46 | alpha = params$alpha 47 | beta = params$beta 48 | delta = params$delta 49 | k_values = params$k_values 50 | z_values = params$z_values 51 | z_probs = params$z_probs 52 | 53 | # Get capital and productivity values from index. 54 | kt0 = k_values[kt0_index] 55 | zt = z_values[zt_index] 56 | 57 | # Calculate array of value function values for all capital values. 58 | V_max_values = log(zt * (kt0 ^ alpha) + (1 - delta) * kt0 - k_values) + 59 | beta * drop(Value_Function %*% z_probs[zt_index, ]) 60 | 61 | 62 | # Get the index for the optimal capital choice. 63 | kt1_index_optimal = which.max(V_max_values) 64 | 65 | # Get the Value Function and Policy Function values. 66 | kt1_optimal = k_values[kt1_index_optimal] 67 | v_max = V_max_values[kt1_index_optimal] 68 | 69 | return(list(v_max=v_max, kt1_optimal=kt1_optimal)) 70 | } 71 | 72 | # Alternative: import other versions from script. 73 | # source("custom_functions") 74 | # use Solve_HH_Problem_v1 or Solve_HH_Problem_v2 75 | 76 | # ----------------------------------------------------------------------------------------------------- 77 | # 3 - Perform value function iteration. 78 | # ----------------------------------------------------------------------------------------------------- 79 | for (iteration in 2:number_of_iterations) 80 | { 81 | # Loop over all possible starting states. 82 | for (kt0_index in 1:number_of_k_values) 83 | { 84 | for (zt_index in 1:number_of_z_values) 85 | { 86 | # Solve the Value Function and Policy Function and update values. 87 | result = Solve_HH_Problem(Value_Function[iteration-1, , ], kt0_index, zt_index, params) 88 | 89 | Value_Function[iteration,kt0_index,zt_index] = result$v_max 90 | Policy_Function[iteration,kt0_index,zt_index] = result$kt1_optimal 91 | } 92 | } 93 | } 94 | 95 | # ----------------------------------------------------------------------------------------------------- 96 | # 4 - Plot results. 97 | # ----------------------------------------------------------------------------------------------------- 98 | # Plot the Value Function for different starting states. 99 | plot(c(min(k_values), max(k_values)), 100 | c(min(Value_Function[number_of_iterations, , ]), (Value_Function[number_of_iterations, , ])), 101 | type="l", col="white", # hidden values to establish plot size 102 | main="Value Function", xlab="k", ylab="V(k,z)") 103 | for (z_index in 1:number_of_z_values) 104 | { 105 | lines(k_values, Value_Function[number_of_iterations, ,z_index]) 106 | } 107 | legend("right", legend=round(rev(z_values), 2), title="z values") 108 | 109 | # Plot the final Policy Function for certain productivity values. 110 | z_indices = c(1, 4, 6, 8, 11) 111 | plot(k_values, k_values, type="l", lty=2, col="black", 112 | main="Policy Function", xlab="k", ylab="g(k)") 113 | for (z_index in z_indices){ 114 | lines(k_values, Policy_Function[number_of_iterations, , z_index]) 115 | } 116 | legend("topleft", legend=c(round(rev(z_values[z_indices]), 2), "45-degree line"), 117 | lty=c(1, 1, 1, 1, 1, 2), title="z values") -------------------------------------------------------------------------------- /2 - Stochastic Growth/Julia/main.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Stochastic Growth model implemented in Julia. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Create a function to solve the household's problem for a given starting state. 7 | 3 - Perform value function iteration. 8 | 4 - Plot results. 9 | =# 10 | 11 | function main() 12 | 13 | # ----------------------------------------------------------------------------------------------------- 14 | # 1 - Define utility parameters, grids, and parameter struct. 15 | # ----------------------------------------------------------------------------------------------------- 16 | # Assign parameter values. 17 | α = 0.400; 18 | β = 0.987; 19 | δ = 0.012; 20 | number_of_iterations = 1000; 21 | 22 | # Calculate the steady-state level of capital. 23 | k_steady = ((1 - β * (1 - δ)) / (α * β)) ^ (1 / (α - 1)) 24 | 25 | # Create a range of capital values around the steady-state (+/- 50%). 26 | number_of_k_values = 201; 27 | k_low_pct = 0.98; 28 | k_high_pct = 1.02; 29 | k_values = collect(range(k_low_pct * k_steady, k_high_pct * k_steady, length=number_of_k_values)); 30 | 31 | # Get productivity levels and transition probabilities. 32 | using DelimitedFiles 33 | cd("C:\\Users\\Ray\\Documents\\GitHub\\DSGE-models\\2 - Stochastic Growth\\Julia") 34 | z_probs = readdlm("Inputs\\z_probs.csv", ',', Float64); 35 | z_values = readdlm("Inputs\\z_values.csv", ',', Float64)[:, 1]; 36 | number_of_z_values = size(z_values, 1); 37 | 38 | # Initialize the Value Function and Policy Function (as arrays). 39 | Value_Function = zeros(number_of_iterations, number_of_k_values, number_of_z_values); 40 | Policy_Function = zeros(number_of_iterations, number_of_k_values, number_of_z_values); 41 | 42 | # Store utility parameters and capital/productivity grids in a struct for passing to a function. 43 | struct Parameters 44 | α::Float64 45 | β::Float64 46 | δ::Float64 47 | k_values::Array{Float64, 1} # == Vector{Float64} 48 | z_values::Array{Float64, 1} # == Vector{Float64} 49 | z_probs::Array{Float64, 2} # == Matrix{Float64} 50 | end 51 | 52 | params = Parameters(α, β, δ, k_values, z_values, z_probs); 53 | 54 | # ----------------------------------------------------------------------------------------------------- 55 | # 2 - Create a function to solve the household's problem for a given starting state. 56 | # ----------------------------------------------------------------------------------------------------- 57 | function Solve_HH_Problem(Value_Function, kt0_index, zt_index, params) 58 | 59 | # Unpack utility parameters and grids. 60 | α,β,δ = params.α, params.β, params.δ; 61 | k_values = params.k_values; 62 | z_values = params.z_values; 63 | z_probs = params.z_probs; 64 | 65 | # Get capital and productivity values from index. 66 | kt0 = k_values[kt0_index]; 67 | zt = z_values[zt_index]; 68 | 69 | # Calculate array of value function values for all capital values. 70 | @views V_max_values = log.(zt * (kt0 ^ α) + (1 - δ) * kt0 .- k_values) + β * (Previous_Value_Function * z_probs[zt_index, :]); 71 | 72 | # Get index for the optimal capital choice. 73 | kt1_index_optimal = argmax(V_max_values); 74 | 75 | # Get the Value Function and Policy Function values. 76 | kt1_optimal = k_values[kt1_index_optimal]; 77 | v_max = V_max_values[kt1_index_optimal]; 78 | 79 | return v_max, kt1_optimal; 80 | end 81 | 82 | # Alternative: import other versions from module. 83 | #include("custom_functions.jl") 84 | #using .custom_functions 85 | 86 | # ----------------------------------------------------------------------------------------------------- 87 | # 3 - Perform value function iteration. 88 | # ----------------------------------------------------------------------------------------------------- 89 | for iteration in 2:number_of_iterations 90 | 91 | # Loop over all possible starting states. 92 | for zt_index in eachindex(z_values) # replace for parllel implementation: Threads.@threads for zt_index in eachindex(z_values) 93 | for kt0_index in eachindex(k_values) 94 | 95 | # Solve the Value Function and Policy Function and update values. 96 | @views V, g = Solve_HH_Problem(Value_Function[iteration-1, :, :], kt0_index, zt_index, params); 97 | 98 | Value_Function[iteration, kt0_index, zt_index] = V; 99 | Policy_Function[iteration, kt0_index, zt_index] = g; 100 | end 101 | end 102 | 103 | # ----------------------------------------------------------------------------------------------------- 104 | # 4 - Plot results. 105 | # ----------------------------------------------------------------------------------------------------- 106 | # Plot the Value Function for different starting states. 107 | Figure1 = plot(legendtitle="z value") 108 | for zt_index in eachindex(z_values) 109 | plot!(k_values, Value_Function[number_of_iterations, :, zt_index], label=round(z_values[zt_index], digits=2)) 110 | end 111 | xlabel!("k") 112 | ylabel!("V(k,z)") 113 | title!("Value Function") 114 | display(Figure1) 115 | 116 | # Plot the final Policy Function for certain productivity values. 117 | z_indices = [1,4,6,8,11] 118 | Figure2 = plot(k_values, Policy_Function[number_of_iterations, :, z_indices], label=round.(z_values[z_indices], digits=2)', legend=:topleft, legendtitle="z value") 119 | plot!(k_values,k_values, linestyle=:dash, label="45-degree line", color=:black) 120 | xlabel!("k") 121 | ylabel!("g(k,z)") 122 | title!("Policy Function") 123 | display(Figure2) 124 | 125 | end -------------------------------------------------------------------------------- /Extra content/Julia performance profiling/3 - Idiosyncratic Endowment/main.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Idiosyncratic Endowment model implemented in Julia. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Solve model and get market bond price using binary search. 7 | - Guess bond price 8 | - Solve for the Value Function and Policy Function 9 | - Get the distribution of credit and productivity levels 10 | - Check the market clearing condition and update bond price guess 11 | 3 - Plot results. 12 | =# 13 | 14 | using Plots 15 | include("custom_functions.jl") 16 | using .custom_functions 17 | 18 | # Store parameters in a struct for passing to a function. 19 | struct Parameters 20 | σ::Float64 21 | β::Float64 22 | a_grid::Array{Float64, 1} 23 | e_grid::Array{Float64, 1} 24 | e_probs::Array{Float64, 2} 25 | number_of_a_values::Int64 26 | number_of_e_values::Int64 27 | end 28 | 29 | function main() 30 | # ----------------------------------------------------------------------------------------------------- 31 | # 1 - Define utility parameters, grids, and parameter struct. 32 | # ----------------------------------------------------------------------------------------------------- 33 | 34 | # Endowment parameters. 35 | e_high = 1.0; # high endowment 36 | e_low = 0.1; # low endowment 37 | e_grid = [e_low, e_high]; # endowment grid 38 | number_of_e_values = 2; 39 | e_probs = [0.500 0.500 ; 0.075 0.925]; # transition probabilities 40 | 41 | # Utility parameters. 42 | σ = 1.5; # risk aversion coefficient 43 | β = 0.99322; # discount factor 44 | 45 | # Credit parameters. 46 | a_high = 4; # upper credit limit 47 | a_low = -2; # lower credit limit / borrowing constraint 48 | number_of_a_values = 100; # credit grid size 49 | a_grid = LinRange(a_low, a_high, number_of_a_values); # credit grid 50 | 51 | params = Parameters(σ, β, a_grid, e_grid, e_probs, number_of_a_values, number_of_e_values); 52 | 53 | # ----------------------------------------------------------------------------------------------------- 54 | # 2 - Solve model and get market bond price using binary search. 55 | # ----------------------------------------------------------------------------------------------------- 56 | 57 | # Range of bond price values to search. 58 | global q_min = 0.985; 59 | global q_max = 1.100; 60 | 61 | # Optional: floor for q_min such that those at credit limit can still afford positive consumption. 62 | q_min = (a_low + e_low) / a_low; 63 | 64 | # Placeholder for the market clearing condition. 65 | global mcc = Inf; 66 | 67 | # Iteration parameters. 68 | global dist = Inf; 69 | global iteration_count = 0; 70 | global max_iterations = 20; 71 | global tolerance = 1e-3; 72 | 73 | # Solve for market price q. 74 | while (dist > tolerance) & (iteration_count < max_iterations) 75 | 76 | # Get value of q from middle of range. 77 | global q = (q_min + q_max)/2; 78 | 79 | # Solve for the Value Function and Policy Function. 80 | global Value_Function, Policy_Function, Policy_Function_Index = Solve_Value_Function(q, params); 81 | 82 | # Get the Population Distribution. 83 | global Population_Distribution = Get_Population_Distribution(Policy_Function_Index, params); 84 | 85 | # Check the market clearing condition. 86 | global mcc = sum(Policy_Function .* Population_Distribution); 87 | 88 | # Update search parameters. 89 | global dist = abs(mcc); 90 | global iteration_count += 1; 91 | 92 | # Update range of q according to the sign of the market clearing condition. 93 | if mcc > 0; global q_min = q; end 94 | if mcc < 0; global q_max = q; end 95 | 96 | # Print results. 97 | println("Iteration $iteration_count: q=$(round(q, digits=6)), mcc=$(round(mcc,digits=6))"); 98 | if iteration_count >= max_iterations; println("Warning: search for q did not converge after $iteration_count iterations"); end 99 | 100 | end 101 | 102 | # ----------------------------------------------------------------------------------------------------- 103 | # 3 - Plot results. 104 | # ----------------------------------------------------------------------------------------------------- 105 | 106 | # Policy functions (Figure 1. from Huggett 1993). 107 | Figure1 = plot(legend=:bottomright) 108 | plot!(a_grid, Policy_Function[:, 2], label="high entitlement") 109 | plot!(a_grid, Policy_Function[:, 1], label="low entitlement") 110 | plot!(a_grid, a_grid, linestyle=:dash, label="45-degree line", color=:black) 111 | xlabel!("starting credit level") 112 | ylabel!("optimal new credit level") 113 | title!("Policy Function") 114 | display(Figure1) 115 | 116 | # Distribution of credit levels (Figure 2. from Huggett 1993). 117 | Figure2 = plot(xlim=[-2, 1], ylim=[0, 1], legend=:topleft) 118 | plot!(a_grid, cumsum(Population_Distribution[:, 2]), label="high entitlement") 119 | plot!(a_grid, cumsum(Population_Distribution[:, 1]), label="low entitlement") 120 | xlabel!("starting credit level") 121 | title!("Cumulative Distribution Function for Credit Level") 122 | end 123 | 124 | # Benchmarking and profiling. 125 | using Profile 126 | using BenchmarkTools 127 | 128 | @btime main() 129 | @profview main() 130 | # https://www.julia-vscode.org/docs/dev/userguide/profiler/ -------------------------------------------------------------------------------- /Extra content/C++ implementation using C-style base arrays/1 - Base Model/main.cpp: -------------------------------------------------------------------------------- 1 | // Base Model implementation in c++. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | double** InitiateArray2D(int n_rows, int n_cols); 10 | void DeleteArray2D(double** Array2D, int n_rows, int n_cols); 11 | void WriteArrayToCSV(double** Array2D, int n_rows, int n_cols, const char* file_name); 12 | 13 | int main() 14 | { 15 | // Assign parameter values. 16 | const double alpha = 0.400; 17 | const double beta = 0.987; 18 | const double delta = 1.000; 19 | const int number_of_iterations = 1000; 20 | 21 | // Calculate the steady-state level of capital. 22 | double k_steady = pow(((1 - beta * (1 - delta)) / (alpha * beta)), (1 / (alpha - 1))); // pow(base, exponent) = base^exponent 23 | 24 | // Create grid of capital values around the steady-state (+/- 50%). 25 | const int number_of_k_values = 201; 26 | const double k_low_pct = 0.50; 27 | const double k_high_pct = 1.50; 28 | double k_values[number_of_k_values]; 29 | 30 | for (int i = 0; i < number_of_k_values; i++) 31 | { 32 | k_values[i] = k_steady * (k_low_pct + ((double(i) / (double(number_of_k_values) - 1)) * (k_high_pct - k_low_pct))); 33 | } 34 | 35 | // Initialize Value Function and Policy Function (as arrays). 36 | double** Value_Function = InitiateArray2D(number_of_iterations, number_of_k_values); 37 | double** Policy_Function = InitiateArray2D(number_of_iterations, number_of_k_values); 38 | 39 | // Assign value of 0 to first value function iteration. 40 | for (int i = 0; i < number_of_k_values; i++) 41 | { 42 | Value_Function[0][i] = 0.0; 43 | Policy_Function[0][i] = 0.0; 44 | } 45 | 46 | // Solve the household's problem for each possible starting state. 47 | for (int iteration = 1; iteration < number_of_iterations; iteration++) 48 | { 49 | for (int kt0_ind = 0; kt0_ind < number_of_k_values; kt0_ind++) 50 | { 51 | // Variables to store candidate optimal values. 52 | double v_max = -DBL_MAX; 53 | double kt1_optimal = 0.0; 54 | double new_value_function_value; 55 | 56 | // Check all possible next period capital choices. 57 | for (int kt1_ind = 0; kt1_ind < number_of_k_values; kt1_ind++) 58 | { 59 | // Calculate the Value Function for given starting capital and next period capital choice. 60 | new_value_function_value = log(pow(k_values[kt0_ind], alpha) - k_values[kt1_ind] + (1 - delta) * k_values[kt0_ind]) + 61 | +beta * Value_Function[iteration - 1][kt1_ind]; 62 | 63 | // Check if this capital choice gives highest Value Function value. 64 | if (new_value_function_value > v_max) 65 | { 66 | // Update candidate values. 67 | v_max = new_value_function_value; 68 | kt1_optimal = k_values[kt1_ind]; 69 | } 70 | } 71 | 72 | // Update the Value Function and Policy Function with optimal values. 73 | Value_Function[iteration][kt0_ind] = v_max; 74 | Policy_Function[iteration][kt0_ind] = kt1_optimal; 75 | } 76 | } 77 | 78 | // Write Value Function and Policy Function to csv files. 79 | WriteArrayToCSV(Value_Function, number_of_iterations, number_of_k_values, "Value_Function.csv"); 80 | WriteArrayToCSV(Policy_Function, number_of_iterations, number_of_k_values, "Policy_Function.csv"); 81 | 82 | // Display the first and last 5 values of the Value Function and Policy Function. 83 | for (int i = 0; i < 5; i++) 84 | { 85 | if (i == 0) { std::cout << "Value Function V(k):" << "\n"; }; 86 | std::cout << "V(" << k_values[i] << ") = " << Value_Function[number_of_iterations - 1][i] << "\n"; 87 | } 88 | std::cout << "..." << "\n"; 89 | for (int i = number_of_k_values - 5; i < number_of_k_values; i++) 90 | { 91 | std::cout << "V(" << k_values[i] << ") = " << Value_Function[number_of_iterations - 1][i] << "\n"; 92 | } 93 | 94 | for (int i = 0; i < 5; i++) 95 | { 96 | if (i == 0) { std::cout << "\n" << "Policy Function g(k):" << "\n"; }; 97 | std::cout << "g(" << k_values[i] << ") = " << Policy_Function[number_of_iterations - 1][i] << "\n"; 98 | } 99 | std::cout << "..." << "\n"; 100 | for (int i = number_of_k_values - 5; i < number_of_k_values; i++) 101 | { 102 | std::cout << "g(" << k_values[i] << ") = " << Policy_Function[number_of_iterations - 1][i] << "\n"; 103 | } 104 | 105 | // Remove arrays from memory. 106 | DeleteArray2D(Value_Function, number_of_iterations, number_of_k_values); 107 | DeleteArray2D(Policy_Function, number_of_iterations, number_of_k_values); 108 | 109 | // Leave window open after program terminates. 110 | std::cin.get(); 111 | return 0; 112 | } 113 | 114 | 115 | // Function to dynamically allocate memory for a 2-dimensional array. 116 | double** InitiateArray2D(int n_rows, int n_cols) 117 | { 118 | double** Array2D; 119 | Array2D = new double* [n_rows]; 120 | for (int i = 0; i < n_rows; i++) 121 | { 122 | Array2D[i] = new double[n_cols]; 123 | } 124 | 125 | return Array2D; 126 | } 127 | 128 | // Function to clear the memory allocated for a 2-dimensional array. 129 | void DeleteArray2D(double** Array2D, int n_rows, int n_cols) 130 | { 131 | for (int i = 0; i < n_rows; i++) 132 | { 133 | delete[] Array2D[i]; 134 | } 135 | delete[] Array2D; 136 | } 137 | 138 | // Function to write a 2-dimensional array to csv file. 139 | void WriteArrayToCSV(double** Array2D, int n_rows, int n_cols, const char* file_name) 140 | { 141 | std::ofstream write_output(file_name); 142 | assert(write_output.is_open()); 143 | 144 | for (int i = 0; i < n_rows; i++) 145 | { 146 | for (int j = 0; j < n_cols; j++) 147 | { 148 | write_output << Array2D[i][j] << ","; 149 | } 150 | write_output << "\n"; 151 | } 152 | write_output.close(); 153 | } -------------------------------------------------------------------------------- /2 - Stochastic Growth/c++/custom_functions.cpp: -------------------------------------------------------------------------------- 1 | #include "custom_functions.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Function to solve the household's problem for a given starting state. 10 | void Solve_HH_Problem(Array3D& Value_Function, Array3D& Policy_Function, int iteration, int kt0_index, int zt_index, Parameters& params) 11 | { 12 | // Get starting capital and productivity values from index. 13 | double kt0 = params.k_values[kt0_index]; 14 | double zt = params.z_values[zt_index]; 15 | 16 | // Variables to store candidate optimal values. 17 | double v_max = -DBL_MAX; 18 | double kt1_optimal = 0.0; 19 | double new_v_max; 20 | 21 | for (int kt1_index = 0; kt1_index < params.number_of_k_values; kt1_index++) 22 | { 23 | // Get capital value from index. 24 | double kt1 = params.k_values[kt1_index]; 25 | 26 | // Calculate the Value Function for a given next period capital choice. 27 | double current_period_payoff, future_period_payoff; 28 | 29 | current_period_payoff = log((zt * pow(kt0, params.alpha)) + ((1 - params.delta) * kt0) - kt1); 30 | 31 | future_period_payoff = 0.0; 32 | for (int z_prob_index = 0; z_prob_index < params.number_of_z_values; z_prob_index++) 33 | { 34 | future_period_payoff += Value_Function[iteration - 1][kt1_index][z_prob_index] * params.z_probs[zt_index][z_prob_index]; 35 | } 36 | 37 | new_v_max = current_period_payoff + params.beta * future_period_payoff; 38 | 39 | // Check if this capital choice gives the highest Value Function value. 40 | if (new_v_max > v_max) 41 | { 42 | // Update candidate values. 43 | v_max = new_v_max; 44 | kt1_optimal = kt1; 45 | } 46 | } 47 | 48 | // Update Value Function and Policy Function with optimal values. 49 | Value_Function[iteration][kt0_index][zt_index] = v_max; 50 | Policy_Function[iteration][kt0_index][zt_index] = kt1_optimal; 51 | } 52 | 53 | // Function to write a 2-dimensional array to csv file. 54 | void WriteArrayToCSV(Array2D Array, int n_rows, int n_cols, const char* file_name) 55 | { 56 | std::ofstream write_output(file_name); 57 | assert(write_output.is_open()); 58 | 59 | for (int i = 0; i < n_rows; i++) 60 | { 61 | for (int j = 0; j < n_cols; j++) 62 | { 63 | write_output << Array[i][j] << ","; 64 | } 65 | write_output << "\n"; 66 | } 67 | write_output.close(); 68 | } 69 | 70 | // Function to read a 2-dimensional array from csv file. 71 | Array2D ReadArrayFromCSV(std::string path) 72 | { 73 | // Vector of vectors to store csv conents. 74 | Array2D content_array; 75 | vector row; 76 | std::string line, values; 77 | 78 | // Load file. 79 | std::fstream file(path, std::ios::in); 80 | assert(file.is_open()); 81 | 82 | // Get data from a specific row. 83 | while (getline(file, line)) 84 | { 85 | row.clear(); 86 | 87 | std::stringstream row_string(line); 88 | 89 | // Get the individual values from each column 90 | while (getline(row_string, values, ',')) 91 | { 92 | row.push_back(std::stod(values)); // get values in each row, and convert from string to double with stod() 93 | } 94 | content_array.push_back(row); // add row to content array. 95 | } 96 | 97 | /* 98 | // Print array. 99 | for (int i = 0; i < Content.size(); i++) 100 | { 101 | for (int j = 0; j < Content[0].size(); j++) 102 | { 103 | std::cout << Content[i][j] << " "; 104 | } 105 | std::cout << "\n"; 106 | } 107 | */ 108 | return content_array; 109 | } 110 | 111 | // Function to read a column vector (delimited by new lines) from csv file. 112 | vector ReadVectorFromCSV(std::string path) 113 | { 114 | // Vector of vectors to store csv conents. 115 | vector content_vector; 116 | std::string value; 117 | 118 | // Load file. 119 | std::fstream file(path, std::ios::in); 120 | assert(file.is_open()); 121 | 122 | // Go through each row 123 | while (getline(file, value)) 124 | { 125 | // Get element, convert to double, and add to the output vector. 126 | content_vector.push_back(std::stod(value)); 127 | } 128 | return content_vector; 129 | } 130 | 131 | 132 | /* 133 | // Function to read a row vector (delimited by commas) from csv file. 134 | vector ReadVectorFromCSV(std::string path) 135 | { 136 | // Vector of vectors to store csv conents. 137 | vector content_vector; 138 | std::string value; 139 | 140 | // Load file. 141 | std::fstream file(path, std::ios::in); 142 | assert(file.is_open()); 143 | 144 | // Go through the row of data, stopping at each ',' to get the value. 145 | while (getline(file, value, ',')) 146 | { 147 | // Get element, convert to double, and add to the output vector. 148 | content_vector.push_back(std::stod(value)); 149 | } 150 | return content_vector; 151 | } 152 | */ 153 | 154 | // Alternative: read an array from file and write to a given static array. 155 | template 156 | void ReadArrayFromCSV(std::string path, double(&Static_Array)[n_rows][n_cols]) 157 | { 158 | // Read array from file. 159 | double** Dynamic_Array = ReadArrayFromCSV(path); 160 | 161 | // Write to given array. 162 | for (int i = 0; i < n_rows; i++) 163 | { 164 | for (int j = 0; j < n_cols; j++) 165 | { 166 | Static_Array[i][j] = Dynamic_Array[i][j]; 167 | } 168 | } 169 | } 170 | 171 | // Alternative: read a vector from file and write to a given static vector. 172 | template 173 | void ReadVectorFromCSV(std::string path, double(&static_vector)[n_rows]) 174 | { 175 | // Read vector from file. 176 | double* dynamic_vector = ReadVectorFromCSV(path); 177 | 178 | // Write to given vector. 179 | for (int i = 0; i < n_rows; i++) 180 | { 181 | static_vector[i] = dynamic_vector[i]; 182 | } 183 | } -------------------------------------------------------------------------------- /2 - Stochastic Growth/Python/custom_functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Function to solve the household's problem for a given starting state. 5 | Four different versions with increasing levels of performance. 6 | Each version has identical inputs and outputs. 7 | 8 | Input: 9 | - Current value function 10 | - Starting capital and productivity level 11 | 12 | Output: 13 | - Next value function value 14 | - Optimal choice of next period capital 15 | 16 | Version 17 | v1: using only base functions + for-loops 18 | v2: using Numpy arrays / broadcast instead of for-loop 19 | v3: precompiled with numba and using for-loops 20 | v4: precompiled with numba and using numpy arrays instead of for-loop 21 | """ 22 | 23 | import numpy as np 24 | from math import log 25 | 26 | # ----------------------------------------------------------------------------------------------------- 27 | # Version 1 - using only base functions + for-loops. 28 | # ----------------------------------------------------------------------------------------------------- 29 | def Solve_HH_Problem_v1(Value_Function, kt0, zt, params): 30 | 31 | # Unpack utility parameters and grids. 32 | alpha, beta, delta = params.alpha, params.beta, params.delta 33 | k_values = params.k_values 34 | z_probs = params.z_probs 35 | 36 | # Variables to store candidate optimal values for the Value Function and Policy Function. 37 | v_max = -float('inf') 38 | kt1_optimal = 0.0 39 | 40 | # Check all possible next period capital choices. 41 | for kt1 in enumerate(k_values): 42 | 43 | # Calculate the Value Function for given starting capital and next period capital choice. 44 | new_v_max = ( log( (zt[1] * (kt0[1] ** alpha)) + (1 - delta) * kt0[1] - kt1[1]) 45 | + beta * np.dot(Value_Function[kt1[0], :], z_probs[zt[0], :])) 46 | 47 | # Check if this capital choice gives the highest Value Function value. 48 | if new_v_max > v_max: 49 | 50 | # Update candidate values. 51 | v_max = new_v_max 52 | kt1_optimal = kt1[1] 53 | 54 | return v_max, kt1_optimal 55 | 56 | # ----------------------------------------------------------------------------------------------------- 57 | # Version 2 - using Numpy arrays / broadcast instead of for-loop. 58 | # ----------------------------------------------------------------------------------------------------- 59 | def Solve_HH_Problem_v2(Value_Function, kt0, zt, params): 60 | 61 | # Unpack utility parameters and grids. 62 | alpha, beta, delta = params.alpha, params.beta, params.delta 63 | k_values = params.k_values 64 | z_probs = params.z_probs 65 | 66 | # Calculate array of value function values for all next period capital choices. 67 | V_max_values = (np.log(zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - k_values) 68 | + beta * np.dot(Value_Function, z_probs[zt[0], :])) 69 | 70 | # Get the index for the optimal capital choice. 71 | kt1_index_optimal = np.argmax(V_max_values) 72 | 73 | # Get the optimal Value Function and Policy Function values. 74 | kt1_optimal = k_values[kt1_index_optimal] 75 | v_max = V_max_values[kt1_index_optimal] 76 | 77 | return v_max, kt1_optimal 78 | 79 | # ----------------------------------------------------------------------------------------------------- 80 | # Version 3 - precompiled with numba and using for-loops. 81 | # ----------------------------------------------------------------------------------------------------- 82 | from numba import jit 83 | 84 | @jit(nopython=True) 85 | def Solve_HH_Problem_v3(Value_Function, kt0, zt, params): 86 | 87 | # Unpack utility parameters and grids. 88 | alpha,beta,delta = params.alpha, params.beta, params.delta 89 | k_values = params.k_values 90 | z_probs = params.z_probs 91 | 92 | # Variables to store candidate optimal values for Value Function and Policy Function. 93 | v_max = 0.0 94 | new_v_max = 0.0 95 | kt1_optimal = 0.0 96 | 97 | # Check all possible next period capital choices. 98 | for kt1 in enumerate(k_values): 99 | 100 | # Calculate the Value Function for given starting capital and next period capital choice. 101 | new_v_max = ( log((zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - kt1[1])) 102 | + beta * np.dot(Value_Function[kt1[0], :], z_probs[zt[0], :])) 103 | 104 | # Check if this capital choice gives the highest Value Function value. 105 | if new_v_max > v_max: 106 | 107 | # Update candidate values. 108 | v_max = new_v_max 109 | kt1_optimal = kt1[1] 110 | 111 | return v_max, kt1_optimal 112 | 113 | # ----------------------------------------------------------------------------------------------------- 114 | # Version 4 - precompiled with numba and using numpy arrays instead of for-loop. 115 | # ----------------------------------------------------------------------------------------------------- 116 | from numba import jit 117 | 118 | @jit(nopython=True) 119 | def Solve_HH_Problem_v4(Value_Function, kt0, zt, params): 120 | 121 | # Unpack utility parameters and grids. 122 | alpha,beta,delta = params.alpha, params.beta, params.delta 123 | k_values = params.k_values 124 | z_probs = params.z_probs 125 | 126 | # Calculate array of value function values for all next period capital choices. 127 | V_max_values = (np.log(zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - k_values) 128 | + beta * np.dot(Value_Function, z_probs[zt[0], :])) 129 | 130 | # Get the index for the optimal capital choice. 131 | kt1_ind_optimal = np.argmax(V_max_values) 132 | 133 | # Get the optimal Value Function and Policy Function values. 134 | kt1_optimal = k_values[kt1_ind_optimal] 135 | v_max = V_max_values[kt1_ind_optimal] 136 | 137 | return v_max, kt1_optimal -------------------------------------------------------------------------------- /Extra content/Python numpy and numba benchmarking/custom_functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Function to solve the household's problem for a given starting state. 5 | Four different versions with increasing levels of performance. 6 | Each version has identical inputs and outputs. 7 | 8 | Input: 9 | - Current value function 10 | - Starting capital and productivity level 11 | 12 | Output: 13 | - Next value function value 14 | - Optimal choice of next period capital 15 | 16 | Version 17 | v1: using only base functions + for-loops 18 | v2: using Numpy arrays / broadcast instead of for-loop 19 | v3: precompiled with numba and using for-loops 20 | v4: precompiled with numba and using numpy arrays instead of for-loop 21 | """ 22 | 23 | import numpy as np 24 | from math import log 25 | 26 | # ----------------------------------------------------------------------------------------------------- 27 | # Version 1 - using only base functions + for-loops. 28 | # ----------------------------------------------------------------------------------------------------- 29 | def Solve_HH_Problem_v1(Value_Function, kt0, zt, params): 30 | 31 | # Unpack utility parameters and grids. 32 | alpha, beta, delta = params.alpha, params.beta, params.delta 33 | k_values = params.k_values 34 | z_probs = params.z_probs 35 | 36 | # Variables to store candidate optimal values for the Value Function and Policy Function. 37 | v_max = -float('inf') 38 | kt1_optimal = 0.0 39 | 40 | # Check all possible next period capital choices. 41 | for kt1 in enumerate(k_values): 42 | 43 | # Calculate the Value Function for given starting capital and next period capital choice. 44 | new_v_max = ( log( (zt[1] * (kt0[1] ** alpha)) + (1 - delta) * kt0[1] - kt1[1]) 45 | + beta * np.dot(Value_Function[kt1[0], :], z_probs[zt[0], :])) 46 | 47 | # Check if this capital choice gives the highest Value Function value. 48 | if new_v_max > v_max: 49 | 50 | # Update candidate values. 51 | v_max = new_v_max 52 | kt1_optimal = kt1[1] 53 | 54 | return v_max, kt1_optimal 55 | 56 | # ----------------------------------------------------------------------------------------------------- 57 | # Version 2 - using Numpy arrays / broadcast instead of for-loop. 58 | # ----------------------------------------------------------------------------------------------------- 59 | def Solve_HH_Problem_v2(Value_Function, kt0, zt, params): 60 | 61 | # Unpack utility parameters and grids. 62 | alpha, beta, delta = params.alpha, params.beta, params.delta 63 | k_values = params.k_values 64 | z_probs = params.z_probs 65 | 66 | # Calculate array of value function values for all next period capital choices. 67 | V_max_values = (np.log(zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - k_values) 68 | + beta * np.dot(Value_Function, z_probs[zt[0], :])) 69 | 70 | # Get the index for the optimal capital choice. 71 | kt1_index_optimal = np.argmax(V_max_values) 72 | 73 | # Get the optimal Value Function and Policy Function values. 74 | kt1_optimal = k_values[kt1_index_optimal] 75 | v_max = V_max_values[kt1_index_optimal] 76 | 77 | return v_max, kt1_optimal 78 | 79 | # ----------------------------------------------------------------------------------------------------- 80 | # Version 3 - precompiled with numba and using for-loops. 81 | # ----------------------------------------------------------------------------------------------------- 82 | from numba import jit 83 | 84 | @jit(nopython=True) 85 | def Solve_HH_Problem_v3(Value_Function, kt0, zt, params): 86 | 87 | # Unpack utility parameters and grids. 88 | alpha,beta,delta = params.alpha, params.beta, params.delta 89 | k_values = params.k_values 90 | z_probs = params.z_probs 91 | 92 | # Variables to store candidate optimal values for Value Function and Policy Function. 93 | v_max = 0.0 94 | new_v_max = 0.0 95 | kt1_optimal = 0.0 96 | 97 | # Check all possible next period capital choices. 98 | for kt1 in enumerate(k_values): 99 | 100 | # Calculate the Value Function for given starting capital and next period capital choice. 101 | new_v_max = ( log((zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - kt1[1])) 102 | + beta * np.dot(Value_Function[kt1[0], :], z_probs[zt[0], :])) 103 | 104 | # Check if this capital choice gives the highest Value Function value. 105 | if new_v_max > v_max: 106 | 107 | # Update candidate values. 108 | v_max = new_v_max 109 | kt1_optimal = kt1[1] 110 | 111 | return v_max, kt1_optimal 112 | 113 | # ----------------------------------------------------------------------------------------------------- 114 | # Version 4 - precompiled with numba and using numpy arrays instead of for-loop. 115 | # ----------------------------------------------------------------------------------------------------- 116 | from numba import jit 117 | 118 | @jit(nopython=True) 119 | def Solve_HH_Problem_v4(Value_Function, kt0, zt, params): 120 | 121 | # Unpack utility parameters and grids. 122 | alpha,beta,delta = params.alpha, params.beta, params.delta 123 | k_values = params.k_values 124 | z_probs = params.z_probs 125 | 126 | # Calculate array of value function values for all next period capital choices. 127 | V_max_values = (np.log(zt[1] * (kt0[1] ** alpha) + (1 - delta) * kt0[1] - k_values) 128 | + beta * np.dot(Value_Function, z_probs[zt[0], :])) 129 | 130 | # Get the index for the optimal capital choice. 131 | kt1_ind_optimal = np.argmax(V_max_values) 132 | 133 | # Get the optimal Value Function and Policy Function values. 134 | kt1_optimal = k_values[kt1_ind_optimal] 135 | v_max = V_max_values[kt1_ind_optimal] 136 | 137 | return v_max, kt1_optimal -------------------------------------------------------------------------------- /1 - Base Model/fortran.f08: -------------------------------------------------------------------------------- 1 | ! Implementation of Base Model in Fortran (2008). 2 | 3 | program main 4 | implicit none 5 | 6 | ! --------------------------------------------------------------------------------------------------- 7 | ! Declaration Section. 8 | 9 | ! Double precision variables. 10 | real(8), parameter :: alpha = 0.400 11 | real(8), parameter :: beta = 0.987 12 | real(8), parameter :: delta = 1.000 13 | real(8) :: k_steady, k_pct_low, k_pct_high 14 | real(8) :: v_max, kt1_optimal, new_value_function_value 15 | 16 | ! Integer variables. 17 | integer, parameter :: number_of_iterations = 1000 18 | integer, parameter :: number_of_k_values = 201 19 | integer :: i 20 | integer :: iteration, kt0_index, kt1_index 21 | 22 | ! Value Function, Policy Function, and other arrays. 23 | real(8), dimension(number_of_iterations, number_of_k_values) :: Value_Function, Policy_Function 24 | real(8), dimension(number_of_k_values) :: k_values 25 | 26 | ! --------------------------------------------------------------------------------------------------- 27 | ! Execution Section. 28 | 29 | ! Calculate the steady-state level of capital. 30 | k_steady = ((1 - beta * (1 - delta)) / (alpha * beta)) ** (1 / (alpha - 1)) 31 | 32 | ! Create grid of capital values around steady-state (+/- 50%). 33 | k_pct_low = 0.50 34 | k_pct_high = 1.50 35 | 36 | do i = 1, number_of_k_values 37 | k_values(i) = k_steady * (k_pct_low + ((real(i, 8) - 1) / real(number_of_k_values, 8) * (k_pct_high - k_pct_low))) 38 | end do 39 | 40 | ! Assign value of 0 to first value function iteration. 41 | where (Value_Function /= 0.0) Value_Function = 0 42 | where (Policy_Function /= 0.0) Policy_Function = 0 43 | 44 | ! Solve the household's problem for each possible starting state. 45 | do iteration = 2, number_of_iterations 46 | do kt0_index = 1, number_of_k_values 47 | 48 | ! Initialize variables to store candiate optimal values. 49 | v_max = -huge(k_steady) 50 | kt1_optimal = 0.0 51 | new_value_function_value = 0.0 52 | 53 | ! Check all possible next period capital choices. 54 | do kt1_index = 1, number_of_k_values 55 | 56 | ! Calculate the Value Function for given starting capital and next period capital choice. 57 | new_value_function_value = & 58 | log(k_values(kt0_index) ** alpha + (1 - delta) * k_values(kt0_index) - k_values(kt1_index)) & 59 | + beta * Value_Function(iteration - 1, kt1_index) 60 | 61 | ! Check if this capital choice gives the highest Value Function value. 62 | if (new_value_function_value > v_max) then 63 | 64 | ! Update candidate values. 65 | v_max = new_value_function_value 66 | kt1_optimal = k_values(kt1_index) 67 | end if 68 | end do 69 | 70 | ! Update the Value Function and Policy Function with optimal values. 71 | Value_Function(iteration, kt0_index) = v_max 72 | Policy_Function(iteration, kt0_index) = kt1_optimal 73 | 74 | end do 75 | end do 76 | 77 | ! Write the Value Function and Policy Function to csv files. 78 | call WriteArrayToCSV(Value_Function, number_of_iterations, number_of_k_values, "Value_Function.csv") 79 | call WriteArrayToCSV(Policy_Function, number_of_iterations, number_of_k_values, "Policy_Function.csv") 80 | 81 | ! Display the first and last 5 values of the Value Function and Policy Function. 82 | write(*,*) "Value Function V(k)" 83 | do i = 1,5 84 | print '(2 (A, G0.4) )', "V(", k_values(i), ") = ", Value_Function(number_of_iterations, i) 85 | end do 86 | write(*,*) "..." 87 | do i = number_of_k_values-4,number_of_k_values 88 | print '(2 (A, G0.4) )', "V(", k_values(i), ") = ", Value_Function(number_of_iterations, i) 89 | end do 90 | 91 | write(*,*) 92 | write(*,*) "Policy Function g(k)" 93 | do i = 1,5 94 | print '(2 (A, G0.4) )', "g(", k_values(i), ") = ", Policy_Function(number_of_iterations, i) 95 | end do 96 | write(*,*) "..." 97 | do i = number_of_k_values-4,number_of_k_values 98 | print '(2 (A, G0.4) )', "g(", k_values(i), ") = ", Policy_Function(number_of_iterations, i) 99 | end do 100 | 101 | ! Leave window open after program terminates. 102 | call sleep(100) 103 | 104 | end program 105 | 106 | 107 | ! --------------------------------------------------------------------------------------------------- 108 | ! Subroutines. 109 | 110 | ! Writes a 2-dimensional array of real(8) numbers (double floating point precision) to a csv file. 111 | subroutine WriteArrayToCSV(Array2D, n_rows, n_cols, file_name) 112 | 113 | ! ----------------------------------------------------------------------------------------------- 114 | ! Declaration section. 115 | 116 | ! Input variables. 117 | integer, intent(in) :: n_rows, n_cols 118 | character(len=*), intent(in) :: file_name 119 | real(8), dimension(n_rows, n_cols), intent(in) :: Array2D 120 | 121 | ! Local variables. 122 | integer :: i 123 | 124 | ! ----------------------------------------------------------------------------------------------- 125 | ! Execution section. 126 | 127 | ! Formatting for CSV (label = 101) 128 | 101 format(1x, *(g0, ", ")) 129 | 130 | ! Create and open file. 131 | open(unit = 10, access = "sequential", action = "write", & 132 | status = "replace", file = file_name, form = "formatted") 133 | 134 | ! Write each row to file. 135 | do i = 1, n_rows 136 | write(10, 101) Array2D(i,:) 137 | end do 138 | 139 | ! Close file. 140 | close(10) 141 | 142 | end subroutine WriteArrayToCSV 143 | 144 | ! Compiler instructions. 145 | ! debug mode: gfortran fortran.f08 -g -O0 -Wall -o build.exe 146 | ! release mode: gfortran fortran.f08 -O3 -o build.exe 147 | ! run program: start build -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/Fortran/main.f08: -------------------------------------------------------------------------------- 1 | ! Idiosyncratic Endowment model implemented in Fortran (2008). 2 | ! 3 | ! Steps: 4 | ! 1 - Define utility parameters, grids, and parameter struct. 5 | ! 2 - Solve model and get market bond price using binary search. 6 | ! - Guess bond price 7 | ! - Solve model and get market bond price using binary search. 8 | ! - Get the distribution of credit and productivity levels 9 | ! - Check the market clearing condition and update bond price guess 10 | ! 3 - Print results and save to file. 11 | 12 | program main 13 | 14 | use custom_functions 15 | implicit none 16 | 17 | ! --------------------------------------------------------------------------------------------------- 18 | ! Declaration section. 19 | 20 | ! Endowment parameters. 21 | real(8), parameter :: e_high = 1.0 22 | real(8), parameter :: e_low = 0.1 23 | integer, parameter :: number_of_e_values = 2 24 | real(8), dimension(number_of_e_values) :: e_grid = [e_low, e_high] 25 | real(8), dimension(number_of_e_values, number_of_e_values) :: e_probs = & 26 | reshape([0.500, 0.075, 0.500, 0.925], [number_of_e_values, number_of_e_values]) 27 | 28 | ! Utility parameters. 29 | real(8) :: sigma = 1.5 30 | real(8) :: beta = 0.99322 31 | 32 | ! Credit parameters. 33 | real(8) :: a_high = 4 34 | real(8) :: a_low = -2 35 | integer, parameter :: number_of_a_values = 100 36 | real(8), dimension(number_of_a_values) :: a_grid 37 | 38 | ! Bonds prices and iteration parameters. 39 | real(8) :: q, q_min, q_max, mcc 40 | real(8) :: dist, tolerance 41 | integer :: iteration_count, max_iterations, a_index, e_index, i 42 | 43 | ! Value Function, Policy Functions, and Population Distribution. 44 | real(8), dimension(number_of_e_values, number_of_a_values) :: Value_Function = 0 45 | real(8), dimension(number_of_e_values, number_of_a_values) :: Policy_Function, & 46 | Population_Distribution, Value_Function_New, Policy_Function_New, Population_Distribution_New 47 | integer, dimension(number_of_e_values, number_of_a_values) :: Policy_Function_Index, & 48 | Policy_Function_Index_New 49 | 50 | ! Struct to store utility parameters and capital/productivity grids for passing to a function. 51 | type(Parameters) :: params 52 | 53 | ! --------------------------------------------------------------------------------------------------- 54 | ! Execution section. 55 | 56 | ! Create grid of credit values. 57 | do i = 1, number_of_a_values 58 | a_grid(i) = a_low + (a_high - a_low) * real(i - 1, 8) / real(number_of_a_values - 1, 8) 59 | end do 60 | 61 | ! Store parameters in a struct for passing to a function. 62 | params = Parameters(sigma, beta, number_of_a_values, number_of_e_values, a_grid, e_grid, e_probs) 63 | 64 | ! Range of bond values to search. 65 | q_min = 0.985 66 | q_max = 1.100 67 | 68 | ! Optional: floor for q_min such that those at credit limit can still afford positive consumption. 69 | q_min = (a_low + e_low) / a_low 70 | 71 | ! Placeholder for the market clearing condition. 72 | mcc = huge(mcc); 73 | 74 | ! Iteration parameters. 75 | dist = huge(dist); 76 | iteration_count = 0; 77 | max_iterations = 20; 78 | tolerance = 1e-3; 79 | 80 | ! Solve for market price q. 81 | do while ((dist > tolerance) .and. (iteration_count < max_iterations)) 82 | 83 | ! Get value of q from middle of range. 84 | q = (q_min + q_max) / 2 85 | 86 | ! Solve for the Value Function and Policy Function. 87 | call Solve_Value_Function(q, params, Value_Function, Policy_Function, Policy_Function_Index, & 88 | Value_Function_New, Policy_Function_New, Policy_Function_Index_New) 89 | 90 | ! Get the Population Distribution. 91 | call Get_Population_Distribution(Policy_Function_Index, params, & 92 | Population_Distribution, Population_Distribution_New) 93 | 94 | ! Check the market clearing condition. 95 | call Calculate_Market_Clearing_Condition(mcc, Population_Distribution, Policy_Function) 96 | 97 | ! Update search parameters. 98 | dist = abs(mcc) 99 | iteration_count = iteration_count + 1 100 | 101 | ! Update range of q according to the sign of the market clearing condition. 102 | if (mcc > 0) q_min = q 103 | if (mcc < 0) q_max = q 104 | 105 | ! Print results. 106 | write (*,*) "Iteration", iteration_count, " ", "q=", q, "mcc=", mcc; 107 | end do 108 | 109 | ! Write final Value Function, Policy Function, and Population Distribution to csv files. 110 | call WriteArrayToCSV(transpose(Value_Function), number_of_a_values, number_of_e_values, "Value_Function.csv") 111 | call WriteArrayToCSV(transpose(Policy_Function), number_of_a_values, number_of_e_values, "Policy_Function.csv") 112 | call WriteArrayToCSV(transpose(Population_Distribution), number_of_a_values, number_of_e_values, "Population_Distribution.csv") 113 | 114 | ! Display subset of results: Value Function for certain capital and productivity terms. 115 | write(*,*) NEW_LINE('A'), "Value Function", NEW_LINE('A') 116 | do a_index = 1, 10 117 | do e_index = 1, 2 118 | write(*, '(4x, f8.3)', advance='no') Value_Function(e_index, a_index) 119 | end do 120 | write(*,*) NEW_LINE('A') 121 | end do 122 | call sleep(100) 123 | 124 | end program 125 | 126 | ! Compilier instructions. 127 | 128 | ! Debug and profiling: 129 | ! gfortran -g -O0 -Wall -pg -o obj/custom_functions.o -c src/custom_functions.f08 130 | ! gfortran -g -O0 -Wall -pg -o obj/main.o -c src/main.f08 131 | ! gfortran -g -O0 -Wall -pg -o build obj/custom_functions.o obj/main.o 132 | ! run program: start build 133 | ! profile: gprof build.exe 134 | 135 | ! Release: 136 | ! gfortran -O3 -o obj/custom_functions.o -c src/custom_functions.f08 137 | ! gfortran -O3 -o obj/main.o -c src/main.f08 138 | ! gfortran -O3 -o build obj/custom_functions.o obj/main.o 139 | ! rm obj/custom_functions.o obj/main.o custom_functions.d main.d build 140 | -------------------------------------------------------------------------------- /3 - Idiosyncratic Endowment/C++/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Idiosyncratic Endowment model implemented in C++. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Solve model and get market bond price using binary search. 7 | - Guess bond price 8 | - Solve for the Value Function and Policy Function 9 | - Get the distribution of credit and productivity levels 10 | - Check the market clearing condition and update bond price guess 11 | 3 - Plot results. 12 | */ 13 | 14 | #include 15 | #include "custom_functions.h" 16 | 17 | int main() 18 | { 19 | // ----------------------------------------------------------------------------------------------------- 20 | // 1 - Define utility parameters, grids, and parameter struct. 21 | // ----------------------------------------------------------------------------------------------------- 22 | 23 | // Endowment parameters. 24 | double e_high = 1.0; // high endowment 25 | double e_low = 0.1; // low endowment 26 | int const number_of_e_values = 2; 27 | vector e_grid = { e_low, e_high }; // endowment grid 28 | Array2D e_probs = { {0.500, 0.500}, {0.075, 0.925} }; // endowment transition probabilities 29 | 30 | // Utility parameters. 31 | double sigma = 1.5; // risk aversion coefficient 32 | double beta = 0.99322; // discount factor 33 | 34 | // Credit parameters. 35 | double a_high = 4; // upper credit limit 36 | double a_low = -2; // lower credit limit 37 | int const number_of_a_values = 50; // credit grid size 38 | 39 | // Create grid of credit values. 40 | vector a_grid(number_of_a_values); 41 | for (int i = 0; i < number_of_a_values; i++) 42 | { 43 | a_grid[i] = a_low + (a_high - a_low) * double(i) / double(number_of_a_values - 1); 44 | } 45 | 46 | // Store parameters in a struct for passing to a function. 47 | Parameters params = Parameters { sigma, beta, number_of_a_values, number_of_e_values, a_grid, e_grid, e_probs }; 48 | 49 | // Value Function, Policy Functions, Population Distribution. 50 | Array2D Value_Function(number_of_a_values, vector(number_of_e_values)); 51 | Array2D Policy_Function(number_of_a_values, vector(number_of_e_values)); 52 | Array2D Policy_Function_Index(number_of_a_values, vector(number_of_e_values)); 53 | Array2D Population_Distribution(number_of_a_values, vector(number_of_e_values)); 54 | 55 | // ----------------------------------------------------------------------------------------------------- 56 | // 2 - Solve model and get market bond price using binary search. 57 | // ----------------------------------------------------------------------------------------------------- 58 | 59 | // Range of bond price values to search. 60 | double q_min = 0.985; 61 | double q_max = 1.100; 62 | 63 | // Optional: floor for q_min such that those at credit limit can still afford positive consumption. 64 | q_min = (a_low + e_low) / a_low; 65 | 66 | // Placeholder for the market clearing condition. 67 | double mcc = DBL_MAX; 68 | 69 | // Iteration parameters. 70 | double dist = DBL_MAX; 71 | int iteration_count = 0; 72 | int max_iterations = 20; 73 | double tolerance = 1e-3; 74 | 75 | // Solve for market price q. 76 | while ((dist > tolerance) && (iteration_count < max_iterations)) 77 | { 78 | // Get value of q from middle of range. 79 | double q = (q_min + q_max) / 2; 80 | 81 | // Solve for the Value Function and Policy Function. 82 | Solve_Value_Function(q, params, Value_Function, Policy_Function, Policy_Function_Index); 83 | 84 | // Get the Population Distribution. 85 | Get_Population_Distribution(Policy_Function_Index, params, Population_Distribution); 86 | 87 | // Check the market clearing condition. 88 | mcc = Calculate_Market_Clearing_Condition(Population_Distribution, Policy_Function); 89 | 90 | // Update search parameters; 91 | dist = abs(mcc); 92 | iteration_count++; 93 | 94 | // Update the range of q according to the sign of the market clearing condition. 95 | if (mcc > 0) { q_min = q; }; 96 | if (mcc < 0) { q_max = q; }; 97 | 98 | // Print results. 99 | std::cout << "Iteration " << iteration_count << ": q=" << q << ", mcc=" << mcc << "\n"; 100 | if (iteration_count >= max_iterations) 101 | { 102 | std::cout << "Warning: search for q did not converge after " << iteration_count << " iterations \n"; 103 | } 104 | 105 | } 106 | 107 | // ----------------------------------------------------------------------------------------------------- 108 | // 3 - Display results and write to csv files. 109 | // ----------------------------------------------------------------------------------------------------- 110 | 111 | // Write the final Value Function, Policy Function, and Population Distribution to csv files. 112 | WriteArrayToCSV(Value_Function, "Value_Function.csv"); 113 | WriteArrayToCSV(Policy_Function, "Policy_Function.csv"); 114 | WriteArrayToCSV(Population_Distribution, "Population_Distribution.csv"); 115 | 116 | // Display subset of results: Value Function for certain capital and productivity terms. 117 | std::cout.precision(4); 118 | std::cout << "\n Value Function \n e = " << e_grid[0] << " \t e = " << e_grid[1] << "\n"; 119 | for (int a_index = 0; a_index < 10; a_index++) 120 | { 121 | for (int e_index = 0; e_index < 2; e_index++) 122 | { 123 | std::cout << Value_Function[a_index][e_index] << "\t \t"; 124 | } 125 | std::cout << "\n"; 126 | } 127 | 128 | return 0; 129 | } -------------------------------------------------------------------------------- /2 - Stochastic Growth/Fortran/custom_functions.f08: -------------------------------------------------------------------------------- 1 | module custom_functions 2 | implicit none 3 | 4 | ! Data structure to store parameters. 5 | type Parameters 6 | real(8) :: alpha, beta, delta 7 | integer :: number_of_k_values, number_of_z_values 8 | real(8), allocatable, dimension(:) :: k_values 9 | real(8), allocatable, dimension(:) :: z_values 10 | real(8), allocatable, dimension(:,:) :: z_probs 11 | end type Parameters 12 | 13 | ! Function declarations. 14 | contains 15 | 16 | ! Function to solve the household's problem for a given starting state. 17 | subroutine Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params) 18 | 19 | ! ----------------------------------------------------------------------------------------------- 20 | ! Declaration section. 21 | 22 | ! Input variables. 23 | real(8), dimension(:,:,:), intent(inout) :: Value_Function, Policy_Function 24 | integer, intent(in) :: iteration, kt0_index, zt_index 25 | type(Parameters), intent(in) :: params 26 | 27 | ! Variables for solving the household's problem. 28 | real(8) :: v_max, kt1_optimal, new_value_function_value, kt0, zt 29 | real(8) :: new_v_max, kt1, current_period_payoff, future_period_payoff 30 | integer :: kt1_index, z_prob_index 31 | 32 | ! ----------------------------------------------------------------------------------------------- 33 | ! Execution section. 34 | 35 | ! Get starting capital and productivity values from index. 36 | kt0 = params%k_values(kt0_index) 37 | zt = params%z_values(zt_index) 38 | 39 | ! Variables to store candidate optimal values. 40 | v_max = -huge(kt0) 41 | kt1_optimal = 0.0 42 | new_value_function_value = 0.0 43 | 44 | do kt1_index = 1, params%number_of_k_values 45 | 46 | ! Get capital value from index. 47 | kt1 = params%k_values(kt1_index) 48 | 49 | ! Calculate value function for a given next period capital choice. 50 | current_period_payoff = log(zt * (kt0 ** params%alpha) + (1 - params%delta) * kt0 - kt1) 51 | 52 | future_period_payoff = 0.0 53 | 54 | do z_prob_index = 1, params%number_of_z_values 55 | future_period_payoff = future_period_payoff + & 56 | Value_Function(z_prob_index, kt1_index, iteration - 1) * params%z_probs(zt_index, z_prob_index) 57 | end do 58 | 59 | new_v_max = current_period_payoff + params%beta * future_period_payoff 60 | 61 | ! Check if this capital choice gives the highest Value Function value. 62 | if (new_v_max > v_max) then 63 | 64 | ! Update candidate values. 65 | v_max = new_v_max 66 | kt1_optimal = kt1_index 67 | end if 68 | end do 69 | 70 | ! Update the Value Function and Policy Funtion with optimal values. 71 | Value_Function(zt_index, kt0_index, iteration) = v_max 72 | Policy_Function(zt_index, kt0_index, iteration) = kt1_optimal 73 | end subroutine 74 | 75 | 76 | ! Function to write a 2-dimensional array to csv file. 77 | subroutine WriteArrayToCSV(Array2D, n_rows, n_cols, file_name) 78 | 79 | ! ----------------------------------------------------------------------------------------------- 80 | ! Declaration section. 81 | 82 | ! Input variables. 83 | integer, intent(in) :: n_rows, n_cols 84 | character(len=*), intent(in) :: file_name 85 | real(8), dimension(n_rows, n_cols), intent(in) :: Array2D 86 | 87 | ! Local variables. 88 | integer :: i 89 | 90 | ! ----------------------------------------------------------------------------------------------- 91 | ! Execution section. 92 | 93 | ! Formatting for CSV (label = 101) 94 | 101 format(1x, *(g0, ", ")) 95 | 96 | ! Create and open file. 97 | open(unit = 10, access = "sequential", action = "write", & 98 | status = "replace", file = file_name, form = "formatted") 99 | 100 | ! Write each row to file. 101 | do i = 1, n_rows 102 | write(10, 101) Array2D(i,:) 103 | end do 104 | 105 | ! Close file. 106 | close(10) 107 | 108 | end subroutine 109 | 110 | 111 | ! Function to read a vector from csv file (stored column-wise). 112 | subroutine ReadVectorFromCSV(file_path, n_rows, Output_Vector) 113 | 114 | ! ----------------------------------------------------------------------------------------------- 115 | ! Declaration section. 116 | 117 | ! Input and output variables. 118 | character(len=*), intent(in) :: file_path 119 | integer, intent(in) :: n_rows 120 | real(8), dimension(n_rows), intent(out) :: Output_Vector 121 | 122 | ! Local variables. 123 | integer :: i 124 | 125 | ! ----------------------------------------------------------------------------------------------- 126 | ! Execution section. 127 | 128 | ! Open file. 129 | open(unit=10, file=file_path, access="sequential") 130 | 131 | ! Read file row-by-row. 132 | do i = 1, n_rows 133 | read(10,*) Output_Vector(i) 134 | end do 135 | 136 | ! Close file. 137 | close(unit=10) 138 | 139 | end subroutine 140 | 141 | 142 | ! Function to read a 2-dimensional array from csv file. 143 | subroutine ReadArrayFromCSV(file_path, n_rows, n_cols, Output_Array) 144 | 145 | ! ----------------------------------------------------------------------------------------------- 146 | ! Declaration section. 147 | 148 | ! Input and output variables. 149 | character(len=*), intent(in) :: file_path 150 | integer, intent(in) :: n_rows, n_cols 151 | real(8), dimension(n_rows, n_cols), intent(out) :: Output_Array 152 | 153 | ! Local variables. 154 | integer :: i 155 | 156 | ! ----------------------------------------------------------------------------------------------- 157 | ! Execution section. 158 | 159 | ! Open file. 160 | open(unit=10, file=file_path, access="sequential") 161 | 162 | ! Read file row-by-row. 163 | do i = 1, n_rows 164 | read(10,*) Output_Array(i,:) 165 | end do 166 | 167 | ! Close file. 168 | close(unit=10) 169 | 170 | end subroutine 171 | 172 | end module custom_functions -------------------------------------------------------------------------------- /Extra content/Fortran project template/src/custom_functions.f08: -------------------------------------------------------------------------------- 1 | module custom_functions 2 | implicit none 3 | 4 | ! Data structure to store parameters. 5 | type Parameters 6 | real(8) :: alpha, beta, delta 7 | integer :: number_of_k_values, number_of_z_values 8 | real(8), allocatable, dimension(:) :: k_values 9 | real(8), allocatable, dimension(:) :: z_values 10 | real(8), allocatable, dimension(:,:) :: z_probs 11 | end type Parameters 12 | 13 | ! Function declarations. 14 | contains 15 | 16 | ! Function to solve the household's problem for a given starting state. 17 | subroutine Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params) 18 | 19 | ! ----------------------------------------------------------------------------------------------- 20 | ! Declaration section. 21 | 22 | ! Input variables. 23 | real(8), dimension(:,:,:), intent(inout) :: Value_Function, Policy_Function 24 | integer, intent(in) :: iteration, kt0_index, zt_index 25 | type(Parameters), intent(in) :: params 26 | 27 | ! Variables for solving the household's problem. 28 | real(8) :: v_max, kt1_optimal, new_value_function_value, kt0, zt 29 | real(8) :: new_v_max, kt1, current_period_payoff, future_period_payoff 30 | integer :: kt1_index, z_prob_index 31 | 32 | ! ----------------------------------------------------------------------------------------------- 33 | ! Execution section. 34 | 35 | ! Get starting capital and productivity values from index. 36 | kt0 = params%k_values(kt0_index) 37 | zt = params%z_values(zt_index) 38 | 39 | ! Variables to store candidate optimal values. 40 | v_max = -huge(kt0) 41 | kt1_optimal = 0.0 42 | new_value_function_value = 0.0 43 | 44 | do kt1_index = 1, params%number_of_k_values 45 | 46 | ! Get capital value from index. 47 | kt1 = params%k_values(kt1_index) 48 | 49 | ! Calculate value function for a given next period capital choice. 50 | current_period_payoff = log(zt * (kt0 ** params%alpha) + (1 - params%delta) * kt0 - kt1) 51 | 52 | future_period_payoff = 0.0 53 | 54 | do z_prob_index = 1, params%number_of_z_values 55 | future_period_payoff = future_period_payoff + & 56 | Value_Function(z_prob_index, kt1_index, iteration - 1) * params%z_probs(zt_index, z_prob_index) 57 | end do 58 | 59 | new_v_max = current_period_payoff + params%beta * future_period_payoff 60 | 61 | ! Check if this capital choice gives the highest Value Function value. 62 | if (new_v_max > v_max) then 63 | 64 | ! Update candidate values. 65 | v_max = new_v_max 66 | kt1_optimal = kt1_index 67 | end if 68 | end do 69 | 70 | ! Update the Value Function and Policy Funtion with optimal values. 71 | Value_Function(zt_index, kt0_index, iteration) = v_max 72 | Policy_Function(zt_index, kt0_index, iteration) = kt1_optimal 73 | end subroutine 74 | 75 | 76 | ! Function to write a 2-dimensional array to csv file. 77 | subroutine WriteArrayToCSV(Array2D, n_rows, n_cols, file_name) 78 | 79 | ! ----------------------------------------------------------------------------------------------- 80 | ! Declaration section. 81 | 82 | ! Input variables. 83 | integer, intent(in) :: n_rows, n_cols 84 | character(len=*), intent(in) :: file_name 85 | real(8), dimension(n_rows, n_cols), intent(in) :: Array2D 86 | 87 | ! Local variables. 88 | integer :: i 89 | 90 | ! ----------------------------------------------------------------------------------------------- 91 | ! Execution section. 92 | 93 | ! Formatting for CSV (label = 101) 94 | 101 format(1x, *(g0, ", ")) 95 | 96 | ! Create and open file. 97 | open(unit = 10, access = "sequential", action = "write", & 98 | status = "replace", file = file_name, form = "formatted") 99 | 100 | ! Write each row to file. 101 | do i = 1, n_rows 102 | write(10, 101) Array2D(i,:) 103 | end do 104 | 105 | ! Close file. 106 | close(10) 107 | 108 | end subroutine 109 | 110 | 111 | ! Function to read a vector from csv file (stored column-wise). 112 | subroutine ReadVectorFromCSV(file_path, n_rows, Output_Vector) 113 | 114 | ! ----------------------------------------------------------------------------------------------- 115 | ! Declaration section. 116 | 117 | ! Input and output variables. 118 | character(len=*), intent(in) :: file_path 119 | integer, intent(in) :: n_rows 120 | real(8), dimension(n_rows), intent(out) :: Output_Vector 121 | 122 | ! Local variables. 123 | integer :: i 124 | 125 | ! ----------------------------------------------------------------------------------------------- 126 | ! Execution section. 127 | 128 | ! Open file. 129 | open(unit=10, file=file_path, access="sequential") 130 | 131 | ! Read file row-by-row. 132 | do i = 1, n_rows 133 | read(10,*) Output_Vector(i) 134 | end do 135 | 136 | ! Close file. 137 | close(unit=10) 138 | 139 | end subroutine 140 | 141 | 142 | ! Function to read a 2-dimensional array from csv file. 143 | subroutine ReadArrayFromCSV(file_path, n_rows, n_cols, Output_Array) 144 | 145 | ! ----------------------------------------------------------------------------------------------- 146 | ! Declaration section. 147 | 148 | ! Input and output variables. 149 | character(len=*), intent(in) :: file_path 150 | integer, intent(in) :: n_rows, n_cols 151 | real(8), dimension(n_rows, n_cols), intent(out) :: Output_Array 152 | 153 | ! Local variables. 154 | integer :: i 155 | 156 | ! ----------------------------------------------------------------------------------------------- 157 | ! Execution section. 158 | 159 | ! Open file. 160 | open(unit=10, file=file_path, access="sequential") 161 | 162 | ! Read file row-by-row. 163 | do i = 1, n_rows 164 | read(10,*) Output_Array(i,:) 165 | end do 166 | 167 | ! Close file. 168 | close(unit=10) 169 | 170 | end subroutine 171 | 172 | end module custom_functions -------------------------------------------------------------------------------- /Extra content/C++ implementation using C-style base arrays/3 - Idiosyncratic Endowment/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Idiosyncratic Endowment model implemented in C++. 3 | 4 | Steps: 5 | 1 - Define utility parameters, grids, and parameter struct. 6 | 2 - Solve model and get market bond price using binary search. 7 | - Guess bond price 8 | - Solve for the Value Function and Policy Function 9 | - Get the distribution of credit and productivity levels 10 | - Check the market clearing condition and update bond price guess 11 | 3 - Plot results. 12 | */ 13 | 14 | #include "custom_functions.h" 15 | #include 16 | #include 17 | 18 | int main() 19 | { 20 | // ----------------------------------------------------------------------------------------------------- 21 | // 1 - Define utility parameters, grids, and parameter struct. 22 | // ----------------------------------------------------------------------------------------------------- 23 | 24 | // Endowment parameters. 25 | double e_high = 1.0; // high endowment 26 | double e_low = 0.1; // low endowment 27 | int const number_of_e_values = 2; 28 | double e_grid[number_of_e_values] = { e_low, e_high }; // endowment grid 29 | double e_probs[number_of_e_values * number_of_e_values] 30 | = { 0.500, 0.500, 0.075, 0.925 }; // endowment transition probabilities 31 | 32 | // Utility parameters. 33 | double sigma = 1.5; // risk aversion coefficient 34 | double beta = 0.99322; // discount factor 35 | 36 | // Credit parameters. 37 | double a_high = 4; // upper credit limit 38 | double a_low = -2; // lower credit limit 39 | int const number_of_a_values = 100; // credit grid size 40 | 41 | // Create grid of credit values. 42 | double a_grid[number_of_a_values]; 43 | for (int i = 0; i < number_of_a_values; i++) 44 | { 45 | a_grid[i] = a_low + (a_high - a_low) * double(i) / double(number_of_a_values - 1); 46 | } 47 | 48 | // Store parameters in a struct for passing to a function. 49 | Parameters params = { sigma, beta, number_of_a_values, number_of_e_values, a_grid, e_grid, e_probs }; 50 | 51 | // Value Function, Policy Functions, Population Distribution. 52 | double Value_Function[number_of_a_values * number_of_e_values] = { 0 }; 53 | double Policy_Function[number_of_a_values * number_of_e_values]; 54 | int Policy_Function_Index[number_of_a_values * number_of_e_values]; 55 | double Population_Distribution[number_of_a_values * number_of_e_values]; 56 | 57 | // Placeholders for next Value Function iteration and search for q. 58 | double Value_Function_New[number_of_a_values * number_of_e_values]; 59 | double Policy_Function_New[number_of_a_values * number_of_e_values]; 60 | int Policy_Function_Index_New[number_of_a_values * number_of_e_values]; 61 | double Population_Distribution_New[number_of_a_values * number_of_e_values]; 62 | 63 | // ----------------------------------------------------------------------------------------------------- 64 | // 2 - Solve model and get market bond price using binary search. 65 | // ----------------------------------------------------------------------------------------------------- 66 | 67 | // Range of bond prices values to search. 68 | double q_min = 0.985; 69 | double q_max = 1.100; 70 | 71 | // Optional: floor for q_min such that those at credit limit can still afford positive consumption. 72 | q_min = (a_low + e_low) / a_low; 73 | 74 | // Placeholder for the market clearing condition. 75 | double mcc = DBL_MAX; 76 | 77 | // Iteration parameters. 78 | double dist = DBL_MAX; 79 | int iteration_count = 0; 80 | int max_iterations = 20; 81 | double tolerance = 1e-3; 82 | 83 | // Solve for market price q. 84 | while ((dist > tolerance) && (iteration_count < max_iterations)) 85 | { 86 | // Get value of q from middle of range. 87 | double q = (q_min + q_max) / 2; 88 | 89 | // Solve for the Value Function and Policy Function. 90 | Solve_Value_Function(q, params, Value_Function, Policy_Function, Policy_Function_Index, 91 | Value_Function_New, Policy_Function_New, Policy_Function_Index_New); 92 | 93 | // Get the Population Distribution. 94 | Get_Population_Distribution(Policy_Function_Index, params, 95 | Population_Distribution, Population_Distribution_New); 96 | 97 | // Check market clearing condition. 98 | mcc = Calculate_Market_Clearing_Condition(Population_Distribution, Policy_Function, 99 | number_of_a_values, number_of_e_values); 100 | 101 | // Update search parameters; 102 | dist = abs(mcc); 103 | iteration_count++; 104 | 105 | // Update range of q according to the sign of the market clearing condition. 106 | if (mcc > 0) { q_min = q; }; 107 | if (mcc < 0) { q_max = q; }; 108 | 109 | // Print results. 110 | std::cout << "Iteration " << iteration_count << ": q=" << q << ", mcc=" << mcc << "\n"; 111 | if (iteration_count >= max_iterations) 112 | { 113 | std::cout << "Warning: search for q did not converge after " << iteration_count << " iterations \n"; 114 | } 115 | 116 | } 117 | 118 | // ----------------------------------------------------------------------------------------------------- 119 | // 3 - Display results and write to csv files. 120 | // ----------------------------------------------------------------------------------------------------- 121 | 122 | // Write final Value Function, Policy Function, and Population Distribution to csv files. 123 | WriteArrayToCSV(Value_Function, "Value_Function.csv", number_of_a_values, number_of_e_values); 124 | WriteArrayToCSV(Policy_Function, "Policy_Function.csv", number_of_a_values, number_of_e_values); 125 | WriteArrayToCSV(Population_Distribution, "Population_Distribution.csv", number_of_a_values, number_of_e_values); 126 | 127 | // Display subset of results: Value Function for certain capital and productivity terms. 128 | std::cout.precision(4); 129 | std::cout << "\n Value Function \n e = " << e_grid[0] << " \t e = " << e_grid[1] << "\n"; 130 | for (int a_index = 0; a_index < 10; a_index++) 131 | { 132 | for (int e_index = 0; e_index < 2; e_index++) 133 | { 134 | std::cout << Value_Function[a_index * number_of_e_values + e_index] << "\t \t"; 135 | } 136 | std::cout << "\n"; 137 | } 138 | 139 | return 0; 140 | } -------------------------------------------------------------------------------- /Extra content/C++ multi-threading implementation/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stochastic Growth Model implemented in C++. 3 | 4 | This is the basic multi-threaded implementation using only the standard library. 5 | The changes for this multi-threaded implementations are on lines 76-120. 6 | 7 | Steps: 8 | 1 - Define utility parameters, grids, and parameter struct. 9 | 2 - Perform value function iteration. 10 | 3 - Display results, save results to file, clean up. 11 | 12 | Notes on multi-threaded implementation 13 | - Introduces a lambda function which applies the Solve_HH_Problem over all capital values 14 | for a fixed productivity value (i.e. solves one column of the value function). 15 | - The lambda function is run in parallel threads for all productivity values (i.e. the columns 16 | of the value function are solved in parallel). 17 | - Threads are stored in a list and must be terminated before passing to the next iteration. 18 | - Threads are created and destroyed in each iteration. This avoids the need for additional code 19 | or packages to manage threads, but introduces additional overhead. 20 | - Net improvement is ~4x (uses up to 85% of 6-core 12-thread CPU). 21 | - Requires custom_functions.h and custom_functions.cpp from the Stochastic Growth Model. 22 | */ 23 | 24 | #include "custom_functions.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | using std::thread; 30 | 31 | int main() 32 | { 33 | for (int m = 0; m < 10; m++) { 34 | // Assign parameter values. 35 | double alpha = 0.400; 36 | double beta = 0.987; 37 | double delta = 0.012; 38 | int const number_of_iterations = 1000; 39 | 40 | // Calculate the steady-state level of capital. 41 | double k_steady = pow(((1 - beta * (1 - delta)) / (alpha * beta)), (1 / (alpha - 1))); 42 | 43 | // Create a grid of capital values around the steady-state (+/- 2%). 44 | int const number_of_k_values = 201; 45 | double k_low_pct = 0.98; 46 | double k_high_pct = 1.02; 47 | vector k_values(number_of_k_values); 48 | 49 | for (int i = 0; i < number_of_k_values; i++) 50 | { 51 | k_values[i] = k_low_pct * k_steady + (double(i) / (double(number_of_k_values) - 1)) * ((k_high_pct - k_low_pct) * k_steady); 52 | } 53 | 54 | // Get productivity levels and transition probabilities from csv files (as vector arrays). 55 | std::string directory = "C:/Users/Ray/Documents/GitHub/DSGE-models/2 - Stochastic Growth/c++/Inputs/"; 56 | Array2D z_probs = ReadArrayFromCSV(directory + "z_probs.csv"); 57 | vector z_values = ReadVectorFromCSV(directory + "z_values.csv"); 58 | int number_of_z_values = z_values.size(); 59 | 60 | // Initialize the Value Function and Policy Function (as arrays). 61 | Array3D Value_Function(number_of_iterations, vector>(number_of_k_values, vector(number_of_z_values))); 62 | Array3D Policy_Function(number_of_iterations, vector>(number_of_k_values, vector(number_of_z_values))); 63 | 64 | // Assign value of 0 to first iteration. 65 | for (int i = 0; i < number_of_k_values; i++) 66 | { 67 | for (int j = 0; j < number_of_z_values; j++) 68 | { 69 | Value_Function[0][i][j] = 0.0; 70 | Policy_Function[0][i][j] = 0.0; 71 | } 72 | } 73 | 74 | // Store utility parameters and capital/productivity grids in a struct for passing to a function. 75 | Parameters params = { alpha, beta, delta, number_of_k_values, number_of_z_values, k_values, z_values, z_probs }; 76 | 77 | // Perform value function iteration. 78 | for (int iteration = 1; iteration < number_of_iterations; iteration++) 79 | { 80 | /* // Original loop (inner 2 loops) that gets converted into multi-threaded implementation. 81 | for (int iteration = 1; iteration < number_of_iterations; iteration++) 82 | { 83 | // Loop over all possible starting states. 84 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 85 | { 86 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 87 | { 88 | // Solve the Value Function and Policy Function. 89 | Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params); 90 | } 91 | } 92 | } */ 93 | 94 | // Lambda function which takes a zt_index and solves the HH problem for all k_values at this zt_index. 95 | // The function is applied in parallel over the 11 zt_index values. 96 | // See documentation: https://learn.microsoft.com/en-us/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170 97 | auto Solve_HH_Lambda = [&, iteration](int zt_index) { 98 | 99 | // Loop over all kt0_index starting states. 100 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 101 | { 102 | // Solve the Value Function and Policy Function. 103 | Solve_HH_Problem(Value_Function, Policy_Function, iteration, kt0_index, zt_index, params); 104 | } 105 | }; 106 | 107 | // Vector to store thread objects. 108 | vector Threads; 109 | 110 | // Loop over all possible zt_index starting states. 111 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 112 | { 113 | // Create a thread for this zt_index and store in vector of threads. 114 | thread thread_object = thread(Solve_HH_Lambda, zt_index); 115 | Threads.push_back(std::move(thread_object)); 116 | 117 | // Alternatively: 118 | //Threads.push_back(thread(Solve_HH_Lambda, zt_index)); 119 | } 120 | 121 | // Wait for all threads to terminate. 122 | for (thread& thread_object : Threads) 123 | { 124 | // .join() method forces the program to wait for each thread to finish. 125 | if (thread_object.joinable()) { thread_object.join(); } 126 | } 127 | } 128 | 129 | // Get slice of Value Function and Policy Function for final iteration. 130 | Array2D Final_Value_Function(number_of_k_values, vector(number_of_z_values)); 131 | Array2D Final_Policy_Function(number_of_k_values, vector(number_of_z_values)); 132 | 133 | for (int kt0_index = 0; kt0_index < number_of_k_values; kt0_index++) 134 | { 135 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 136 | { 137 | Final_Value_Function[kt0_index][zt_index] = Value_Function[number_of_iterations - 1][kt0_index][zt_index]; 138 | Final_Policy_Function[kt0_index][zt_index] = Policy_Function[number_of_iterations - 1][kt0_index][zt_index]; 139 | } 140 | } 141 | 142 | // Write final Value Function and Policy Function to csv files. 143 | WriteArrayToCSV(Final_Value_Function, number_of_k_values, number_of_z_values, "Value_Function.csv"); 144 | WriteArrayToCSV(Final_Policy_Function, number_of_k_values, number_of_z_values, "Policy_Function.csv"); 145 | 146 | // Display a subset of results: the final Value Function for certain capital and prodcutivity values. 147 | for (int kt0_index = 0; kt0_index < 10; kt0_index++) 148 | { 149 | for (int zt_index = 0; zt_index < number_of_z_values; zt_index++) 150 | { 151 | std::cout << Value_Function[number_of_iterations - 1][kt0_index][zt_index] << "\t"; 152 | } 153 | std::cout << "\n"; 154 | } 155 | 156 | 157 | } 158 | std::cin.get(); 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /Extra content/C++ implementation using C-style base arrays/2 - Stochastric Growth/custom_functions.cpp: -------------------------------------------------------------------------------- 1 | #include "custom_functions.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Function to solve the household's problem for a given starting state. 10 | void Solve_HH_Problem(double*** Value_Function, double*** Policy_Function, int iteration, int kt0_index, int zt_index, Parameters params) 11 | { 12 | // Unpack utility parameters and grids. 13 | double alpha = params.alpha; 14 | double beta = params.beta; 15 | double delta = params.delta; 16 | double* k_values = params.k_values; 17 | double* z_values = params.z_values; 18 | double** z_probs = params.z_probs; 19 | int number_of_k_values = params.number_of_k_values; 20 | int number_of_z_values = params.number_of_z_values; 21 | 22 | // Get starting capital and productivity values from index. 23 | double kt0 = k_values[kt0_index]; 24 | double zt = z_values[zt_index]; 25 | 26 | // Variables to store candidate optimal values. 27 | double v_max = -DBL_MAX; 28 | double kt1_optimal = 0.0; 29 | double new_v_max; 30 | 31 | for (int kt1_index = 0; kt1_index < params.number_of_k_values; kt1_index++) 32 | { 33 | // Get capital value from index. 34 | double kt1 = params.k_values[kt1_index]; 35 | 36 | // Calculate value function for a given next period capital choice. 37 | double current_period_payoff, future_period_payoff; 38 | 39 | current_period_payoff = log((zt * pow(kt0, params.alpha)) + ((1 - params.delta) * kt0) - kt1); 40 | 41 | future_period_payoff = 0.0; 42 | for (int z_prob_index = 0; z_prob_index < params.number_of_z_values; z_prob_index++) 43 | { 44 | future_period_payoff += Value_Function[iteration - 1][kt1_index][z_prob_index] * params.z_probs[zt_index][z_prob_index]; 45 | } 46 | 47 | new_v_max = current_period_payoff + params.beta * future_period_payoff; 48 | 49 | // Check if this capital choice gives the highest Value Function value. 50 | if (new_v_max > v_max) 51 | { 52 | // Update candidate values. 53 | v_max = new_v_max; 54 | kt1_optimal = kt1; 55 | } 56 | } 57 | 58 | // Update the Value Function and Policy Function with optimal values. 59 | Value_Function[iteration][kt0_index][zt_index] = v_max; 60 | Policy_Function[iteration][kt0_index][zt_index] = kt1_optimal; 61 | } 62 | 63 | // Function to dynamically allocate memory for a 3-dimensional array. 64 | double*** InitializeArray3D(int size_dim_1, int size_dim_2, int size_dim_3) 65 | { 66 | double*** Array3D; // create pointer variable for start of array 67 | 68 | Array3D = new double** [size_dim_1]; // allocate vector of pointers for dimension 1 that will point to dimension 2 vectors 69 | 70 | for (int i = 0; i < size_dim_1; i++) 71 | { 72 | Array3D[i] = new double* [size_dim_2]; // allocate vector of pointers for dimension 2 that will point to dimension 3 vectors 73 | 74 | for (int j = 0; j < size_dim_2; j++) 75 | { 76 | Array3D[i][j] = new double[size_dim_3]; // allocate vector of doubles for dimension 3 77 | } 78 | } 79 | return Array3D; 80 | } 81 | 82 | // Function to clear the memory allocated for a 3-dimensional array. 83 | void DeleteArray3D(double*** Array3D, int size_dim_1, int size_dim_2, int size_dim_3) 84 | { 85 | for (int i = 0; i < size_dim_1; i++) 86 | { 87 | for (int j = 0; j < size_dim_2; j++) 88 | { 89 | delete[] Array3D[i][j]; // delete each dimension 3 vector of data 90 | } 91 | delete[] Array3D[i]; // delete each dimension 2 vector of pointers 92 | } 93 | delete[] Array3D; // delete pointer to dimension 1 vector of pointers 94 | } 95 | 96 | // Function to dynamically allocate memory for a 2-dimensional array. 97 | double** InitializeArray2D(int n_rows, int n_cols) 98 | { 99 | double** Array2D; 100 | Array2D = new double* [n_rows]; // create rows of pointers 101 | for (int i = 0; i < n_rows; i++) 102 | { 103 | Array2D[i] = new double[n_cols]; // create column of pointers for each row 104 | } 105 | return Array2D; 106 | } 107 | 108 | // Function to clear the memory allocated for a 2-dimensional array. 109 | void DeleteArray2D(double** Array2D, int n_rows, int n_cols) 110 | { 111 | for (int i = 0; i < n_rows; i++) 112 | { 113 | delete[] Array2D[i]; 114 | } 115 | delete[] Array2D; 116 | } 117 | 118 | // Function to write a 2-dimensional array to csv file. 119 | void WriteArrayToCSV(double** Array2D, int n_rows, int n_cols, const char* file_name) 120 | { 121 | std::ofstream write_output(file_name); 122 | assert(write_output.is_open()); 123 | 124 | for (int i = 0; i < n_rows; i++) 125 | { 126 | for (int j = 0; j < n_cols; j++) 127 | { 128 | write_output << Array2D[i][j] << ","; 129 | } 130 | write_output << "\n"; 131 | } 132 | write_output.close(); 133 | } 134 | 135 | // Function to read a 2-dimensional array from csv file. 136 | double** ReadArrayFromCSV(std::string path) 137 | { 138 | // Vector of vectors to store csv conents. 139 | std::vector> content_array; 140 | std::vector row; 141 | std::string line, values; 142 | 143 | // Load file. 144 | std::fstream file(path, std::ios::in); 145 | assert(file.is_open()); 146 | 147 | // Get data from a specific row. 148 | while (getline(file, line)) 149 | { 150 | row.clear(); 151 | 152 | std::stringstream row_string(line); 153 | 154 | // Get the individual values from each column 155 | while (getline(row_string, values, ',')) 156 | { 157 | row.push_back(std::stod(values)); // get values in each row, and convert from string to double with stod() 158 | } 159 | content_array.push_back(row); // add row to content array. 160 | } 161 | 162 | // Convert from std::vector to base dynamic array. 163 | int n_rows = content_array.size(); 164 | int n_cols = content_array[0].size(); 165 | double** Base_array = InitializeArray2D(n_rows, n_cols); 166 | 167 | for (int i = 0; i < n_rows; i++) 168 | { 169 | for (int j = 0; j < n_cols; j++) 170 | { 171 | Base_array[i][j] = content_array[i][j]; 172 | } 173 | } 174 | return Base_array; 175 | } 176 | 177 | // Function to read a vector from csv file (stored column-wise). 178 | double* ReadVectorFromCSV(std::string path) 179 | { 180 | // Vector of vectors to store csv conents. 181 | std::vector content_vector; 182 | std::string value; 183 | 184 | // Load file. 185 | std::fstream file(path, std::ios::in); 186 | assert(file.is_open()); 187 | 188 | // Go through each row 189 | while (getline(file, value)) 190 | { 191 | // Get element, convert to double, and add to the output vector. 192 | content_vector.push_back(std::stod(value)); 193 | } 194 | 195 | // Convert from std::vector to base dynamic array. 196 | int n_rows = content_vector.size(); 197 | double* base_vector = new double[n_rows]; 198 | 199 | for (int i = 0; i < n_rows; i++) 200 | { 201 | base_vector[i] = content_vector[i]; 202 | } 203 | 204 | return base_vector; 205 | } 206 | 207 | // Alternative: read an array from file and write to a given static array. 208 | template 209 | void ReadArrayFromCSV(std::string path, double(&Static_Array)[n_rows][n_cols]) 210 | { 211 | // Read array from file. 212 | double** Dynamic_Array = ReadArrayFromCSV(path); 213 | 214 | // Write to given array. 215 | for (int i = 0; i < n_rows; i++) 216 | { 217 | for (int j = 0; j < n_cols; j++) 218 | { 219 | Static_Array[i][j] = Dynamic_Array[i][j]; 220 | } 221 | } 222 | } 223 | 224 | // Alternative: read a vector from file and write to a given static vector. 225 | template 226 | void ReadVectorFromCSV(std::string path, double(&static_vector)[n_rows]) 227 | { 228 | // Read vector from file. 229 | double* dynamic_vector = ReadVectorFromCSV(path); 230 | 231 | // Write to given vector. 232 | for (int i = 0; i < n_rows; i++) 233 | { 234 | static_vector[i] = dynamic_vector[i]; 235 | } 236 | } --------------------------------------------------------------------------------