├── CUDA_main.cu ├── Cpp_main.cpp ├── Julia_main_parallel.jl ├── Julia_main_pmap.jl ├── MPI_host_file ├── MPI_main.cpp ├── Makefile ├── Makefile~ ├── Matlab_main.m ├── Python_main.py ├── R_main.R ├── Rcpp_main.R ├── Rcpp_main.cpp ├── Readme.md └── Readme.md~ /CUDA_main.cu: -------------------------------------------------------------------------------- 1 | // [[Rcpp::depends(RcppArmadillo)]] 2 | // [[Rcpp::depends(RcppEigen)]] 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | //====================================== 9 | // Grids 10 | //====================================== 11 | 12 | void gridx(const int nx, const double xmin, const double xmax, double* xgrid){ 13 | 14 | const double size = nx; 15 | const double xstep = (xmax - xmin) /(size - 1); 16 | double it = 0; 17 | 18 | for(int i = 0; i < nx; i++){ 19 | xgrid[i] = xmin + it*xstep; 20 | it++; 21 | } 22 | } 23 | 24 | 25 | void gride(const int ne, const double ssigma_eps, const double llambda_eps, const double m, double* egrid){ 26 | 27 | // This grid is made with Tauchen (1986) 28 | const double size = ne; 29 | const double ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 30 | const double estep = 2*ssigma_y*m / (size-1); 31 | double it = 0; 32 | 33 | for(int i = 0; i < ne; i++){ 34 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 35 | it++; 36 | } 37 | } 38 | 39 | double normCDF(const double value){ 40 | return 0.5 * erfc(-value * M_SQRT1_2); 41 | } 42 | 43 | 44 | 45 | void eprob(const int ne, const double ssigma_eps, const double llambda_eps, const double m, const double* egrid, double* P){ 46 | 47 | // This grid is made with Tauchen (1986) 48 | // P is: first ne elements are transition from e_0 to e_i, 49 | // second ne elementrs are from e_1 to e_i, ... 50 | const double w = egrid[1] - egrid[0]; 51 | 52 | for(int j = 0; j < ne; j++){ 53 | for(int k = 0; k < ne; k++){ 54 | if(k == 0){ 55 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 56 | } else if(k == ne-1){ 57 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 58 | } else{ 59 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps) - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 60 | } 61 | } 62 | } 63 | } 64 | 65 | 66 | 67 | //====================================== 68 | // Parameter structure 69 | //====================================== 70 | 71 | class parameters{ 72 | public: 73 | int nx; 74 | double xmin; 75 | double xmax; 76 | int ne; 77 | double ssigma_eps; 78 | double llambda_eps; 79 | double m; 80 | 81 | double ssigma; 82 | double eeta; 83 | double ppsi; 84 | double rrho; 85 | double llambda; 86 | double bbeta; 87 | int T; 88 | double r; 89 | double w; 90 | 91 | void load(const char*); 92 | }; 93 | 94 | 95 | 96 | //====================================== 97 | // MAIN MAIN MAIN 98 | //====================================== 99 | 100 | __global__ void Vmaximization(const parameters params, const double* xgrid, const double* egrid, const double* P, const int age, double* V){ 101 | 102 | // Recover the parameters 103 | const int nx = params.nx; 104 | const int ne = params.ne; 105 | const double ssigma = params.ssigma; 106 | const double bbeta = params.bbeta; 107 | const int T = params.T; 108 | const double r = params.r; 109 | const double w = params.w; 110 | 111 | // Recover state variables from indices 112 | const int ix = blockIdx.x * blockDim.x + threadIdx.x; 113 | const int ie = threadIdx.y; 114 | 115 | double expected; 116 | double utility; 117 | double cons; 118 | double VV = pow(-10.0,5.0); 119 | 120 | for(int ixp = 0; ixp < nx; ixp++){ 121 | 122 | expected = 0.0; 123 | if(age < T-1){ 124 | for(int iep = 0; iep < ne; iep++){ 125 | expected = expected + P[ie*ne + iep]*V[(age+1)*nx*ne + ixp*ne + iep]; 126 | } 127 | } 128 | 129 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 130 | 131 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 132 | 133 | if(cons <= 0){ 134 | utility = pow(-10.0, 5.0); 135 | } 136 | 137 | if(utility >= VV){ 138 | VV = utility; 139 | } 140 | 141 | utility = 0.0; 142 | } 143 | 144 | V[age*nx*ne + ix*ne + ie] = VV; 145 | } 146 | 147 | 148 | 149 | int main() 150 | { 151 | // Grids 152 | const int nx = 300; 153 | const double xmin = 0.1; 154 | const double xmax = 4.0; 155 | const int ne = 15; 156 | const double ssigma_eps = 0.02058; 157 | const double llambda_eps = 0.99; 158 | const double m = 1.5; 159 | 160 | // Parameters 161 | const double ssigma = 2; 162 | const double eeta = 0.36; 163 | const double ppsi = 0.89; 164 | const double rrho = 0.5; 165 | const double llambda = 1; 166 | const double bbeta = 0.97; 167 | const int T = 10; 168 | 169 | // Prices 170 | const double r = 0.07; 171 | const double w = 5; 172 | 173 | parameters params = {nx, xmin, xmax, ne, ssigma_eps, llambda_eps, m, ssigma, eeta, ppsi, rrho, llambda, bbeta, T, r, w}; 174 | 175 | // Pointers to variables in the DEVICE memory 176 | double *V, *X, *E, *P; 177 | size_t sizeX = nx*sizeof(double); 178 | size_t sizeE = ne*sizeof(double); 179 | size_t sizeP = ne*ne*sizeof(double); 180 | size_t sizeV = T*ne*nx*sizeof(double); 181 | 182 | cudaMalloc((void**)&X, sizeX); 183 | cudaMalloc((void**)&E, sizeE); 184 | cudaMalloc((void**)&P, sizeP); 185 | cudaMalloc((void**)&V, sizeV); 186 | 187 | // Parameters for CUDA: cada block tiene ne columnas, y una fila que representa un valor de x 188 | // Hay nx blocks 189 | // Cada layer es una edad >= hay 80 layers 190 | 191 | const int block_size = 30; 192 | dim3 dimBlock(block_size, ne); 193 | dim3 dimGrid(nx/block_size, 1); 194 | 195 | 196 | // Variables in the host have "h" prefix 197 | // I create the grid for X 198 | double hxgrid[nx]; 199 | gridx(nx, xmin, xmax, hxgrid); 200 | 201 | // I create the grid for E and the probability matrix 202 | double hegrid[ne]; 203 | double hP[ne*ne]; 204 | gride(ne, ssigma_eps, llambda_eps, m, hegrid); 205 | eprob(ne, ssigma_eps, llambda_eps, m, hegrid, hP); 206 | 207 | // Exponential of the grid e 208 | for(int i=0; i=0; age--){ 232 | Vmaximization<<>>(params, X, E, P, age, V); 233 | cudaDeviceSynchronize(); 234 | 235 | t = clock() - t0; 236 | std::cout << "Age: " << age << ". Time: " << ((double)t)/CLOCKS_PER_SEC << " seconds." << std::endl; 237 | 238 | } 239 | 240 | std::cout << " " << std::endl; 241 | t = clock() - t0; 242 | std::cout << "TOTAL ELAPSED TIME: " << ((double)t)/CLOCKS_PER_SEC << " seconds. " << std::endl; 243 | 244 | cudaMemcpy(hV, V, sizeV, cudaMemcpyDeviceToHost); 245 | 246 | // Free variables in device memory 247 | cudaFree(V); 248 | cudaFree(X); 249 | cudaFree(E); 250 | cudaFree(P); 251 | 252 | std::cout << " " << std::endl; 253 | std::cout << " - - - - - - - - - - - - - - - - - - - - - " << std::endl; 254 | std::cout << " " << std::endl; 255 | std::cout << "The first entries of the value function: " << std::endl; 256 | std::cout << " " << std::endl; 257 | 258 | for(int i = 0; i<3; i++){ 259 | std::cout << hV[i] << std::endl; 260 | } 261 | 262 | std::cout << " " << std::endl; 263 | 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /Cpp_main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | //====================================== 10 | // Grids 11 | //====================================== 12 | 13 | void gridx(const int nx, const float xmin, const float xmax, float* xgrid){ 14 | 15 | const float size = nx; 16 | const float xstep = (xmax - xmin) /(size - 1); 17 | float it = 0; 18 | 19 | for(int i = 0; i < nx; i++){ 20 | xgrid[i] = xmin + it*xstep; 21 | it++; 22 | } 23 | } 24 | 25 | 26 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 27 | 28 | // This grid is made with Tauchen (1986) 29 | const float size = ne; 30 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 31 | const float estep = 2*ssigma_y*m / (size-1); 32 | float it = 0; 33 | 34 | for(int i = 0; i < ne; i++){ 35 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 36 | it++; 37 | } 38 | } 39 | 40 | float normCDF(const float value){ 41 | return 0.5 * erfc(-value * M_SQRT1_2); 42 | } 43 | 44 | 45 | 46 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 47 | 48 | // This grid is made with Tauchen (1986) 49 | // P is: first ne elements are transition from e_0 to e_i, 50 | // second ne elementrs are from e_1 to e_i, ... 51 | const float w = egrid[1] - egrid[0]; 52 | 53 | for(int j = 0; j < ne; j++){ 54 | for(int k = 0; k < ne; k++){ 55 | if(k == 0){ 56 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 57 | } else if(k == ne-1){ 58 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 59 | } else{ 60 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps) - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 61 | } 62 | } 63 | } 64 | } 65 | 66 | 67 | //====================================== 68 | // MAIN MAIN MAIN 69 | //====================================== 70 | 71 | 72 | int main() 73 | { 74 | 75 | //--------------------------------// 76 | // Initialization // 77 | //--------------------------------// 78 | 79 | // Grid for x 80 | const int nx = 300; 81 | const float xmin = 0.1; 82 | const float xmax = 4.0; 83 | 84 | // Grid for e 85 | const int ne = 15; 86 | const float ssigma_eps = 0.02058; 87 | const float llambda_eps = 0.99; 88 | const float m = 1.5; 89 | 90 | // Utility function 91 | const float ssigma = 2; 92 | const float eeta = 0.36; 93 | const float ppsi = 0.89; 94 | const float rrho = 0.5; 95 | const float llambda = 1; 96 | const float bbeta = 0.97; 97 | const int T = 10; 98 | 99 | // Prices 100 | const float r = 0.07; 101 | const float w = 5; 102 | 103 | // I create the grid for X 104 | float xgrid[nx]; 105 | 106 | // I create the grid for E and the probability matrix 107 | float egrid[ne]; 108 | float P[ne*ne]; 109 | 110 | 111 | //--------------------------------// 112 | // Grid creation // 113 | //--------------------------------// 114 | 115 | gridx(nx, xmin, xmax, xgrid); 116 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 117 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 118 | 119 | // Exponential of the grid e 120 | for(int i=0; i=0; age--){ 147 | 148 | #pragma omp parallel for shared(V, age, P, xgrid, egrid, t, t0) private(expected, cons, utility, VV) 149 | for(int ix = 0; ix= VV){ 170 | VV = utility; 171 | } 172 | } 173 | 174 | V[age*nx*ne + ix*ne + ie] = VV; 175 | } 176 | } 177 | 178 | t = omp_get_wtime() - t0; 179 | cout << "Age: " << age << ". Time: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds." << endl; 180 | } 181 | 182 | cout << " " << endl; 183 | t = omp_get_wtime() - t0; 184 | cout << "TOTAL ELAPSED TIME: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds. " << endl; 185 | 186 | 187 | //--------------------------------// 188 | // Some checks // 189 | //--------------------------------// 190 | 191 | cout << " " << endl; 192 | cout << " - - - - - - - - - - - - - - - - - - - - - " << endl; 193 | cout << " " << endl; 194 | cout << "The first entries of the value function: " << endl; 195 | cout << " " << endl; 196 | 197 | for(int i = 0; i<3; i++){ 198 | cout << V[i] << endl; 199 | } 200 | cout << " " << endl; 201 | 202 | return 0; 203 | } 204 | -------------------------------------------------------------------------------- /Julia_main_parallel.jl: -------------------------------------------------------------------------------- 1 | #--------------------------------# 2 | # House-keeping # 3 | #--------------------------------# 4 | 5 | workspace() 6 | using Distributions 7 | 8 | #--------------------------------# 9 | # Initialization # 10 | #--------------------------------# 11 | 12 | # Number of workers 13 | # addprocs(8) 14 | 15 | # Grid for x 16 | @everywhere nx = 300; 17 | xmin = 0.1; 18 | xmax = 4.0; 19 | 20 | # Grid for e: parameters for Tauchen 21 | @everywhere ne = 15; 22 | ssigma_eps = 0.02058; 23 | llambda_eps = 0.99; 24 | m = 1.5; 25 | 26 | # Utility function 27 | @everywhere ssigma = 2; 28 | @everywhere eeta = 0.36; 29 | @everywhere ppsi = 0.89; 30 | @everywhere rrho = 0.5; 31 | @everywhere llambda = 1; 32 | @everywhere bbeta = 0.97; 33 | @everywhere T = 10; 34 | 35 | # Prices 36 | @everywhere r = 0.07; 37 | @everywhere w = 5; 38 | 39 | # Initialize grids 40 | @everywhere xgrid = zeros(nx) 41 | @everywhere egrid = zeros(ne) 42 | @everywhere P = zeros(ne, ne) 43 | @everywhere V = zeros(T, nx, ne) 44 | 45 | # Initialize value function as a shared array 46 | tempV = SharedArray{Float64}(ne*nx, init = tempV -> tempV[Base.localindexes(tempV)] = myid()) 47 | 48 | #--------------------------------# 49 | # Grid creation # 50 | #--------------------------------# 51 | 52 | # Grid for x 53 | size = nx; 54 | xstep = (xmax - xmin) /(size - 1); 55 | it = 0; 56 | for i = 1:nx 57 | xgrid[i] = xmin + it*xstep; 58 | it = it+1; 59 | end 60 | 61 | # Grid for e with Tauchen (1986) 62 | size = ne; 63 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 64 | estep = 2*ssigma_y*m / (size-1); 65 | it = 0; 66 | for i = 1:ne 67 | egrid[i] = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + it*estep); 68 | it = it+1; 69 | end 70 | 71 | # Transition probability matrix Tauchen (1986) 72 | mm = egrid[2] - egrid[1]; 73 | for j = 1:ne 74 | for k = 1:ne 75 | if(k == 1) 76 | P[j, k] = cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 77 | elseif(k == ne) 78 | P[j, k] = 1 - cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 79 | else 80 | P[j, k] = cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps) - cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 81 | end 82 | end 83 | end 84 | 85 | # Exponential of the grid e 86 | for i = 1:ne 87 | egrid[i] = exp(egrid[i]); 88 | end 89 | 90 | #--------------------------------# 91 | # Life-cycle computation # 92 | #--------------------------------# 93 | 94 | print(" \n") 95 | print("Life cycle computation: \n") 96 | print(" \n") 97 | 98 | start = Dates.unix2datetime(time()) 99 | 100 | for age = T:-1:1 101 | 102 | @sync @parallel for ind = 1:(ne*nx) 103 | 104 | ix = convert(Int, ceil(ind/ne)); 105 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 106 | 107 | VV = -10^3; 108 | 109 | for ixp = 1:nx 110 | 111 | expected = 0.0; 112 | if(age < T) 113 | for iep = 1:ne 114 | expected = expected + P[ie, iep]*V[age+1, ixp, iep]; 115 | end 116 | end 117 | 118 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 119 | 120 | utility = (cons^(1-ssigma))/(1-ssigma) + bbeta*expected; 121 | 122 | if(cons <= 0) 123 | utility = -10^(5); 124 | end 125 | 126 | if(utility >= VV) 127 | VV = utility; 128 | end 129 | 130 | end 131 | 132 | tempV[ind] = VV; 133 | end 134 | 135 | for ind = 1:(ne*nx) 136 | 137 | ix = convert(Int, ceil(ind/ne)); 138 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 139 | 140 | V[age, ix, ie] = tempV[ind] 141 | end 142 | 143 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 144 | print("Age: ", age, ". Time: ", finish, " seconds. \n") 145 | end 146 | 147 | print("\n") 148 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 149 | print("TOTAL ELAPSED TIME: ", finish, " seconds. \n") 150 | 151 | #---------------------# 152 | # Some checks # 153 | #---------------------# 154 | 155 | print(" \n") 156 | print(" - - - - - - - - - - - - - - - - - - - - - \n") 157 | print(" \n") 158 | print("The first entries of the value function: \n") 159 | print(" \n") 160 | 161 | # I print the first entries of the value function, to check 162 | for i = 1:3 163 | print(round(V[1, 1, i], 5), "\n") 164 | end 165 | -------------------------------------------------------------------------------- /Julia_main_pmap.jl: -------------------------------------------------------------------------------- 1 | #--------------------------------# 2 | # House-keeping # 3 | #--------------------------------# 4 | 5 | workspace() 6 | using Distributions 7 | 8 | #--------------------------------# 9 | # Initialization # 10 | #--------------------------------# 11 | 12 | # Number of workers 13 | # addprocs(1) 14 | 15 | # Grid for x 16 | nx = 300; 17 | xmin = 0.1; 18 | xmax = 4.0; 19 | 20 | # Grid for e: parameters for Tauchen 21 | ne = 15; 22 | ssigma_eps = 0.02058; 23 | llambda_eps = 0.99; 24 | m = 1.5; 25 | 26 | # Utility function 27 | ssigma = 2; 28 | eeta = 0.36; 29 | ppsi = 0.89; 30 | rrho = 0.5; 31 | llambda = 1; 32 | bbeta = 0.97; 33 | T = 10; 34 | 35 | # Prices 36 | r = 0.07; 37 | w = 5; 38 | 39 | # Initialize grids 40 | xgrid = zeros(nx) 41 | egrid = zeros(ne) 42 | P = zeros(ne, ne) 43 | V = zeros(T, nx, ne) 44 | 45 | #--------------------------------# 46 | # Grid creation # 47 | #--------------------------------# 48 | 49 | # Grid for x 50 | size = nx; 51 | xstep = (xmax - xmin) /(size - 1); 52 | it = 0; 53 | for i = 1:nx 54 | xgrid[i] = xmin + it*xstep; 55 | it = it+1; 56 | end 57 | 58 | # Grid for e with Tauchen (1986) 59 | size = ne; 60 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 61 | estep = 2*ssigma_y*m / (size-1); 62 | it = 0; 63 | for i = 1:ne 64 | egrid[i] = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + it*estep); 65 | it = it+1; 66 | end 67 | 68 | # Transition probability matrix Tauchen (1986) 69 | mm = egrid[2] - egrid[1]; 70 | for j = 1:ne 71 | for k = 1:ne 72 | if(k == 1) 73 | P[j, k] = cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 74 | elseif(k == ne) 75 | P[j, k] = 1 - cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 76 | else 77 | P[j, k] = cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps) - cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 78 | end 79 | end 80 | end 81 | 82 | # Exponential of the grid e 83 | for i in 1:ne 84 | egrid[i] = exp(egrid[i]); 85 | end 86 | 87 | 88 | #--------------------------------# 89 | # Structure and function # 90 | #--------------------------------# 91 | 92 | # Value function structure 93 | @everywhere type modelState 94 | ind::Int64 95 | ne::Int64 96 | nx::Int64 97 | T::Int64 98 | age::Int64 99 | P::Array{Float64,2} 100 | xgrid::Vector{Float64} 101 | egrid::Vector{Float64} 102 | ssigma::Float64 103 | bbeta::Float64 104 | V::Array{Float64,3} 105 | w::Float64 106 | r::Float64 107 | end 108 | 109 | @everywhere function value(currentState::modelState) 110 | 111 | ind = currentState.ind 112 | age = currentState.age 113 | ne = currentState.ne 114 | nx = currentState.nx 115 | T = currentState.T 116 | P = currentState.P 117 | xgrid = currentState.xgrid 118 | egrid = currentState.egrid 119 | ssigma = currentState.ssigma 120 | bbeta = currentState.bbeta 121 | w = currentState.w 122 | r = currentState.r 123 | V = currentState.V 124 | 125 | ix = convert(Int, floor((ind-0.05)/ne))+1; 126 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 127 | 128 | VV = -10^3; 129 | ixpopt = 0; 130 | 131 | 132 | for ixp = 1:nx 133 | 134 | expected = 0.0; 135 | if(age < T) 136 | for iep = 1:ne 137 | expected = expected + P[ie, iep]*V[age+1, ixp, iep]; 138 | end 139 | end 140 | 141 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 142 | 143 | utility = (cons^(1-ssigma))/(1-ssigma) + bbeta*expected; 144 | 145 | if(cons <= 0) 146 | utility = -10^(5); 147 | end 148 | 149 | if(utility >= VV) 150 | VV = utility; 151 | ixpopt = ixp; 152 | end 153 | 154 | utility = 0.0; 155 | end 156 | 157 | return(VV); 158 | 159 | end 160 | 161 | 162 | #--------------------------------# 163 | # Life-cycle computation # 164 | #--------------------------------# 165 | 166 | print(" \n") 167 | print("Life cycle computation: \n") 168 | print(" \n") 169 | 170 | start = Dates.unix2datetime(time()) 171 | 172 | for age = T:-1:1 173 | 174 | pars = [modelState(ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta, V,w,r) for ind in 1:ne*nx]; 175 | 176 | s = pmap(value,pars) 177 | 178 | for ind = 1:nx*ne 179 | ix = convert(Int, floor((ind-0.05)/ne))+1; 180 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 181 | 182 | V[age, ix, ie] = s[ind] 183 | end 184 | 185 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 186 | print("Age: ", age, ". Time: ", finish, " seconds. \n") 187 | 188 | end 189 | 190 | print("\n") 191 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 192 | print("TOTAL ELAPSED TIME: ", finish, " seconds. \n") 193 | 194 | 195 | #---------------------# 196 | # Some checks # 197 | #---------------------# 198 | 199 | print(" \n") 200 | print(" - - - - - - - - - - - - - - - - - - - - - \n") 201 | print(" \n") 202 | print("The first entries of the value function: \n") 203 | print(" \n") 204 | 205 | # For comparison, I print first entries of value function 206 | for i = 1:3 207 | print(round(V[1, 1, i], 5), "\n") 208 | end 209 | -------------------------------------------------------------------------------- /MPI_host_file: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /MPI_main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by David Zarruk Valencia on June, 2016. 3 | // Copyright (c) 2016 David Zarruk Valencia. All rights reserved. 4 | // 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | 13 | //====================================== 14 | // Grids 15 | //====================================== 16 | 17 | void gridx(const int nx, const float xmin, const float xmax, float* xgrid){ 18 | 19 | const float size = nx; 20 | const float xstep = (xmax - xmin) /(size - 1); 21 | float it = 0; 22 | 23 | for(int i = 0; i < nx; i++){ 24 | xgrid[i] = xmin + it*xstep; 25 | it++; 26 | } 27 | } 28 | 29 | 30 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 31 | 32 | // This grid is made with Tauchen (1986) 33 | const float size = ne; 34 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 35 | const float estep = 2*ssigma_y*m / (size-1); 36 | float it = 0; 37 | 38 | for(int i = 0; i < ne; i++){ 39 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 40 | it++; 41 | } 42 | } 43 | 44 | float normCDF(const float value){ 45 | return 0.5 * erfc(-value * M_SQRT1_2); 46 | } 47 | 48 | 49 | 50 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 51 | 52 | // This grid is made with Tauchen (1986) 53 | // P is: first ne elements are transition from e_0 to e_i, 54 | // second ne elementrs are from e_1 to e_i, ... 55 | const float w = egrid[1] - egrid[0]; 56 | 57 | for(int j = 0; j < ne; j++){ 58 | for(int k = 0; k < ne; k++){ 59 | if(k == 0){ 60 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 61 | } else if(k == ne-1){ 62 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 63 | } else{ 64 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps) - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 65 | } 66 | } 67 | } 68 | } 69 | 70 | 71 | //====================================== 72 | // MAIN MAIN MAIN 73 | //====================================== 74 | 75 | 76 | int main() 77 | { 78 | 79 | //--------------------------------// 80 | // MPI // 81 | //--------------------------------// 82 | 83 | // Thread id and number of threads 84 | int tid,nthreads; 85 | 86 | // Initialize MPI 87 | MPI_Init(NULL, NULL); 88 | MPI_Comm_rank(MPI_COMM_WORLD, &tid); 89 | MPI_Comm_size(MPI_COMM_WORLD, &nthreads); 90 | 91 | 92 | //--------------------------------// 93 | // Initialization // 94 | //--------------------------------// 95 | 96 | // Grid for x 97 | const int nx = 300; 98 | const float xmin = 0.1; 99 | const float xmax = 4.0; 100 | 101 | // Grid for e 102 | const int ne = 15; 103 | const float ssigma_eps = 0.02058; 104 | const float llambda_eps = 0.99; 105 | const float m = 1.5; 106 | 107 | // Utility function 108 | const float ssigma = 2; 109 | const float eeta = 0.36; 110 | const float ppsi = 0.89; 111 | const float rrho = 0.5; 112 | const float llambda = 1; 113 | const float bbeta = 0.97; 114 | const int T = 10; 115 | 116 | // Prices 117 | const float r = 0.07; 118 | const float w = 5; 119 | 120 | // Initialize the grid for X 121 | float xgrid[nx]; 122 | 123 | // Initialize the grid for E and the probability matrix 124 | float egrid[ne]; 125 | float P[ne*ne]; 126 | 127 | //--------------------------------// 128 | // Grid creation // 129 | //--------------------------------// 130 | 131 | gridx(nx, xmin, xmax, xgrid); 132 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 133 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 134 | 135 | // Exponential of the grid e 136 | for(int i=0; i=0; age--){ 195 | 196 | // Synchronize 197 | MPI_Barrier(MPI_COMM_WORLD); 198 | MPI_Bcast(Val, (T*ne*nx), MPI_FLOAT, 0, MPI_COMM_WORLD); 199 | 200 | iter = 0; 201 | 202 | for(int ind = loop_min; ind < loop_max; ind++){ 203 | 204 | ix = floor(ind/ne); 205 | ie = ind % ne; 206 | 207 | VV = pow(-10, 5); 208 | 209 | for(int ixp = 0; ixp < nx; ixp++){ 210 | 211 | expected = 0.0; 212 | if(age < T-1){ 213 | for(int iep = 0; iep < ne; iep++){ 214 | expected = expected + P[ie*ne + iep]*Val[(age+1)*nx*ne + ixp*ne + iep]; 215 | } 216 | } 217 | 218 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 219 | 220 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 221 | 222 | if(cons <= 0){ 223 | utility = pow(-10.0, 5.0); 224 | } 225 | 226 | if(utility >= VV){ 227 | VV = utility; 228 | } 229 | } 230 | 231 | Valp[iter] = VV; 232 | iter = iter + 1; 233 | } 234 | 235 | MPI_Gatherv(Valp, leng, MPI_FLOAT, Val1, rcounts, displs, MPI_FLOAT, 0, MPI_COMM_WORLD); 236 | 237 | if(tid == 0){ 238 | for(int ind = 0; ind < (nx*ne); ind++){ 239 | 240 | ix = floor(ind/ne); 241 | ie = ind % ne; 242 | 243 | Val[age*nx*ne + ix*ne + ie] = Val1[ix*ne + ie]; 244 | } 245 | 246 | t = MPI_Wtime() - t0; 247 | cout << "Age: " << age << ". Time: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds." << endl; 248 | } 249 | } 250 | 251 | MPI_Finalize(); 252 | 253 | if(tid == 0){ 254 | std::cout << " " << std::endl; 255 | t = MPI_Wtime() - t0; 256 | std::cout << "TOTAL ELAPSED TIME: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds. " << std::endl; 257 | } 258 | 259 | 260 | // //--------------------------------// 261 | // // Some checks // 262 | // //--------------------------------// 263 | 264 | if(tid == 0){ 265 | std::cout << " " << std::endl; 266 | std::cout << " - - - - - - - - - - - - - - - - - - - - - " << std::endl; 267 | std::cout << " " << std::endl; 268 | std::cout << "The first entries of the value function: " << std::endl; 269 | std::cout << " " << std::endl; 270 | 271 | for(int i = 0; i<3; i++){ 272 | std::cout << Val[i] << std::endl; 273 | } 274 | } 275 | 276 | return 0; 277 | } 278 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # Home directory 3 | HOMET=/home/davidza/ 4 | 5 | # Ask the number of cores to be used in the parallelization: 6 | CORES := $(shell bash -c 'read -p "Enter the number of cores for parallelization: " pwd; echo $$pwd') 7 | 8 | 9 | # Execute the code for each language 10 | cpp: 11 | g++ Cpp_main.cpp -fopenmp -o Cpp_main 12 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 13 | rm Cpp_main 14 | 15 | julia_parallel: 16 | julia -p$(CORES) Julia_main_parallel.jl 17 | 18 | julia_pmap: 19 | julia -p$(CORES) Julia_main_pmap.jl 20 | 21 | Rcpp: 22 | export OMP_NUM_THREADS=$(CORES); Rscript Rcpp_main.R; 23 | 24 | R: 25 | Rscript R_main.R $(CORES) 26 | 27 | python: 28 | python Python_main.py $(CORES) 29 | 30 | matlab: 31 | matlab -nodesktop -nodisplay -r "Matlab_main $(CORES)" 32 | 33 | MPI: 34 | mpic++ -g MPI_main.cpp -o main 35 | mpirun -np $(CORES) -hostfile MPI_host_file ./main 36 | rm main 37 | 38 | CUDA: 39 | nvcc CUDA_main.cu -o main 40 | ./main 41 | rm main 42 | 43 | -------------------------------------------------------------------------------- /Makefile~: -------------------------------------------------------------------------------- 1 | 2 | # Home directory 3 | HOMET=/home/davidza/ 4 | 5 | # Ask the number of cores to be used in the parallelization: 6 | CORES := $(shell bash -c 'read -p "Enter the number of cores for parallelization: " pwd; echo $$pwd') 7 | 8 | 9 | # Execute the code for each language 10 | cpp: 11 | g++ Cpp_main.cpp -fopenmp -o Cpp_main 12 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 13 | rm Cpp_main 14 | 15 | julia_parallel: 16 | julia -p$(CORES) Julia_main_parallel.jl 17 | 18 | julia_pmap: 19 | julia -p$(CORES) Julia_main_pmap.jl 20 | 21 | Rcpp: 22 | export OMP_NUM_THREADS=$(CORES); Rscript Rcpp_main.R; 23 | 24 | R: 25 | Rscript R_main.R $(CORES) 26 | 27 | python: 28 | python Python_main.py $(CORES) 29 | 30 | matlab: 31 | matlab -nodesktop -nodisplay -r "Matlab_main $(CORES)" 32 | 33 | MPI: 34 | mpic++ -g MPI_main.cpp -o main 35 | mpirun -np $(CORES) -hostfile MPI_host_file ./main 36 | rm main 37 | 38 | CUDA: 39 | export PATH=/usr/local/cuda/bin/:$PATH 40 | export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH 41 | nvcc CUDA_main.cu -o main 42 | ./main 43 | rm main 44 | 45 | -------------------------------------------------------------------------------- /Matlab_main.m: -------------------------------------------------------------------------------- 1 | function []=Matlab_main(cores) 2 | %--------------------------------% 3 | % House-keeping % 4 | %--------------------------------% 5 | 6 | %clc 7 | 8 | %--------------------------------% 9 | % Initialization % 10 | %--------------------------------% 11 | 12 | % Number of workers 13 | parpool(str2num(cores)); 14 | 15 | % Grid for x 16 | nx = 300; 17 | xmin = 0.1; 18 | xmax = 4.0; 19 | 20 | % Grid for e: parameters for Tauchen 21 | ne = 15; 22 | ssigma_eps = 0.02058; 23 | llambda_eps = 0.99; 24 | m = 1.5; 25 | 26 | % Utility function 27 | ssigma = 2; 28 | eeta = 0.36; 29 | ppsi = 0.89; 30 | rrho = 0.5; 31 | llambda = 1; 32 | bbeta = 0.97; 33 | T = 10; 34 | 35 | % Prices 36 | r = 0.07; 37 | w = 5; 38 | 39 | % Initialize grid 40 | xgrid = zeros(1, nx); 41 | egrid = zeros(1, ne); 42 | P = zeros(ne, ne); 43 | V = zeros(T, nx, ne); 44 | 45 | %--------------------------------% 46 | % Grid creation % 47 | %--------------------------------% 48 | 49 | % Grid for x 50 | size = nx; 51 | xstep = (xmax - xmin) /(size - 1); 52 | it = 0; 53 | for i = 1:nx 54 | xgrid(i) = xmin + it*xstep; 55 | it = it+1; 56 | end 57 | 58 | % Grid for e with Tauchen (1986) 59 | size = ne; 60 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 61 | estep = 2*ssigma_y*m / (size-1); 62 | it = 0; 63 | for i = 1:ne 64 | egrid(i) = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + it*estep); 65 | it = it+1; 66 | end 67 | 68 | % Transition probability matrix Tauchen (1986) 69 | mm = egrid(2) - egrid(1); 70 | for j = 1:ne 71 | for k = 1:ne 72 | if k == 1 73 | P(j, k) = normcdf((egrid(k) - llambda_eps*egrid(j) + (mm/2))/ssigma_eps); 74 | elseif k == ne 75 | P(j, k) = 1 - normcdf((egrid(k) - llambda_eps*egrid(j) - (mm/2))/ssigma_eps); 76 | else 77 | P(j, k) = normcdf((egrid(k) - llambda_eps*egrid(j) + (mm/2))/ssigma_eps) - normcdf((egrid(k) - llambda_eps*egrid(j) - (mm/2))/ssigma_eps); 78 | end 79 | end 80 | end 81 | 82 | % Exponential of the grid e 83 | for i = 1:ne 84 | egrid(i) = exp(egrid(i)); 85 | end 86 | 87 | %--------------------------------% 88 | % Life-cycle computation % 89 | %--------------------------------% 90 | 91 | disp(' ') 92 | disp('Life cycle computation: ') 93 | disp(' ') 94 | 95 | tic; 96 | 97 | tempV = zeros(nx*ne); 98 | 99 | for age = T:-1:1 100 | parfor ind = 1:(ne*nx) 101 | 102 | ix = int64(floor((ind-0.05)/ne))+1; 103 | ie = int64(floor(mod(ind-0.05, ne))+1); 104 | 105 | VV = -10^3; 106 | for ixp = 1:1:nx 107 | 108 | expected = 0.0; 109 | if age < T 110 | for iep = 1:1:ne 111 | expected = expected + P(ie, iep)*V(age+1, ixp, iep); 112 | end 113 | end 114 | 115 | cons = (1 + r)*xgrid(ix) + egrid(ie)*w - xgrid(ixp); 116 | 117 | utility = (cons^(1-ssigma))/(1-ssigma) + bbeta*expected; 118 | 119 | if cons <= 0 120 | utility = -10^(5); 121 | end 122 | if utility >= VV 123 | VV = utility; 124 | end 125 | 126 | utility = 0.0; 127 | end 128 | 129 | tempV(ind) = VV; 130 | 131 | end 132 | 133 | for ind = 1:nx*ne 134 | ix = int64(floor((ind-0.05)/ne))+1; 135 | ie = int64(floor(mod(ind-0.05, ne))+1); 136 | 137 | V(age, ix, ie) = tempV(ind); 138 | end 139 | 140 | finish = toc; 141 | disp(['Age: ', num2str(age), '. Time: ', num2str(round(finish, 3)), ' seconds.']) 142 | end 143 | 144 | disp(' ') 145 | finish = toc; 146 | disp(['TOTAL ELAPSED TIME: ', num2str(finish), ' seconds. ']) 147 | 148 | 149 | %---------------------% 150 | % Some checks % 151 | %---------------------% 152 | 153 | disp(' ') 154 | disp(' - - - - - - - - - - - - - - - - - - - - - ') 155 | disp(' ') 156 | disp('The first entries of the value function: ') 157 | disp(' ') 158 | 159 | for i = 1:3 160 | disp(num2str(V(1, 1, i))); 161 | end 162 | 163 | disp(' ') 164 | quit() 165 | 166 | end -------------------------------------------------------------------------------- /Python_main.py: -------------------------------------------------------------------------------- 1 | 2 | #--------------------------------# 3 | # House-keeping # 4 | #--------------------------------# 5 | 6 | import numpy 7 | import math 8 | import time 9 | from scipy.stats import norm 10 | from joblib import Parallel, delayed 11 | import multiprocessing 12 | import sys 13 | 14 | #--------------------------------# 15 | # Initialization # 16 | #--------------------------------# 17 | 18 | # Number of workers 19 | num_cores = int(sys.argv[1]); 20 | 21 | # Grid for x 22 | nx = 300; 23 | xmin = 0.1; 24 | xmax = 4.0; 25 | 26 | # Grid for e: parameters for Tauchen 27 | ne = 15; 28 | ssigma_eps = 0.02058; 29 | llambda_eps = 0.99; 30 | m = 1.5; 31 | 32 | # Utility function 33 | ssigma = 2; 34 | eeta = 0.36; 35 | ppsi = 0.89; 36 | rrho = 0.5; 37 | llambda = 1; 38 | bbeta = 0.97; 39 | T = 10; 40 | 41 | # Prices 42 | r = 0.07; 43 | w = 5; 44 | 45 | # Initialize grids 46 | xgrid = numpy.zeros(nx) 47 | egrid = numpy.zeros(ne) 48 | P = numpy.zeros((ne, ne)) 49 | V = numpy.zeros((T, nx, ne)) 50 | 51 | 52 | #--------------------------------# 53 | # Grid creation # 54 | #--------------------------------# 55 | 56 | # Grid for x 57 | size = nx; 58 | xstep = (xmax - xmin) /(size - 1); 59 | it = 0; 60 | for i in range(0,nx): 61 | xgrid[i] = xmin + it*xstep; 62 | it = it+1; 63 | 64 | 65 | # Grid for e with Tauchen (1986) 66 | size = ne; 67 | ssigma_y = math.sqrt(math.pow(ssigma_eps, 2) / (1 - math.pow(llambda_eps,2))); 68 | estep = 2*ssigma_y*m / (size-1); 69 | it = 0; 70 | for i in range(0,ne): 71 | egrid[i] = (-m*math.sqrt(math.pow(ssigma_eps, 2) / (1 - math.pow(llambda_eps,2))) + it*estep); 72 | it = it+1; 73 | 74 | 75 | # Transition probability matrix Tauchen (1986) 76 | mm = egrid[1] - egrid[0]; 77 | for j in range(0,ne): 78 | for k in range(0,ne): 79 | if (k == 0): 80 | P[j, k] = norm.cdf((egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 81 | elif (k == ne-1): 82 | P[j, k] = 1 - norm.cdf((egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 83 | else: 84 | P[j, k] = norm.cdf((egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps) - norm.cdf((egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 85 | 86 | 87 | # Exponential of the grid e 88 | for i in range(0,ne): 89 | egrid[i] = math.exp(egrid[i]); 90 | 91 | 92 | #--------------------------------# 93 | # Structure and function # 94 | #--------------------------------# 95 | 96 | # Value function 97 | VV = math.pow(-10, 5); 98 | 99 | # Structure of input parameters for the value function estimation 100 | class modelState(object): 101 | def __init__(self,ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta,w,r): 102 | self.ind = ind 103 | self.ne = ne 104 | self.nx = nx 105 | self.T = T 106 | self.age = age 107 | self.P = P 108 | self.xgrid = xgrid 109 | self.egrid = egrid 110 | self.ssigma = ssigma 111 | self.bbeta = bbeta 112 | self.w = w 113 | self.r = r 114 | 115 | # Function that returns value for a given state 116 | # ind: a unique state that corresponds to a pair (ie,ix) 117 | def value_func(states): 118 | 119 | ind = states.ind 120 | ne = states.ne 121 | nx = states.nx 122 | T = states.T 123 | age = states.age 124 | P = states.P 125 | xgrid = states.xgrid 126 | egrid = states.egrid 127 | ssigma = states.ssigma 128 | bbeta = states.bbeta 129 | w = states.w 130 | r = states.r 131 | 132 | ix = int(math.floor(ind/ne)); 133 | ie = int(math.floor(ind%ne)); 134 | 135 | VV = math.pow(-10, 3) 136 | for ixp in range(0,nx): 137 | expected = 0.0; 138 | if(age < T-1): 139 | for iep in range(0,ne): 140 | expected = expected + P[ie, iep]*V[age+1, ixp, iep] 141 | 142 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 143 | 144 | utility = math.pow(cons, (1-ssigma))/(1-ssigma) + bbeta*expected; 145 | 146 | if(cons <= 0): 147 | utility = math.pow(-10,5); 148 | 149 | if(utility >= VV): 150 | VV = utility; 151 | 152 | utility = 0.0; 153 | 154 | return[VV]; 155 | 156 | 157 | 158 | #--------------------------------# 159 | # Life-cycle computation # 160 | #--------------------------------# 161 | 162 | print(" ") 163 | print("Life cycle computation: ") 164 | print(" ") 165 | 166 | 167 | start = time.time() 168 | 169 | for age in reversed(range(0,T)): 170 | 171 | # This function computes `value_func` in parallel for all the states 172 | results = Parallel(n_jobs=num_cores)(delayed(value_func)(modelState(ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta,w,r)) for ind in range(0,nx*ne)) 173 | 174 | # I write the results on the value matrix: V 175 | for ind in range(0,nx*ne): 176 | 177 | ix = int(math.floor(ind/ne)); 178 | ie = int(math.floor(ind%ne)); 179 | 180 | V[age, ix, ie] = results[ind][0]; 181 | 182 | finish = time.time() - start 183 | print "Age: ", age+1, ". Time: ", round(finish, 4), " seconds." 184 | 185 | finish = time.time() - start 186 | print "TOTAL ELAPSED TIME: ", round(finish, 4), " seconds. \n" 187 | 188 | 189 | #---------------------# 190 | # Some checks # 191 | #---------------------# 192 | 193 | print " - - - - - - - - - - - - - - - - - - - - - \n" 194 | print "The first entries of the value function: \n" 195 | 196 | for i in range(0,3): 197 | print(round(V[0, 0, i], 5)) 198 | 199 | print " \n" 200 | 201 | -------------------------------------------------------------------------------- /R_main.R: -------------------------------------------------------------------------------- 1 | 2 | #--------------------------------# 3 | # House-keeping # 4 | #--------------------------------# 5 | 6 | library("parallel") 7 | args<-commandArgs(TRUE) 8 | 9 | #--------------------------------# 10 | # Initialization # 11 | #--------------------------------# 12 | 13 | # Number of workers 14 | no_cores <- as.integer(args) 15 | cl <- makeCluster(no_cores) 16 | 17 | # Grid for x 18 | nx = 300; 19 | xmin = 0.1; 20 | xmax = 4.0; 21 | 22 | # Grid for e: parameters for Tauchen 23 | ne = 15; 24 | ssigma_eps = 0.02058; 25 | llambda_eps = 0.99; 26 | m = 1.5; 27 | 28 | # Utility function 29 | ssigma = 2; 30 | eeta = 0.36; 31 | ppsi = 0.89; 32 | rrho = 0.5; 33 | llambda = 1; 34 | bbeta = 0.97; 35 | T = 10; 36 | 37 | # Prices 38 | r = 0.07; 39 | w = 5; 40 | 41 | # Initialize grids 42 | xgrid = matrix(0, 1, nx) 43 | egrid = matrix(0, 1, ne) 44 | P = matrix(0, ne, ne) 45 | V = array(0, dim=c(T, nx, ne)) 46 | 47 | 48 | #--------------------------------# 49 | # Grid creation # 50 | #--------------------------------# 51 | 52 | # Grid for x 53 | size = nx; 54 | xstep = (xmax - xmin) /(size - 1); 55 | it = 0; 56 | for(i in 1:nx){ 57 | xgrid[i] = xmin + it*xstep; 58 | it = it+1; 59 | } 60 | 61 | # Grid for e with Tauchen (1986) 62 | size = ne; 63 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 64 | estep = 2*ssigma_y*m / (size-1); 65 | it = 0; 66 | for(i in 1:ne){ 67 | egrid[i] = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + it*estep); 68 | it = it+1; 69 | } 70 | 71 | # Transition probability matrix Tauchen (1986) 72 | mm = egrid[2] - egrid[1]; 73 | for(j in 1:ne){ 74 | for(k in 1:ne){ 75 | if(k == 1){ 76 | P[j, k] = pnorm((egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 77 | } else if(k == ne){ 78 | P[j, k] = 1 - pnorm((egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 79 | } else{ 80 | P[j, k] = pnorm((egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps) - pnorm((egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 81 | } 82 | } 83 | } 84 | 85 | # Exponential of the grid e 86 | for(i in 1:ne){ 87 | egrid[i] = exp(egrid[i]); 88 | } 89 | 90 | #--------------------------------# 91 | # Value function # 92 | #--------------------------------# 93 | 94 | value = function(x){ 95 | 96 | age = x$age 97 | ind = x$ind 98 | ne = x$ne 99 | nx = x$nx 100 | T = x$T 101 | P = x$P 102 | xgrid = x$xgrid 103 | egrid = x$egrid 104 | ssigma = x$ssigma 105 | bbeta = x$bbeta 106 | V = x$V 107 | w = x$w 108 | r = x$r 109 | 110 | ix = as.integer(floor((ind-0.05)/ne))+1; 111 | ie = as.integer(floor((ind-0.05) %% ne)+1); 112 | 113 | VV = -10^3; 114 | for(ixp in 1:nx){ 115 | 116 | expected = 0.0; 117 | if(age < T){ 118 | for(iep in 1:ne){ 119 | expected = expected + P[ie, iep]*V[age+1, ixp, iep]; 120 | } 121 | } 122 | 123 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 124 | 125 | utility = (cons^(1-ssigma))/(1-ssigma) + bbeta*expected; 126 | 127 | if(cons <= 0){ 128 | utility = -10^(5); 129 | } 130 | 131 | if(utility >= VV){ 132 | VV = utility; 133 | } 134 | } 135 | 136 | return(VV); 137 | } 138 | 139 | 140 | #--------------------------------# 141 | # Life-cycle computation # 142 | #--------------------------------# 143 | 144 | print(" ") 145 | print("Life cycle computation: ") 146 | print(" ") 147 | 148 | start = proc.time()[3]; 149 | 150 | for(age in T:1){ 151 | 152 | states = lapply(1:(ne*nx), function(x) list(age=age,ind=x,ne=ne,nx=nx,T=T,P=P, 153 | xgrid=xgrid,egrid=egrid,ssigma=ssigma,bbeta=bbeta,V=V,w=w,r=r)) 154 | s = parLapply(cl, states, value) 155 | 156 | for(ind in 1:(nx*ne)){ 157 | ix = as.integer(floor((ind-0.05)/ne))+1; 158 | ie = as.integer(floor((ind-0.05) %% ne)+1); 159 | 160 | V[age, ix, ie] = s[[ind]][1] 161 | } 162 | 163 | finish = proc.time()[3] - start; 164 | print(paste0("Age: ", age, ". Time: ", round(finish, 3), " seconds.")) 165 | } 166 | 167 | print(" ") 168 | finish = proc.time()[3] - start; 169 | print(paste("TOTAL ELAPSED TIME: ", finish, " seconds. ")) 170 | 171 | 172 | #---------------------# 173 | # Some checks # 174 | #---------------------# 175 | 176 | print(" ") 177 | print(" - - - - - - - - - - - - - - - - - - - - - ") 178 | print(" ") 179 | print("The first entries of the value function: ") 180 | print(" ") 181 | 182 | for(i in 1:3){ 183 | print(V[1, 1, i]) 184 | } 185 | 186 | print(" ") -------------------------------------------------------------------------------- /Rcpp_main.R: -------------------------------------------------------------------------------- 1 | 2 | #--------------------------------# 3 | # House-keeping # 4 | #--------------------------------# 5 | 6 | library("Rcpp") 7 | 8 | setwd("/home/david/Dropbox/Documents/Doctorado/Computation course/Codigos/") 9 | 10 | Sys.setenv("PKG_CXXFLAGS"=" -fopenmp") 11 | 12 | # Number of workers 13 | sourceCpp("Rcpp_main.cpp") 14 | 15 | 16 | #--------------------------------# 17 | # Initialization # 18 | #--------------------------------# 19 | 20 | # Grid for x 21 | nx = 300; 22 | xmin = 0.1; 23 | xmax = 4.0; 24 | 25 | # Grid for e: parameters for Tauchen 26 | ne = 15; 27 | ssigma_eps = 0.02058; 28 | llambda_eps = 0.99; 29 | m = 1.5; 30 | 31 | # Utility function 32 | ssigma = 2; 33 | eeta = 0.36; 34 | ppsi = 0.89; 35 | rrho = 0.5; 36 | llambda = 1; 37 | bbeta = 0.97; 38 | T = 10; 39 | 40 | # Prices 41 | r = 0.07; 42 | w = 5; 43 | 44 | 45 | #--------------------------------# 46 | # Value function # 47 | #--------------------------------# 48 | 49 | V = value(nx, xmin, xmax, 50 | ne, ssigma_eps, llambda_eps, m, 51 | ssigma, eeta, ppsi, rrho, llambda, bbeta, T, r, w); 52 | 53 | 54 | # I recover the Policy Functions 55 | Value = array(0,dim=c(T, nx, ne)); 56 | 57 | for (age in 1:T){ 58 | for (ix in 1:nx){ 59 | for(ie in 1:ne){ 60 | Value[age, ix, ie] = V[(age-1)*nx*ne + (ix-1)*ne + ie]; 61 | } 62 | } 63 | } 64 | 65 | #---------------------# 66 | # Some checks # 67 | #---------------------# 68 | 69 | print(" ") 70 | print(" - - - - - - - - - - - - - - - - - - - - - ") 71 | print(" ") 72 | print("The first entries of the value function: ") 73 | print(" ") 74 | 75 | for(i in 1:3){ 76 | print(Value[1, 1, i]) 77 | } 78 | 79 | print(" ") 80 | -------------------------------------------------------------------------------- /Rcpp_main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | //====================================== 9 | // Grids 10 | //====================================== 11 | 12 | void gridx(const int nx, const float xmin, const float xmax, float* xgrid){ 13 | 14 | const float size = nx; 15 | const float xstep = (xmax - xmin) /(size - 1); 16 | float it = 0; 17 | 18 | for(int i = 0; i < nx; i++){ 19 | xgrid[i] = xmin + it*xstep; 20 | it++; 21 | } 22 | } 23 | 24 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 25 | 26 | // This grid is made with Tauchen (1986) 27 | const float size = ne; 28 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 29 | const float estep = 2*ssigma_y*m / (size-1); 30 | float it = 0; 31 | 32 | for(int i = 0; i < ne; i++){ 33 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 34 | it++; 35 | } 36 | } 37 | 38 | float normCDF(const float value){ 39 | return 0.5 * erfc(-value * M_SQRT1_2); 40 | } 41 | 42 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 43 | 44 | // This grid is made with Tauchen (1986) 45 | // P is: first ne elements are transition from e_0 to e_i, 46 | // second ne elementrs are from e_1 to e_i, ... 47 | const float w = egrid[1] - egrid[0]; 48 | 49 | for(int j = 0; j < ne; j++){ 50 | for(int k = 0; k < ne; k++){ 51 | if(k == 0){ 52 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 53 | } else if(k == ne-1){ 54 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 55 | } else{ 56 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps) - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 57 | } 58 | } 59 | } 60 | } 61 | 62 | //====================================== 63 | // MAIN MAIN MAIN 64 | //====================================== 65 | 66 | // [[Rcpp::export]] 67 | vector value(int nx, float xmin, float xmax, 68 | int ne, float ssigma_eps, float llambda_eps, float m, 69 | float ssigma, float eeta, float ppsi, float rrho, 70 | float llambda, float bbeta, int T, float r, float w){ 71 | 72 | // I create the grid for X 73 | float xgrid[nx]; 74 | 75 | // I create the grid for E and the probability matrix 76 | float egrid[ne]; 77 | float P[ne*ne]; 78 | 79 | //--------------------------------// 80 | // Grid creation // 81 | //--------------------------------// 82 | 83 | gridx(nx, xmin, xmax, xgrid); 84 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 85 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 86 | 87 | // Exponential of the grid e 88 | for(int i=0; i V; 93 | V.resize(T*nx*ne); 94 | 95 | //--------------------------------// 96 | // Life-cycle computation // 97 | //--------------------------------// 98 | 99 | float expected; 100 | float utility; 101 | float cons; 102 | float VV = pow(-10.0,5.0); 103 | 104 | cout << " " << endl; 105 | cout << "Life cycle computation: " << endl; 106 | cout << " " << endl; 107 | 108 | double t0 = omp_get_wtime(); 109 | double t = t0; 110 | 111 | for(int age=T-1; age>=0; age--){ 112 | 113 | #pragma omp parallel for shared(V, age, P, xgrid, egrid, t, t0) private(expected, cons, utility, VV) 114 | 115 | for(int ix = 0; ix= VV){ 136 | VV = utility; 137 | } 138 | } 139 | 140 | V[age*nx*ne + ix*ne + ie] = VV; 141 | } 142 | } 143 | 144 | t = omp_get_wtime() - t0; 145 | cout << "Age: " << age << ". Time: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds." << endl; 146 | } 147 | 148 | cout << " " << endl; 149 | t = omp_get_wtime() - t0; 150 | cout << "TOTAL ELAPSED TIME: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds. " << endl; 151 | 152 | return V; 153 | } 154 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## A Practical Guide to Parallel Computing in Macroeconomics 2 | 3 | This repository contains the source code referenced in the paper *A Practical Guide to Parallel Computing in Macroeconomics* by Jesús 4 | Fernández-Villaverde and David Zarruk Valencia. 5 | 6 | ### Abstract from the paper 7 | 8 | > Parallel computing opens the door to solving and estimating richer models in Economics. From dynamic optimization 9 | > problems with high dimensionality to structural estimation with complex data, readily-available and economical parallel 10 | > computing allows researchers to tackle problems in Economics that were beyond the realm of possibility just a decade ago. This 11 | > paper describes the basics of parallel computing for economists, reviews widely-used implementation routines in `Julia`, `Python`, 12 | > `R`, `Matlab`, `C++` (`OpenMP` and `MPI`) and `CUDA` and compares performance gains using as a test bed a standard life-cycle problem 13 | > such as those used in macro, labor, and other fields. 14 | 15 | The file `Makefile` contains the compilation flags used in Linux and can be used to execute the codes in every language. 16 | 17 | ## Files 18 | 19 | 1. `Cpp_main.cpp`: C++ code for OpenMP 20 | 2. `CUDA_main.cu`: CUDA code 21 | 3. `Julia_main_parallel.jl`: Julia code 22 | 4. `Julia_main_pmap.jl`: Julia code 23 | 5. `Matlab_main.m`: Matlab code 24 | 6. `MPI_host_file`: MPI host file 25 | 6. `MPI_main.cpp`: C++ code for MPI 26 | 8. `Python_main.py`: Python code 27 | 9. `Rcpp_main.cpp`: C++ code for Rcpp package in R 28 | 10. `Rcpp_main.R`: Rcpp code 29 | 11. `R_main.R`: R code 30 | 12. `Makefile`: Makefile to execute codes 31 | -------------------------------------------------------------------------------- /Readme.md~: -------------------------------------------------------------------------------- 1 | ## A Practical Guide to Parallel Computing in Macroeconomics 2 | 3 | This repository contains the source code referenced in the paper *A Practical Guide to Parallel Computing in Macroeconomics* by Jesús 4 | Fernández-Villaverde and David Zarruk Valencia. 5 | 6 | ### Abstract from the paper 7 | 8 | > Parallel computing opens the door to solving and estimating much richer models in Economics. From dynamic optimization 9 | > problems with high dimensionality to structural estimation with complex data, readily-available and economical parallel 10 | > computing allows researchers to tackle problems in Economics that were beyond the realm of possibility just a decade ago. This 11 | > paper describes the basics of parallel computing for economists, reviews widely-used implementation routines in `Julia`, `Python`, 12 | > `R`, `Matlab`, `C++` (`OpenMP` and `MPI`) and `CUDA` and compares performance gains using, as a test bed a standard life-cycle problem 13 | > such as those in many models in macro, labor, and other fields. 14 | 15 | The file `Makefile` contains the compilation flags used in Linux and can be used to execute the codes in every language. 16 | 17 | ## Files 18 | 19 | 1. `Cpp_main.cpp`: C++ code for OpenMP 20 | 2. `CUDA_main.cu`: CUDA code 21 | 3. `Julia_main_parallel.jl`: Julia code 22 | 4. `Julia_main_pmap.jl`: Julia code 23 | 5. `Matlab_main.m`: Matlab code 24 | 6. `MPI_host_file`: MPI host file 25 | 6. `MPI_main.cpp`: C++ code for MPI 26 | 8. `Python_main.py`: Python code 27 | 9. `Rcpp_main.cpp`: C++ code for Rcpp package in R 28 | 10. `Rcpp_main.R`: Rcpp code 29 | 11. `R_main.R`: R code 30 | 12. `Makefile`: Makefile to execute codes 31 | --------------------------------------------------------------------------------