├── .Rhistory ├── CUDA_main.cu ├── Cpp_main_OpenACC.cpp ├── Cpp_main_OpenMP.cpp ├── Julia_main_parallel.jl ├── Julia_main_pmap.jl ├── Julia_threads.jl ├── MPI_host_file ├── MPI_main.cpp ├── Makefile ├── Makefile~ ├── Matlab_main.m ├── Python_main.py ├── Python_numba_main.py ├── R_main.R ├── Rcpp_main.R ├── Rcpp_main.cpp ├── Readme.md └── Readme.md~ /.Rhistory: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidzarruk/Parallel_Computing/d806258e12d97c79960e3e2c8f056b5b85e900a1/.Rhistory -------------------------------------------------------------------------------- /CUDA_main.cu: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | //====================================== 7 | // Grids 8 | //====================================== 9 | 10 | // Function to construct the grid for capital (x) 11 | void gridx(const int nx, const double xmin, const double xmax, double* xgrid){ 12 | 13 | const double size = nx; 14 | const double xstep = (xmax - xmin) /(size - 1); 15 | double it = 0; 16 | 17 | for(int i = 0; i < nx; i++){ 18 | xgrid[i] = xmin + it*xstep; 19 | it++; 20 | } 21 | } 22 | 23 | 24 | // Function to construct the grid for productivity (e) using Tauchen (1986) 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 | // Function to compute CDF of Normal distribution 40 | double normCDF(const double value){ 41 | return 0.5 * erfc(-value * M_SQRT1_2); 42 | } 43 | 44 | 45 | 46 | // Function to construct the transition probability matrix for productivity (P) using Tauchen (1986) 47 | void eprob(const int ne, const double ssigma_eps, const double llambda_eps, const double m, const double* egrid, double* P){ 48 | 49 | // This grid is made with Tauchen (1986) 50 | // P is: first ne elements are transition from e_0 to e_i, 51 | // second ne elementrs are from e_1 to e_i, ... 52 | const double w = egrid[1] - egrid[0]; 53 | 54 | for(int j = 0; j < ne; j++){ 55 | for(int k = 0; k < ne; k++){ 56 | if(k == 0){ 57 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 58 | } else if(k == ne-1){ 59 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 60 | } else{ 61 | 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); 62 | } 63 | } 64 | } 65 | } 66 | 67 | 68 | 69 | //====================================== 70 | // Parameter structure 71 | //====================================== 72 | 73 | // Data structure of state and exogenous variables 74 | class parameters{ 75 | public: 76 | int nx; 77 | double xmin; 78 | double xmax; 79 | int ne; 80 | double ssigma_eps; 81 | double llambda_eps; 82 | double m; 83 | 84 | double ssigma; 85 | double bbeta; 86 | int T; 87 | double r; 88 | double w; 89 | 90 | void load(const char*); 91 | }; 92 | 93 | 94 | // Function that computes value function, given vector of state variables 95 | __global__ void Vmaximization(const parameters params, const double* xgrid, const double* egrid, const double* P, const int age, double* V){ 96 | 97 | // Recover the parameters 98 | const int nx = params.nx; 99 | const int ne = params.ne; 100 | const double ssigma = params.ssigma; 101 | const double bbeta = params.bbeta; 102 | const int T = params.T; 103 | const double r = params.r; 104 | const double w = params.w; 105 | 106 | // Recover state variables from indices 107 | const int ix = blockIdx.x * blockDim.x + threadIdx.x; 108 | const int ie = threadIdx.y; 109 | 110 | double expected; 111 | double utility; 112 | double cons; 113 | double VV = pow(-10.0,5.0); 114 | 115 | for(int ixp = 0; ixp < nx; ixp++){ 116 | 117 | expected = 0.0; 118 | if(age < T-1){ 119 | for(int iep = 0; iep < ne; iep++){ 120 | expected = expected + P[ie*ne + iep]*V[(age+1)*nx*ne + ixp*ne + iep]; 121 | } 122 | } 123 | 124 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 125 | 126 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 127 | 128 | if(cons <= 0){ 129 | utility = pow(-10.0, 5.0); 130 | } 131 | 132 | if(utility >= VV){ 133 | VV = utility; 134 | } 135 | 136 | utility = 0.0; 137 | } 138 | 139 | V[age*nx*ne + ix*ne + ie] = VV; 140 | } 141 | 142 | 143 | 144 | //====================================== 145 | // MAIN MAIN MAIN 146 | //====================================== 147 | 148 | 149 | int main() 150 | { 151 | 152 | //--------------------------------// 153 | // Initialization // 154 | //--------------------------------// 155 | 156 | // Grid for x 157 | const int nx = 1500; 158 | const double xmin = 0.1; 159 | const double xmax = 4.0; 160 | 161 | // Grid for e 162 | const int ne = 15; 163 | const double ssigma_eps = 0.02058; 164 | const double llambda_eps = 0.99; 165 | const double m = 1.5; 166 | 167 | // Utility function 168 | const double ssigma = 2; 169 | const double bbeta = 0.97; 170 | const int T = 10; 171 | 172 | // Prices 173 | const double r = 0.07; 174 | const double w = 5; 175 | 176 | // Initialize data structure 177 | parameters params = {nx, xmin, xmax, ne, ssigma_eps, llambda_eps, m, ssigma, bbeta, T, r, w}; 178 | 179 | // Pointers to variables in the DEVICE memory 180 | double *V, *X, *E, *P; 181 | size_t sizeX = nx*sizeof(double); 182 | size_t sizeE = ne*sizeof(double); 183 | size_t sizeP = ne*ne*sizeof(double); 184 | size_t sizeV = T*ne*nx*sizeof(double); 185 | 186 | // Allocate memory to objects in device (GPU) 187 | cudaMalloc((void**)&X, sizeX); 188 | cudaMalloc((void**)&E, sizeE); 189 | cudaMalloc((void**)&P, sizeP); 190 | cudaMalloc((void**)&V, sizeV); 191 | 192 | // Parameters for CUDA: each block has ne columns, and one row that represents the value of x 193 | // there are nx blocks 194 | // Every layer is an age >= there are 80 layers 195 | 196 | const int block_size = 30; 197 | dim3 dimBlock(block_size, ne); 198 | dim3 dimGrid(nx/block_size, 1); 199 | 200 | // Initialize the grid for X 201 | double hxgrid[nx]; 202 | 203 | // Initialize the grid for E and the transition probability matrix 204 | double hegrid[ne]; 205 | double hP[ne*ne]; 206 | 207 | //--------------------------------// 208 | // Grid creation // 209 | //--------------------------------// 210 | 211 | // Variables in the host have "h" prefix 212 | // I create the grid for X 213 | gridx(nx, xmin, xmax, hxgrid); 214 | 215 | // I create the grid for E and the probability matrix 216 | gride(ne, ssigma_eps, llambda_eps, m, hegrid); 217 | eprob(ne, ssigma_eps, llambda_eps, m, hegrid, hP); 218 | 219 | // Exponential of the grid e 220 | for(int i=0; i=0; age--){ 249 | Vmaximization<<>>(params, X, E, P, age, V); 250 | cudaDeviceSynchronize(); 251 | 252 | t = clock() - t0; 253 | std::cout << "Age: " << age << ". Time: " << ((double)t)/CLOCKS_PER_SEC << " seconds." << std::endl; 254 | 255 | } 256 | 257 | std::cout << " " << std::endl; 258 | t = clock() - t0; 259 | std::cout << "TOTAL ELAPSED TIME: " << ((double)t)/CLOCKS_PER_SEC << " seconds. " << std::endl; 260 | 261 | // Copy back from device (GPU) to host (CPU) 262 | cudaMemcpy(hV, V, sizeV, cudaMemcpyDeviceToHost); 263 | 264 | // Free variables in device memory 265 | cudaFree(V); 266 | cudaFree(X); 267 | cudaFree(E); 268 | cudaFree(P); 269 | 270 | 271 | //--------------------------------// 272 | // Some checks // 273 | //--------------------------------// 274 | 275 | std::cout << " " << std::endl; 276 | std::cout << " - - - - - - - - - - - - - - - - - - - - - " << std::endl; 277 | std::cout << " " << std::endl; 278 | std::cout << "The first entries of the value function: " << std::endl; 279 | std::cout << " " << std::endl; 280 | 281 | for(int i = 0; i<3; i++){ 282 | std::cout << hV[i] << std::endl; 283 | } 284 | 285 | std::cout << " " << std::endl; 286 | 287 | return 0; 288 | } 289 | -------------------------------------------------------------------------------- /Cpp_main_OpenACC.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | //====================================== 9 | // Grids 10 | //====================================== 11 | 12 | // Function to construct the grid for capital (x) 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 | // Function to construct the grid for productivity (e) using Tauchen (1986) 27 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 28 | 29 | // This grid is made with Tauchen (1986) 30 | const float size = ne; 31 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 32 | const float estep = 2*ssigma_y*m / (size-1); 33 | float it = 0; 34 | 35 | for(int i = 0; i < ne; i++){ 36 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 37 | it++; 38 | } 39 | } 40 | 41 | // Function to compute CDF of Normal distribution 42 | float normCDF(const float value){ 43 | return 0.5 * erfc(-value * M_SQRT1_2); 44 | } 45 | 46 | 47 | 48 | // Function to construct the transition probability matrix for productivity (P) using Tauchen (1986) 49 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 50 | 51 | // This grid is made with Tauchen (1986) 52 | // P is: first ne elements are transition from e_0 to e_i, 53 | // second ne elementrs are from e_1 to e_i, ... 54 | const float w = egrid[1] - egrid[0]; 55 | 56 | for(int j = 0; j < ne; j++){ 57 | for(int k = 0; k < ne; k++){ 58 | if(k == 0){ 59 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 60 | } else if(k == ne-1){ 61 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 62 | } else{ 63 | 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); 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | // Data structure of state and exogenous variables 71 | struct modelState{ 72 | int ie; 73 | int ix; 74 | int ne; 75 | int nx; 76 | int T; 77 | int age; 78 | float *P; 79 | float *xgrid; 80 | float *egrid; 81 | float ssigma; 82 | float bbeta; 83 | float *V; 84 | float w; 85 | float r; 86 | }; 87 | 88 | // Function that computes value function, given vector of state variables 89 | float value(modelState currentState){ 90 | 91 | int ie = currentState.ie; 92 | int ix = currentState.ix; 93 | int ne = currentState.ne; 94 | int nx = currentState.nx; 95 | int T = currentState.T; 96 | int age = currentState.age; 97 | float *P = currentState.P; 98 | float *xgrid = currentState.xgrid; 99 | float *egrid = currentState.egrid; 100 | float ssigma = currentState.ssigma; 101 | float bbeta = currentState.bbeta; 102 | float *V = currentState.V; 103 | float w = currentState.w; 104 | float r = currentState.r; 105 | 106 | float expected; 107 | float utility; 108 | float cons; 109 | float VV = pow(-10.0,5.0); 110 | 111 | for(int ixp = 0; ixp < nx; ixp++){ 112 | 113 | expected = 0.0; 114 | if(age < T-1){ 115 | for(int iep = 0; iep < ne; iep++){ 116 | expected = expected + P[ie*ne + iep]*V[(age+1)*nx*ne + ixp*ne + iep]; 117 | } 118 | } 119 | 120 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 121 | 122 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 123 | 124 | if(cons <= 0){ 125 | utility = pow(-10.0, 5.0); 126 | } 127 | 128 | if(utility >= VV){ 129 | VV = utility; 130 | } 131 | } 132 | 133 | return VV; 134 | } 135 | 136 | 137 | 138 | //====================================== 139 | // MAIN MAIN MAIN 140 | //====================================== 141 | 142 | 143 | int main() 144 | { 145 | 146 | //--------------------------------// 147 | // Initialization // 148 | //--------------------------------// 149 | 150 | // Grid for x 151 | const int nx = 1500; 152 | const float xmin = 0.1; 153 | const float xmax = 4.0; 154 | 155 | // Grid for e 156 | const int ne = 15; 157 | const float ssigma_eps = 0.02058; 158 | const float llambda_eps = 0.99; 159 | const float m = 1.5; 160 | 161 | // Utility function 162 | const float ssigma = 2; 163 | const float bbeta = 0.97; 164 | const int T = 10; 165 | 166 | // Prices 167 | const float r = 0.07; 168 | const float w = 5; 169 | 170 | // Initialize the grid for X 171 | float xgrid[nx]; 172 | 173 | // Initialize the grid for E and the transition probability matrix 174 | float egrid[ne]; 175 | float P[ne*ne]; 176 | 177 | // Initialize value function V 178 | size_t sizeV = T*ne*nx*sizeof(float); 179 | float *V; 180 | V = (float *)malloc(sizeV); 181 | 182 | 183 | //--------------------------------// 184 | // Grid creation // 185 | //--------------------------------// 186 | 187 | gridx(nx, xmin, xmax, xgrid); 188 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 189 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 190 | 191 | // Exponential of the grid e 192 | for(int i=0; i=0; age--){ 211 | 212 | #pragma acc data copy(V[0:(T*ne*nx)]) 213 | #pragma acc parallel loop 214 | for(int ix = 0; ix 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | //====================================== 9 | // Grids 10 | //====================================== 11 | 12 | // Function to construct the grid for capital (x) 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 | // Function to construct the grid for productivity (e) using Tauchen (1986) 27 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 28 | 29 | // This grid is made with Tauchen (1986) 30 | const float size = ne; 31 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 32 | const float estep = 2*ssigma_y*m / (size-1); 33 | float it = 0; 34 | 35 | for(int i = 0; i < ne; i++){ 36 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 37 | it++; 38 | } 39 | } 40 | 41 | // Function to compute CDF of Normal distribution 42 | float normCDF(const float value){ 43 | return 0.5 * erfc(-value * M_SQRT1_2); 44 | } 45 | 46 | 47 | 48 | // Function to construct the transition probability matrix for productivity (P) using Tauchen (1986) 49 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 50 | 51 | // This grid is made with Tauchen (1986) 52 | // P is: first ne elements are transition from e_0 to e_i, 53 | // second ne elementrs are from e_1 to e_i, ... 54 | const float w = egrid[1] - egrid[0]; 55 | 56 | for(int j = 0; j < ne; j++){ 57 | for(int k = 0; k < ne; k++){ 58 | if(k == 0){ 59 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 60 | } else if(k == ne-1){ 61 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 62 | } else{ 63 | 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); 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | // Data structure of state and exogenous variables 71 | struct modelState{ 72 | int ie; 73 | int ix; 74 | int ne; 75 | int nx; 76 | int T; 77 | int age; 78 | float *P; 79 | float *xgrid; 80 | float *egrid; 81 | float ssigma; 82 | float bbeta; 83 | float *V; 84 | float w; 85 | float r; 86 | }; 87 | 88 | // Function that computes value function, given vector of state variables 89 | float value(modelState currentState){ 90 | 91 | int ie = currentState.ie; 92 | int ix = currentState.ix; 93 | int ne = currentState.ne; 94 | int nx = currentState.nx; 95 | int T = currentState.T; 96 | int age = currentState.age; 97 | float *P = currentState.P; 98 | float *xgrid = currentState.xgrid; 99 | float *egrid = currentState.egrid; 100 | float ssigma = currentState.ssigma; 101 | float bbeta = currentState.bbeta; 102 | float *V = currentState.V; 103 | float w = currentState.w; 104 | float r = currentState.r; 105 | 106 | float expected; 107 | float utility; 108 | float cons; 109 | float VV = pow(-10.0,5.0); 110 | 111 | for(int ixp = 0; ixp < nx; ixp++){ 112 | 113 | expected = 0.0; 114 | if(age < T-1){ 115 | for(int iep = 0; iep < ne; iep++){ 116 | expected = expected + P[ie*ne + iep]*V[(age+1)*nx*ne + ixp*ne + iep]; 117 | } 118 | } 119 | 120 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 121 | 122 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 123 | 124 | if(cons <= 0){ 125 | utility = pow(-10.0, 5.0); 126 | } 127 | 128 | if(utility >= VV){ 129 | VV = utility; 130 | } 131 | } 132 | 133 | return VV; 134 | } 135 | 136 | 137 | 138 | //====================================== 139 | // MAIN MAIN MAIN 140 | //====================================== 141 | 142 | int main() 143 | { 144 | 145 | //--------------------------------// 146 | // Initialization // 147 | //--------------------------------// 148 | 149 | // Grid for x 150 | const int nx = 15000; 151 | const float xmin = 0.1; 152 | const float xmax = 4.0; 153 | 154 | // Grid for e 155 | const int ne = 15; 156 | const float ssigma_eps = 0.02058; 157 | const float llambda_eps = 0.99; 158 | const float m = 1.5; 159 | 160 | // Utility function 161 | const float ssigma = 2; 162 | const float bbeta = 0.97; 163 | const int T = 10; 164 | 165 | // Prices 166 | const float r = 0.07; 167 | const float w = 5; 168 | 169 | // Initialize the grid for X 170 | float xgrid[nx]; 171 | 172 | // Initialize the grid for E and the transition probability matrix 173 | float egrid[ne]; 174 | float P[ne*ne]; 175 | 176 | // Initialize value function V 177 | size_t sizeV = T*ne*nx*sizeof(float); 178 | float *V; 179 | V = (float *)malloc(sizeV); 180 | 181 | // Initialize data structure of state and exogenous variables 182 | modelState currentState; 183 | 184 | 185 | //--------------------------------// 186 | // Grid creation // 187 | //--------------------------------// 188 | 189 | gridx(nx, xmin, xmax, xgrid); 190 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 191 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 192 | 193 | // Exponential of the grid e 194 | for(int i=0; i=0; age--){ 212 | 213 | #pragma omp parallel for shared(V, age, P, xgrid, egrid, t, t0) private(currentState) 214 | for(int ix = 0; ix= VV) 154 | VV = utility; 155 | ixpopt = ixp; 156 | end 157 | 158 | utility = 0.0; 159 | end 160 | 161 | return(VV); 162 | 163 | end 164 | 165 | 166 | #--------------------------------# 167 | # Life-cycle computation # 168 | #--------------------------------# 169 | 170 | print(" \n") 171 | print("Life cycle computation: \n") 172 | print(" \n") 173 | 174 | start = Dates.unix2datetime(time()) 175 | 176 | for age = T:-1:1 177 | 178 | @sync @distributed for ind = 1:(ne*nx) 179 | 180 | ix = convert(Int, ceil(ind/ne)); 181 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 182 | 183 | currentState = modelState(ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta, V_tomorrow,w,r) 184 | tempV[ind] = value(currentState); 185 | 186 | end 187 | 188 | for ind = 1:(ne*nx) 189 | 190 | ix = convert(Int, ceil(ind/ne)); 191 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 192 | 193 | V[age, ix, ie] = tempV[ind] 194 | V_tomorrow[ix, ie] = tempV[ind] 195 | end 196 | 197 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 198 | print("Age: ", age, ". Time: ", finish, " seconds. \n") 199 | end 200 | 201 | print("\n") 202 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 203 | print("TOTAL ELAPSED TIME: ", finish, " seconds. \n") 204 | 205 | #---------------------# 206 | # Some checks # 207 | #---------------------# 208 | 209 | print(" \n") 210 | print(" - - - - - - - - - - - - - - - - - - - - - \n") 211 | print(" \n") 212 | print("The first entries of the value function: \n") 213 | print(" \n") 214 | 215 | # I print the first entries of the value function, to check 216 | for i = 1:3 217 | print(round(V[1, 1, i], digits=5), "\n") 218 | end 219 | -------------------------------------------------------------------------------- /Julia_main_pmap.jl: -------------------------------------------------------------------------------- 1 | #--------------------------------# 2 | # House-keeping # 3 | #--------------------------------# 4 | 5 | using Distributed 6 | using Distributions 7 | using Compat.Dates 8 | 9 | #--------------------------------# 10 | # Initialization # 11 | #--------------------------------# 12 | 13 | # Number of cores/workers 14 | addprocs(5) 15 | 16 | # Grid for x 17 | nx = 1500; 18 | xmin = 0.1; 19 | xmax = 4.0; 20 | 21 | # Grid for e: parameters for Tauchen 22 | ne = 15; 23 | ssigma_eps = 0.02058; 24 | llambda_eps = 0.99; 25 | m = 1.5; 26 | 27 | # Utility function 28 | ssigma = 2; 29 | bbeta = 0.97; 30 | T = 10; 31 | 32 | # Prices 33 | r = 0.07; 34 | w = 5; 35 | 36 | # Initialize the grid for X 37 | xgrid = zeros(nx) 38 | 39 | # Initialize the grid for E and the transition probability matrix 40 | egrid = zeros(ne) 41 | P = zeros(ne, ne) 42 | 43 | # Initialize value function V 44 | V = zeros(T, nx, ne) 45 | V_tomorrow = zeros(nx, ne) 46 | 47 | 48 | #--------------------------------# 49 | # Grid creation # 50 | #--------------------------------# 51 | 52 | # Grid for capital (x) 53 | size = nx; 54 | xstep = (xmax - xmin) /(size - 1); 55 | for i = 1:nx 56 | xgrid[i] = xmin + (i-1)*xstep; 57 | end 58 | 59 | # Grid for productivity (e) with Tauchen (1986) 60 | size = ne; 61 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 62 | estep = 2*ssigma_y*m / (size-1); 63 | for i = 1:ne 64 | egrid[i] = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + (i-1)*estep); 65 | end 66 | 67 | # Transition probability matrix (P) Tauchen (1986) 68 | mm = egrid[2] - egrid[1]; 69 | for j = 1:ne 70 | for k = 1:ne 71 | if(k == 1) 72 | P[j, k] = cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 73 | elseif(k == ne) 74 | P[j, k] = 1 - cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 75 | else 76 | 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); 77 | end 78 | end 79 | end 80 | 81 | # Exponential of the grid e 82 | for i in 1:ne 83 | egrid[i] = exp(egrid[i]); 84 | end 85 | 86 | 87 | #--------------------------------# 88 | # Structure and function # 89 | #--------------------------------# 90 | 91 | # Data structure of state and exogenous variables 92 | @everywhere struct modelState 93 | ind::Int64 94 | ne::Int64 95 | nx::Int64 96 | T::Int64 97 | age::Int64 98 | P::Array{Float64,2} 99 | xgrid::Vector{Float64} 100 | egrid::Vector{Float64} 101 | ssigma::Float64 102 | bbeta::Float64 103 | V::Array{Float64,2} 104 | w::Float64 105 | r::Float64 106 | end 107 | 108 | # Function that computes value function, given vector of state variables 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.0^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[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.0^(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_tomorrow,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 | V_tomorrow[ix, ie] = s[ind] 184 | end 185 | 186 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 187 | print("Age: ", age, ". Time: ", finish, " seconds. \n") 188 | 189 | end 190 | 191 | print("\n") 192 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 193 | print("TOTAL ELAPSED TIME: ", finish, " seconds. \n") 194 | 195 | 196 | #---------------------# 197 | # Some checks # 198 | #---------------------# 199 | 200 | print(" \n") 201 | print(" - - - - - - - - - - - - - - - - - - - - - \n") 202 | print(" \n") 203 | print("The first entries of the value function: \n") 204 | print(" \n") 205 | 206 | # For comparison, I print first entries of value function 207 | for i = 1:3 208 | print(round(V[1, 1, i], digits=5), "\n") 209 | end 210 | -------------------------------------------------------------------------------- /Julia_threads.jl: -------------------------------------------------------------------------------- 1 | #--------------------------------# 2 | # House-keeping # 3 | #--------------------------------# 4 | 5 | using Distributed 6 | using Distributions 7 | using Compat.Dates 8 | 9 | #--------------------------------# 10 | # Initialization # 11 | #--------------------------------# 12 | 13 | # Number of threads 14 | println("started one julia process with $(Threads.nthreads()) threads.") 15 | 16 | # Grid for x 17 | nx = 1500; 18 | xmin = 0.1; 19 | xmax = 4.0; 20 | 21 | # Grid for e: parameters for Tauchen 22 | ne = 15; 23 | ssigma_eps = 0.02058; 24 | llambda_eps = 0.99; 25 | m = 1.5; 26 | 27 | # Utility function 28 | ssigma = 2; 29 | bbeta = 0.97; 30 | T = 10; 31 | 32 | # Prices 33 | r = 0.07; 34 | w = 5; 35 | 36 | # Initialize the grid for X 37 | xgrid = zeros(nx) 38 | 39 | # Initialize the grid for E and the transition probability matrix 40 | egrid = zeros(ne) 41 | P = zeros(ne, ne) 42 | 43 | # Initialize value function V 44 | V = zeros(T, nx, ne) 45 | V_tomorrow = zeros(nx, ne) 46 | 47 | # Initialize value function as a shared array 48 | tempV = zeros(ne*nx) 49 | 50 | #--------------------------------# 51 | # Grid creation # 52 | #--------------------------------# 53 | 54 | # Grid for capital (x) 55 | size = nx; 56 | xstep = (xmax - xmin) /(size - 1); 57 | for i = 1:nx 58 | xgrid[i] = xmin + (i-1)*xstep; 59 | end 60 | 61 | # Grid for productivity (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 | for i = 1:ne 66 | egrid[i] = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + (i-1)*estep); 67 | end 68 | 69 | # Transition probability matrix (P) Tauchen (1986) 70 | mm = egrid[2] - egrid[1]; 71 | for j = 1:ne 72 | for k = 1:ne 73 | if(k == 1) 74 | P[j, k] = cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 75 | elseif(k == ne) 76 | P[j, k] = 1 - cdf(Normal(), (egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 77 | else 78 | 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); 79 | end 80 | end 81 | end 82 | 83 | # Exponential of the grid e 84 | for i = 1:ne 85 | egrid[i] = exp(egrid[i]); 86 | end 87 | 88 | 89 | 90 | #--------------------------------# 91 | # Structure and function # 92 | #--------------------------------# 93 | 94 | # Data structure of state and exogenous variables 95 | struct modelState 96 | ind::Int64 97 | ne::Int64 98 | nx::Int64 99 | T::Int64 100 | age::Int64 101 | P::Array{Float64,2} 102 | xgrid::Vector{Float64} 103 | egrid::Vector{Float64} 104 | ssigma::Float64 105 | bbeta::Float64 106 | V::Array{Float64,2} 107 | w::Float64 108 | r::Float64 109 | end 110 | 111 | # Function that computes value function, given vector of state variables 112 | function value(currentState::modelState) 113 | 114 | ind = currentState.ind 115 | age = currentState.age 116 | ne = currentState.ne 117 | nx = currentState.nx 118 | T = currentState.T 119 | P = currentState.P 120 | xgrid = currentState.xgrid 121 | egrid = currentState.egrid 122 | ssigma = currentState.ssigma 123 | bbeta = currentState.bbeta 124 | w = currentState.w 125 | r = currentState.r 126 | V = currentState.V 127 | 128 | ix = convert(Int, floor((ind-0.05)/ne))+1; 129 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 130 | 131 | VV = -10.0^3; 132 | ixpopt = 0; 133 | 134 | 135 | for ixp = 1:nx 136 | 137 | expected = 0.0; 138 | if(age < T) 139 | for iep = 1:ne 140 | expected = expected + P[ie, iep]*V[ixp, iep]; 141 | end 142 | end 143 | 144 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 145 | 146 | utility = (cons^(1-ssigma))/(1-ssigma) + bbeta*expected; 147 | 148 | if(cons <= 0) 149 | utility = -10.0^(5); 150 | end 151 | 152 | if(utility >= VV) 153 | VV = utility; 154 | ixpopt = ixp; 155 | end 156 | 157 | utility = 0.0; 158 | end 159 | 160 | return(VV); 161 | 162 | end 163 | 164 | 165 | #--------------------------------# 166 | # Life-cycle computation # 167 | #--------------------------------# 168 | 169 | print(" \n") 170 | print("Life cycle computation: \n") 171 | print(" \n") 172 | 173 | start = Dates.unix2datetime(time()) 174 | 175 | for age = T:-1:1 176 | 177 | Threads.@threads for ind = 1:(ne*nx) 178 | 179 | ix = convert(Int, ceil(ind/ne)); 180 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 181 | 182 | currentState = modelState(ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta, V_tomorrow,w,r) 183 | tempV[ind] = value(currentState); 184 | 185 | end 186 | 187 | for ind = 1:(ne*nx) 188 | 189 | ix = convert(Int, ceil(ind/ne)); 190 | ie = convert(Int, floor(mod(ind-0.05, ne))+1); 191 | 192 | V[age, ix, ie] = tempV[ind] 193 | V_tomorrow[ix, ie] = tempV[ind] 194 | end 195 | 196 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 197 | print("Age: ", age, ". Time: ", finish, " seconds. \n") 198 | end 199 | 200 | print("\n") 201 | finish = convert(Int, Dates.value(Dates.unix2datetime(time())- start))/1000; 202 | print("TOTAL ELAPSED TIME: ", finish, " seconds. \n") 203 | 204 | #---------------------# 205 | # Some checks # 206 | #---------------------# 207 | 208 | print(" \n") 209 | print(" - - - - - - - - - - - - - - - - - - - - - \n") 210 | print(" \n") 211 | print("The first entries of the value function: \n") 212 | print(" \n") 213 | 214 | # I print the first entries of the value function, to check 215 | for i = 1:3 216 | print(round(V[1, 1, i], digits=5), "\n") 217 | end 218 | -------------------------------------------------------------------------------- /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 | // Function to construct the grid for capital (x) 18 | void gridx(const int nx, const float xmin, const float xmax, float* xgrid){ 19 | 20 | const float size = nx; 21 | const float xstep = (xmax - xmin) /(size - 1); 22 | float it = 0; 23 | 24 | for(int i = 0; i < nx; i++){ 25 | xgrid[i] = xmin + it*xstep; 26 | it++; 27 | } 28 | } 29 | 30 | 31 | // Function to construct the grid for productivity (e) using Tauchen (1986) 32 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 33 | 34 | // This grid is made with Tauchen (1986) 35 | const float size = ne; 36 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 37 | const float estep = 2*ssigma_y*m / (size-1); 38 | float it = 0; 39 | 40 | for(int i = 0; i < ne; i++){ 41 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 42 | it++; 43 | } 44 | } 45 | 46 | // Function to compute CDF of Normal distribution 47 | float normCDF(const float value){ 48 | return 0.5 * erfc(-value * M_SQRT1_2); 49 | } 50 | 51 | 52 | 53 | // Function to construct the transition probability matrix for productivity (P) using Tauchen (1986) 54 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 55 | 56 | // This grid is made with Tauchen (1986) 57 | // P is: first ne elements are transition from e_0 to e_i, 58 | // second ne elementrs are from e_1 to e_i, ... 59 | const float w = egrid[1] - egrid[0]; 60 | 61 | for(int j = 0; j < ne; j++){ 62 | for(int k = 0; k < ne; k++){ 63 | if(k == 0){ 64 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 65 | } else if(k == ne-1){ 66 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 67 | } else{ 68 | 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); 69 | } 70 | } 71 | } 72 | } 73 | 74 | 75 | // Data structure of state and exogenous variables 76 | struct modelState{ 77 | int ie; 78 | int ix; 79 | int ne; 80 | int nx; 81 | int T; 82 | int age; 83 | float *P; 84 | float *xgrid; 85 | float *egrid; 86 | float ssigma; 87 | float bbeta; 88 | float *V; 89 | float w; 90 | float r; 91 | }; 92 | 93 | // Function that computes value function, given vector of state variables 94 | float value(modelState currentState){ 95 | 96 | int ie = currentState.ie; 97 | int ix = currentState.ix; 98 | int ne = currentState.ne; 99 | int nx = currentState.nx; 100 | int T = currentState.T; 101 | int age = currentState.age; 102 | float *P = currentState.P; 103 | float *xgrid = currentState.xgrid; 104 | float *egrid = currentState.egrid; 105 | float ssigma = currentState.ssigma; 106 | float bbeta = currentState.bbeta; 107 | float *V = currentState.V; 108 | float w = currentState.w; 109 | float r = currentState.r; 110 | 111 | float expected; 112 | float utility; 113 | float cons; 114 | float VV = pow(-10.0,5.0); 115 | 116 | for(int ixp = 0; ixp < nx; ixp++){ 117 | 118 | expected = 0.0; 119 | if(age < T-1){ 120 | for(int iep = 0; iep < ne; iep++){ 121 | expected = expected + P[ie*ne + iep]*V[(age+1)*nx*ne + ixp*ne + iep]; 122 | } 123 | } 124 | 125 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 126 | 127 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 128 | 129 | if(cons <= 0){ 130 | utility = pow(-10.0, 5.0); 131 | } 132 | 133 | if(utility >= VV){ 134 | VV = utility; 135 | } 136 | } 137 | 138 | return VV; 139 | } 140 | 141 | 142 | //====================================== 143 | // MAIN MAIN MAIN 144 | //====================================== 145 | 146 | 147 | int main() 148 | { 149 | 150 | //--------------------------------// 151 | // MPI // 152 | //--------------------------------// 153 | 154 | // Thread id and number of threads 155 | int tid,nthreads; 156 | 157 | // Initialize MPI 158 | MPI_Init(NULL, NULL); 159 | MPI_Comm_rank(MPI_COMM_WORLD, &tid); 160 | MPI_Comm_size(MPI_COMM_WORLD, &nthreads); 161 | 162 | 163 | //--------------------------------// 164 | // Initialization // 165 | //--------------------------------// 166 | 167 | // Grid for x 168 | const int nx = 1500; 169 | const float xmin = 0.1; 170 | const float xmax = 4.0; 171 | 172 | // Grid for e 173 | const int ne = 15; 174 | const float ssigma_eps = 0.02058; 175 | const float llambda_eps = 0.99; 176 | const float m = 1.5; 177 | 178 | // Utility function 179 | const float ssigma = 2; 180 | const float bbeta = 0.97; 181 | const int T = 10; 182 | 183 | // Prices 184 | const float r = 0.07; 185 | const float w = 5; 186 | 187 | // Initialize the grid for X 188 | float xgrid[nx]; 189 | 190 | // Initialize the grid for E and the probability matrix 191 | float egrid[ne]; 192 | float P[ne*ne]; 193 | 194 | // Total Value function 195 | size_t sizeVal = T*ne*nx*sizeof(float); 196 | float *Val; 197 | Val = (float *)malloc(sizeVal); 198 | 199 | // Value function at every age t+1 200 | size_t sizeVal1 = ne*nx*sizeof(float); 201 | float *Val1; 202 | Val1 = (float *)malloc(sizeVal1); 203 | 204 | 205 | // Loop limits of parallelization 206 | int loop_min = (int)((tid + 0) * ceil((float)(nx*ne)/nthreads)); 207 | int loop_max = (int)((tid + 1) * ceil((float)(nx*ne)/nthreads)); 208 | if(ne*nx < loop_max){ 209 | loop_max = ne*nx; 210 | } 211 | int leng = (loop_max - loop_min); 212 | 213 | // Value function at every age t, computed by every processor 214 | size_t sizeValp = leng*sizeof(float); 215 | float *Valp; 216 | Valp = (float *)malloc(sizeValp); 217 | 218 | 219 | // Initialize iterators 220 | int ix; 221 | int ie; 222 | int iter; 223 | 224 | 225 | // Parameters for the gathering (MPI_Gatherv) of value function after each iteration 226 | int displs[nthreads],rcounts[nthreads]; 227 | for(int i = 0; i < nthreads; i++){ 228 | displs[i] = i*leng; 229 | rcounts[i] = leng; 230 | } 231 | 232 | 233 | //--------------------------------// 234 | // Grid creation // 235 | //--------------------------------// 236 | 237 | gridx(nx, xmin, xmax, xgrid); 238 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 239 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 240 | 241 | // Exponential of the grid e 242 | for(int i=0; i=0; age--){ 264 | 265 | // Synchronize 266 | MPI_Barrier(MPI_COMM_WORLD); 267 | MPI_Bcast(Val, (T*ne*nx), MPI_FLOAT, 0, MPI_COMM_WORLD); 268 | 269 | iter = 0; 270 | 271 | for(int ind = loop_min; ind < loop_max; ind++){ 272 | 273 | ix = floor(ind/ne); 274 | ie = ind % ne; 275 | 276 | modelState currentState = {ie, ix, ne, nx, T, age, P, xgrid, egrid, ssigma, bbeta, Val, w, r}; 277 | 278 | Valp[iter] = value(currentState); 279 | iter = iter + 1; 280 | } 281 | 282 | MPI_Gatherv(Valp, leng, MPI_FLOAT, Val1, rcounts, displs, MPI_FLOAT, 0, MPI_COMM_WORLD); 283 | 284 | if(tid == 0){ 285 | for(int ind = 0; ind < (nx*ne); ind++){ 286 | 287 | ix = floor(ind/ne); 288 | ie = ind % ne; 289 | 290 | Val[age*nx*ne + ix*ne + ie] = Val1[ix*ne + ie]; 291 | } 292 | 293 | t = MPI_Wtime() - t0; 294 | cout << "Age: " << age << ". Time: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds." << endl; 295 | } 296 | } 297 | 298 | MPI_Finalize(); 299 | 300 | if(tid == 0){ 301 | std::cout << " " << std::endl; 302 | t = MPI_Wtime() - t0; 303 | std::cout << "TOTAL ELAPSED TIME: " << 1000000*((float)t)/CLOCKS_PER_SEC << " seconds. " << std::endl; 304 | } 305 | 306 | 307 | // //--------------------------------// 308 | // // Some checks // 309 | // //--------------------------------// 310 | 311 | if(tid == 0){ 312 | std::cout << " " << std::endl; 313 | std::cout << " - - - - - - - - - - - - - - - - - - - - - " << std::endl; 314 | std::cout << " " << std::endl; 315 | std::cout << "The first entries of the value function: " << std::endl; 316 | std::cout << " " << std::endl; 317 | 318 | for(int i = 0; i<3; i++){ 319 | std::cout << Val[i] << std::endl; 320 | } 321 | } 322 | 323 | return 0; 324 | } 325 | -------------------------------------------------------------------------------- /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_OpenMP.cpp -fopenmp -o Cpp_main 12 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 13 | rm Cpp_main 14 | 15 | cpp1: 16 | g++ Cpp_main_OpenMP.cpp -fopenmp -o Cpp_main -O1 17 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 18 | rm Cpp_main 19 | 20 | cpp2: 21 | g++ Cpp_main_OpenMP.cpp -fopenmp -o Cpp_main -O2 22 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 23 | rm Cpp_main 24 | 25 | cpp3: 26 | g++ Cpp_main_OpenMP.cpp -fopenmp -o Cpp_main -O3 27 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 28 | rm Cpp_main 29 | 30 | pgi2: 31 | pgc++ Cpp_main_OpenMP.cpp -o Cpp_main -mp -Minfo=accel -O 32 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 33 | rm Cpp_main 34 | 35 | pgi: 36 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main -fast -ta=multicore -acc 37 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 38 | rm Cpp_main 39 | 40 | acc: 41 | PGI=/opt/pgi; 42 | PATH=/opt/pgi/linux86-64/17.10/bin:$PATH; 43 | MANPATH=$MANPATH:/opt/pgi/linux86-64/17.10/man; 44 | LM_LICENSE_FILE=$LM_LICENSE_FILE:/opt/pgi/license.dat; 45 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main_acc.exe -fast -acc -ta=nvidia 46 | ./Cpp_main_acc.exe; 47 | rm Cpp_main_acc.exe 48 | 49 | acc_profile: 50 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main_acc.exe -fast -acc -ta=nvidia -Minfo=accel,ccff 51 | ./Cpp_main_acc.exe; 52 | pgprof ./Cpp_main_acc.exe 53 | rm Cpp_main_acc.exe 54 | 55 | omp: 56 | g++ Cpp_main_OpenACC.cpp -o Cpp_main_omp.exe -fopenmp 57 | ./Cpp_main_omp.exe; 58 | rm Cpp_main_omp.exe 59 | 60 | omp_pgi: 61 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main_omp_pgi.exe -fast -mp -ta=multicore 62 | ./Cpp_main_omp_pgi.exe; 63 | rm Cpp_main_omp_pgi.exe 64 | 65 | julia_parallel: 66 | julia -p$(CORES) Julia_main_parallel.jl 67 | 68 | julia_pmap: 69 | julia -p$(CORES) Julia_main_pmap.jl 70 | 71 | Rcpp: 72 | export OMP_NUM_THREADS=$(CORES); Rscript Rcpp_main.R; 73 | 74 | R: 75 | Rscript R_main.R $(CORES) 76 | 77 | python: 78 | python Python_main.py $(CORES) 79 | 80 | matlab: 81 | matlab -nodesktop -nodisplay -r "Matlab_main $(CORES)" 82 | 83 | MPI: 84 | mpic++ -g MPI_main.cpp -o main 85 | mpirun -np $(CORES) -hostfile MPI_host_file ./main 86 | rm main 87 | 88 | CUDA: 89 | export PATH=/usr/local/cuda/bin/:$PATH 90 | export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH 91 | nvcc CUDA_main.cu -o main 92 | ./main 93 | rm main 94 | 95 | -------------------------------------------------------------------------------- /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_OpenMP.cpp -fopenmp -o Cpp_main 12 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 13 | rm Cpp_main 14 | 15 | cpp1: 16 | g++ Cpp_main_OpenMP.cpp -fopenmp -o Cpp_main -O1 17 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 18 | rm Cpp_main 19 | 20 | cpp2: 21 | g++ Cpp_main_OpenMP.cpp -fopenmp -o Cpp_main -O2 22 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 23 | rm Cpp_main 24 | 25 | cpp3: 26 | g++ Cpp_main_OpenMP.cpp -fopenmp -o Cpp_main -O3 27 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 28 | rm Cpp_main 29 | 30 | pgi2: 31 | pgc++ Cpp_main_OpenMP.cpp -o Cpp_main -mp -Minfo=accel -O 32 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 33 | rm Cpp_main 34 | 35 | pgi: 36 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main -fast -ta=multicore -acc 37 | export OMP_NUM_THREADS=$(CORES); ./Cpp_main; 38 | rm Cpp_main 39 | 40 | acc: 41 | PGI=/opt/pgi; 42 | PATH=/opt/pgi/linux86-64/17.10/bin:$PATH; 43 | MANPATH=$MANPATH:/opt/pgi/linux86-64/17.10/man; 44 | LM_LICENSE_FILE=$LM_LICENSE_FILE:/opt/pgi/license.dat; 45 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main_acc.exe -fast -acc -ta=nvidia 46 | ./Cpp_main_acc.exe; 47 | rm Cpp_main_acc.exe 48 | 49 | acc_profile: 50 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main_acc.exe -fast -acc -ta=nvidia -Minfo=accel,ccff 51 | ./Cpp_main_acc.exe; 52 | pgprof ./Cpp_main_acc.exe 53 | rm Cpp_main_acc.exe 54 | 55 | omp: 56 | g++ Cpp_main_OpenACC.cpp -o Cpp_main_omp.exe -fopenmp 57 | ./Cpp_main_omp.exe; 58 | rm Cpp_main_omp.exe 59 | 60 | omp_pgi: 61 | pgc++ Cpp_main_OpenACC.cpp -o Cpp_main_omp_pgi.exe -fast -mp -ta=multicore 62 | ./Cpp_main_omp_pgi.exe; 63 | rm Cpp_main_omp_pgi.exe 64 | 65 | julia_parallel: 66 | ./julia -p$(CORES) Julia_main_parallel.jl 67 | 68 | julia_pmap: 69 | julia -p$(CORES) Julia_main_pmap.jl 70 | 71 | Rcpp: 72 | export OMP_NUM_THREADS=$(CORES); Rscript Rcpp_main.R; 73 | 74 | R: 75 | Rscript R_main.R $(CORES) 76 | 77 | python: 78 | python Python_main.py $(CORES) 79 | 80 | matlab: 81 | matlab -nodesktop -nodisplay -r "Matlab_main $(CORES)" 82 | 83 | MPI: 84 | mpic++ -g MPI_main.cpp -o main 85 | mpirun -np $(CORES) -hostfile MPI_host_file ./main 86 | rm main 87 | 88 | CUDA: 89 | export PATH=/usr/local/cuda/bin/:$PATH 90 | export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH 91 | nvcc CUDA_main.cu -o main 92 | ./main 93 | rm main 94 | 95 | -------------------------------------------------------------------------------- /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 = 1500; 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 | bbeta = 0.97; 29 | T = 10; 30 | 31 | % Prices 32 | r = 0.07; 33 | w = 5; 34 | 35 | % Initialize the grid for X 36 | xgrid = zeros(1, nx); 37 | 38 | % Initialize the grid for E and the transition probability matrix 39 | egrid = zeros(1, ne); 40 | P = zeros(ne, ne); 41 | 42 | % Initialize value function V 43 | V = zeros(T, nx, ne); 44 | 45 | 46 | %--------------------------------% 47 | % Grid creation % 48 | %--------------------------------% 49 | 50 | % Grid for x 51 | size = nx; 52 | xstep = (xmax - xmin) /(size - 1); 53 | it = 0; 54 | for i = 1:nx 55 | xgrid(i) = xmin + it*xstep; 56 | it = it+1; 57 | end 58 | 59 | % Grid for e with Tauchen (1986) 60 | size = ne; 61 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 62 | estep = 2*ssigma_y*m / (size-1); 63 | it = 0; 64 | for i = 1:ne 65 | egrid(i) = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + it*estep); 66 | it = it+1; 67 | end 68 | 69 | % Transition probability matrix Tauchen (1986) 70 | mm = egrid(2) - egrid(1); 71 | for j = 1:ne 72 | for k = 1:ne 73 | if k == 1 74 | P(j, k) = normcdf((egrid(k) - llambda_eps*egrid(j) + (mm/2))/ssigma_eps); 75 | elseif k == ne 76 | P(j, k) = 1 - normcdf((egrid(k) - llambda_eps*egrid(j) - (mm/2))/ssigma_eps); 77 | else 78 | 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); 79 | end 80 | end 81 | end 82 | 83 | % Exponential of the grid e 84 | for i = 1:ne 85 | egrid(i) = exp(egrid(i)); 86 | end 87 | 88 | 89 | 90 | %--------------------------------% 91 | % Life-cycle computation % 92 | %--------------------------------% 93 | 94 | disp(' ') 95 | disp('Life cycle computation: ') 96 | disp(' ') 97 | 98 | tic; 99 | 100 | tempV = zeros(nx*ne); 101 | 102 | for age = T:-1:1 103 | parfor ind = 1:(ne*nx) 104 | 105 | ix = int64(floor((ind-0.05)/ne))+1; 106 | ie = int64(floor(mod(ind-0.05, ne))+1); 107 | 108 | VV = -10.0^3; 109 | for ixp = 1:1:nx 110 | 111 | expected = 0.0; 112 | if age < T 113 | for iep = 1: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.0^(5); 124 | end 125 | if utility >= VV 126 | VV = utility; 127 | end 128 | 129 | utility = 0.0; 130 | end 131 | 132 | tempV(ind) = VV; 133 | 134 | end 135 | 136 | for ind = 1:nx*ne 137 | ix = int64(floor((ind-0.05)/ne))+1; 138 | ie = int64(floor(mod(ind-0.05, ne))+1); 139 | 140 | V(age, ix, ie) = tempV(ind); 141 | end 142 | 143 | finish = toc; 144 | disp(['Age: ', num2str(age), '. Time: ', num2str(round(finish, 3)), ' seconds.']) 145 | end 146 | 147 | disp(' ') 148 | finish = toc; 149 | disp(['TOTAL ELAPSED TIME: ', num2str(finish), ' seconds. ']) 150 | 151 | 152 | %---------------------% 153 | % Some checks % 154 | %---------------------% 155 | 156 | disp(' ') 157 | disp(' - - - - - - - - - - - - - - - - - - - - - ') 158 | disp(' ') 159 | disp('The first entries of the value function: ') 160 | disp(' ') 161 | 162 | for i = 1:3 163 | disp(num2str(V(1, 1, i))); 164 | end 165 | 166 | disp(' ') 167 | quit() 168 | 169 | 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 = 1500; 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 | bbeta = 0.97; 35 | T = 10; 36 | 37 | # Prices 38 | r = 0.07; 39 | w = 5; 40 | 41 | # Initialize the grid for X 42 | xgrid = numpy.zeros(nx) 43 | 44 | # Initialize the grid for E and the transition probability matrix 45 | egrid = numpy.zeros(ne) 46 | P = numpy.zeros((ne, ne)) 47 | 48 | # Initialize value function V 49 | V = numpy.zeros((T, nx, ne)) 50 | 51 | 52 | #--------------------------------# 53 | # Grid creation # 54 | #--------------------------------# 55 | 56 | # Function to construct the grid for capital (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 | # Function to construct the grid for productivity (e) using 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 | # Function to construct the transition probability matrix for productivity (P) using 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 | #--------------------------------# 94 | # Structure and function # 95 | #--------------------------------# 96 | 97 | # Value function 98 | VV = math.pow(-10.0, 5); 99 | 100 | 101 | # Data structure of state and exogenous variables 102 | class modelState(object): 103 | def __init__(self,ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta,w,r): 104 | self.ind = ind 105 | self.ne = ne 106 | self.nx = nx 107 | self.T = T 108 | self.age = age 109 | self.P = P 110 | self.xgrid = xgrid 111 | self.egrid = egrid 112 | self.ssigma = ssigma 113 | self.bbeta = bbeta 114 | self.w = w 115 | self.r = r 116 | 117 | # Function that returns value for a given state 118 | # ind: a unique state that corresponds to a pair (ie,ix) 119 | def value_func(states): 120 | 121 | ind = states.ind 122 | ne = states.ne 123 | nx = states.nx 124 | T = states.T 125 | age = states.age 126 | P = states.P 127 | xgrid = states.xgrid 128 | egrid = states.egrid 129 | ssigma = states.ssigma 130 | bbeta = states.bbeta 131 | w = states.w 132 | r = states.r 133 | 134 | ix = int(math.floor(ind/ne)); 135 | ie = int(math.floor(ind%ne)); 136 | 137 | VV = math.pow(-10.0, 3) 138 | for ixp in range(0,nx): 139 | expected = 0.0; 140 | if(age < T-1): 141 | for iep in range(0,ne): 142 | expected = expected + P[ie, iep]*V[age+1, ixp, iep] 143 | 144 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 145 | 146 | utility = math.pow(cons, (1-ssigma))/(1-ssigma) + bbeta*expected; 147 | 148 | if(cons <= 0): 149 | utility = math.pow(-10.0,5); 150 | 151 | if(utility >= VV): 152 | VV = utility; 153 | 154 | utility = 0.0; 155 | 156 | return[VV]; 157 | 158 | 159 | 160 | #--------------------------------# 161 | # Life-cycle computation # 162 | #--------------------------------# 163 | 164 | print(" ") 165 | print("Life cycle computation: ") 166 | print(" ") 167 | 168 | 169 | start = time.time() 170 | 171 | for age in reversed(range(0,T)): 172 | 173 | # This function computes `value_func` in parallel for all the states 174 | 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)) 175 | 176 | # I write the results on the value matrix: V 177 | for ind in range(0,nx*ne): 178 | 179 | ix = int(math.floor(ind/ne)); 180 | ie = int(math.floor(ind%ne)); 181 | 182 | V[age, ix, ie] = results[ind][0]; 183 | 184 | finish = time.time() - start 185 | print "Age: ", age+1, ". Time: ", round(finish, 4), " seconds." 186 | 187 | finish = time.time() - start 188 | print "TOTAL ELAPSED TIME: ", round(finish, 4), " seconds. \n" 189 | 190 | 191 | #---------------------# 192 | # Some checks # 193 | #---------------------# 194 | 195 | print " - - - - - - - - - - - - - - - - - - - - - \n" 196 | print "The first entries of the value function: \n" 197 | 198 | for i in range(0,3): 199 | print(round(V[0, 0, i], 5)) 200 | 201 | print " \n" 202 | 203 | -------------------------------------------------------------------------------- /Python_numba_main.py: -------------------------------------------------------------------------------- 1 | 2 | #--------------------------------# 3 | # House-keeping # 4 | #--------------------------------# 5 | 6 | from numba import jit, jitclass, njit, prange, int64, float64 7 | import numpy 8 | import math 9 | import time 10 | from scipy.stats import norm 11 | from collections import OrderedDict 12 | import sys 13 | 14 | #--------------------------------# 15 | # Initialization # 16 | #--------------------------------# 17 | 18 | # Number of workers 19 | 20 | # Grid for x 21 | nx = 1500; 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 | bbeta = 0.97; 34 | T = 10; 35 | 36 | # Prices 37 | r = 0.07; 38 | w = 5; 39 | 40 | # Initialize the grid for X 41 | xgrid = numpy.zeros(nx) 42 | 43 | # Initialize the grid for E and the transition probability matrix 44 | egrid = numpy.zeros(ne) 45 | P = numpy.zeros((ne, ne)) 46 | 47 | 48 | 49 | 50 | #--------------------------------# 51 | # Grid creation # 52 | #--------------------------------# 53 | 54 | # Function to construct the grid for capital (x) 55 | size = nx; 56 | xstep = (xmax - xmin) /(size - 1); 57 | it = 0; 58 | for i in range(0,nx): 59 | xgrid[i] = xmin + it*xstep; 60 | it = it+1; 61 | 62 | 63 | # Function to construct the grid for productivity (e) using Tauchen (1986) 64 | size = ne; 65 | ssigma_y = math.sqrt(math.pow(ssigma_eps, 2) / (1 - math.pow(llambda_eps,2))); 66 | estep = 2*ssigma_y*m / (size-1); 67 | it = 0; 68 | for i in range(0,ne): 69 | egrid[i] = (-m*math.sqrt(math.pow(ssigma_eps, 2) / (1 - math.pow(llambda_eps,2))) + it*estep); 70 | it = it+1; 71 | 72 | 73 | # Function to construct the transition probability matrix for productivity (P) using Tauchen (1986) 74 | mm = egrid[1] - egrid[0]; 75 | for j in range(0,ne): 76 | for k in range(0,ne): 77 | if (k == 0): 78 | P[j, k] = norm.cdf((egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 79 | elif (k == ne-1): 80 | P[j, k] = 1 - norm.cdf((egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 81 | else: 82 | 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); 83 | 84 | 85 | # Exponential of the grid e 86 | for i in range(0,ne): 87 | egrid[i] = math.exp(egrid[i]); 88 | 89 | 90 | 91 | #--------------------------------# 92 | # Structure and function # 93 | #--------------------------------# 94 | 95 | # Value function 96 | VV = math.pow(-10.0, 5); 97 | 98 | specs = OrderedDict() 99 | specs['ind'] = int64 100 | specs['ne'] = int64 101 | specs['nx'] = int64 102 | specs['T'] = int64 103 | specs['age'] = int64 104 | specs['P'] = float64[:,:] 105 | specs['xgrid'] = float64[:] 106 | specs['egrid'] = float64[:] 107 | specs['ssigma'] = float64 108 | specs['bbeta'] = float64 109 | specs['w'] = float64 110 | specs['r'] = float64 111 | specs['V'] = float64[:,:,:] 112 | 113 | 114 | # Data structure of state and exogenous variables 115 | @jitclass(specs) 116 | class modelState(object): 117 | def __init__(self,ind,ne,nx,T,age,P,xgrid,egrid,ssigma,bbeta,w,r,V): 118 | self.ind = ind 119 | self.ne = ne 120 | self.nx = nx 121 | self.T = T 122 | self.age = age 123 | self.P = P 124 | self.xgrid = xgrid 125 | self.egrid = egrid 126 | self.ssigma = ssigma 127 | self.bbeta = bbeta 128 | self.w = w 129 | self.r = r 130 | self.V = V 131 | 132 | # Function that returns value for a given state 133 | # ind: a unique state that corresponds to a pair (ie,ix) 134 | @njit 135 | def value_func(states): 136 | 137 | ind = states.ind 138 | ne = states.ne 139 | nx = states.nx 140 | T = states.T 141 | age = states.age 142 | P = states.P 143 | xgrid = states.xgrid 144 | egrid = states.egrid 145 | ssigma = states.ssigma 146 | bbeta = states.bbeta 147 | w = states.w 148 | r = states.r 149 | V = states.V 150 | 151 | ix = int(math.floor(ind/ne)); 152 | ie = int(math.floor(ind%ne)); 153 | 154 | VV = math.pow(-10.0, 3) 155 | for ixp in range(0,nx): 156 | expected = 0.0; 157 | if(age < T-1): 158 | for iep in range(0,ne): 159 | expected = expected + P[ie, iep]*V[age+1, ixp, iep] 160 | 161 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 162 | 163 | utility = math.pow(cons, (1-ssigma))/(1-ssigma) + bbeta*expected; 164 | 165 | if(cons <= 0): 166 | utility = math.pow(-10.0,5); 167 | 168 | if(utility >= VV): 169 | VV = utility; 170 | 171 | utility = 0.0; 172 | 173 | return[VV]; 174 | 175 | 176 | 177 | #--------------------------------# 178 | # Life-cycle computation # 179 | #--------------------------------# 180 | 181 | print(" ") 182 | print("Life cycle computation: ") 183 | print(" ") 184 | 185 | @njit(parallel=True) 186 | def compute(age, V): 187 | 188 | for ind in prange(0,nx*ne): 189 | 190 | states = modelState(ind, ne, nx, T, age, P, xgrid, egrid, ssigma, bbeta, w, r, V) 191 | 192 | ix = int(math.floor(ind/ne)); 193 | ie = int(math.floor(ind%ne)); 194 | 195 | V[age, ix, ie] = value_func(states)[0]; 196 | 197 | return(V) 198 | 199 | 200 | 201 | start = time.time() 202 | # Initialize value function V 203 | V = numpy.zeros((T, nx, ne)) 204 | 205 | for age in range(T-1, -1, -1): 206 | V = compute(age, V) 207 | 208 | finish = time.time() - start 209 | print("Age: ", age+1, ". Time: ", round(finish, 4), " seconds.") 210 | 211 | 212 | finish = time.time() - start 213 | print("TOTAL ELAPSED TIME: ", round(finish, 4), " seconds. \n") 214 | 215 | 216 | #---------------------# 217 | # Some checks # 218 | #---------------------# 219 | 220 | print(" - - - - - - - - - - - - - - - - - - - - - \n") 221 | print("The first entries of the value function: \n") 222 | 223 | for i in range(0,3): 224 | print(round(V[0, 0, i], 5)) 225 | 226 | print(" \n") 227 | 228 | -------------------------------------------------------------------------------- /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 = 1500; 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 | bbeta = 0.97; 31 | T = 10; 32 | 33 | # Prices 34 | r = 0.07; 35 | w = 5; 36 | 37 | # Initialize grids 38 | xgrid = matrix(0, 1, nx) 39 | egrid = matrix(0, 1, ne) 40 | P = matrix(0, ne, ne) 41 | V = array(0, dim=c(T, nx, ne)) 42 | 43 | 44 | #--------------------------------# 45 | # Grid creation # 46 | #--------------------------------# 47 | 48 | # Grid for capital (x) 49 | size = nx; 50 | xstep = (xmax - xmin) /(size - 1); 51 | it = 0; 52 | for(i in 1:nx){ 53 | xgrid[i] = xmin + it*xstep; 54 | it = it+1; 55 | } 56 | 57 | # Grid for productivity (e) with Tauchen (1986) 58 | size = ne; 59 | ssigma_y = sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))); 60 | estep = 2*ssigma_y*m / (size-1); 61 | it = 0; 62 | for(i in 1:ne){ 63 | egrid[i] = (-m*sqrt((ssigma_eps^2) / (1 - (llambda_eps^2))) + it*estep); 64 | it = it+1; 65 | } 66 | 67 | # Transition probability matrix (P) Tauchen (1986) 68 | mm = egrid[2] - egrid[1]; 69 | for(j in 1:ne){ 70 | for(k in 1:ne){ 71 | if(k == 1){ 72 | P[j, k] = pnorm((egrid[k] - llambda_eps*egrid[j] + (mm/2))/ssigma_eps); 73 | } else if(k == ne){ 74 | P[j, k] = 1 - pnorm((egrid[k] - llambda_eps*egrid[j] - (mm/2))/ssigma_eps); 75 | } else{ 76 | 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); 77 | } 78 | } 79 | } 80 | 81 | # Exponential of the grid e 82 | for(i in 1:ne){ 83 | egrid[i] = exp(egrid[i]); 84 | } 85 | 86 | #--------------------------------# 87 | # Value function # 88 | #--------------------------------# 89 | 90 | # Function that computes value function, given vector of state variables 91 | value = function(ind){ 92 | 93 | ix = as.integer(floor((ind-0.05)/ne))+1; 94 | ie = as.integer(floor((ind-0.05) %% ne)+1); 95 | 96 | VV = -10.0^3; 97 | for(ixp in 1:nx){ 98 | 99 | expected = 0.0; 100 | if(age < T){ 101 | for(iep in 1:ne){ 102 | expected = expected + P[ie, iep]*V[age+1, ixp, iep]; 103 | } 104 | } 105 | 106 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 107 | 108 | utility = (cons^(1-ssigma))/(1-ssigma) + bbeta*expected; 109 | 110 | if(cons <= 0){ 111 | utility = -10.0^(5); 112 | } 113 | 114 | if(utility >= VV){ 115 | VV = utility; 116 | } 117 | } 118 | 119 | return(VV); 120 | } 121 | 122 | 123 | #--------------------------------# 124 | # Life-cycle computation # 125 | #--------------------------------# 126 | 127 | print(" ") 128 | print("Life cycle computation: ") 129 | print(" ") 130 | 131 | start = proc.time()[3]; 132 | 133 | for(age in T:1){ 134 | 135 | clusterExport(cl, c("V", "age", "ne","nx", "r", "T", "P", "xgrid", "egrid", "ssigma", "bbeta", "w"), envir=environment()) 136 | 137 | s = parLapply(cl, 1:(ne*nx), value) 138 | 139 | for(ind in 1:(nx*ne)){ 140 | ix = as.integer(floor((ind-0.05)/ne))+1; 141 | ie = as.integer(floor((ind-0.05) %% ne)+1); 142 | 143 | V[age, ix, ie] = s[[ind]][1] 144 | } 145 | 146 | finish = proc.time()[3] - start; 147 | print(paste0("Age: ", age, ". Time: ", round(finish, 3), " seconds.")) 148 | } 149 | 150 | print(" ") 151 | finish = proc.time()[3] - start; 152 | print(paste("TOTAL ELAPSED TIME: ", finish, " seconds. ")) 153 | 154 | 155 | #---------------------# 156 | # Some checks # 157 | #---------------------# 158 | 159 | print(" ") 160 | print(" - - - - - - - - - - - - - - - - - - - - - ") 161 | print(" ") 162 | print("The first entries of the value function: ") 163 | print(" ") 164 | 165 | for(i in 1:3){ 166 | print(V[1, 1, i]) 167 | } 168 | 169 | print(" ") 170 | -------------------------------------------------------------------------------- /Rcpp_main.R: -------------------------------------------------------------------------------- 1 | 2 | #--------------------------------# 3 | # House-keeping # 4 | #--------------------------------# 5 | 6 | .libPaths( c( .libPaths(), "~/R/x86_64-pc-linux-gnu-library/3.4/") ) 7 | 8 | library("Rcpp") 9 | 10 | setwd("/home/david/Dropbox/Documents/Doctorado/Computation course/Codigos/Github Repository/Parallel_Computing_2/") 11 | 12 | Sys.setenv("PKG_CXXFLAGS"=" -fopenmp") 13 | 14 | # Number of workers 15 | sourceCpp("Rcpp_main.cpp") 16 | 17 | 18 | #--------------------------------# 19 | # Initialization # 20 | #--------------------------------# 21 | 22 | # Grid for x 23 | nx = 1500; 24 | xmin = 0.1; 25 | xmax = 4.0; 26 | 27 | # Grid for e: parameters for Tauchen 28 | ne = 15; 29 | ssigma_eps = 0.02058; 30 | llambda_eps = 0.99; 31 | m = 1.5; 32 | 33 | # Utility function 34 | ssigma = 2; 35 | bbeta = 0.97; 36 | T = 10; 37 | 38 | # Prices 39 | r = 0.07; 40 | w = 5; 41 | 42 | 43 | #--------------------------------# 44 | # Value function # 45 | #--------------------------------# 46 | 47 | V = value(nx, xmin, xmax, 48 | ne, ssigma_eps, llambda_eps, m, 49 | ssigma, bbeta, T, r, w); 50 | 51 | 52 | # I recover the Policy Functions 53 | Value = array(0,dim=c(T, nx, ne)); 54 | 55 | for (age in 1:T){ 56 | for (ix in 1:nx){ 57 | for(ie in 1:ne){ 58 | Value[age, ix, ie] = V[(age-1)*nx*ne + (ix-1)*ne + ie]; 59 | } 60 | } 61 | } 62 | 63 | #---------------------# 64 | # Some checks # 65 | #---------------------# 66 | 67 | print(" ") 68 | print(" - - - - - - - - - - - - - - - - - - - - - ") 69 | print(" ") 70 | print("The first entries of the value function: ") 71 | print(" ") 72 | 73 | for(i in 1:3){ 74 | print(Value[1, 1, i]) 75 | } 76 | 77 | print(" ") 78 | -------------------------------------------------------------------------------- /Rcpp_main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | //====================================== 9 | // Grids 10 | //====================================== 11 | 12 | // Function to construct the grid for capital (x) 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 | // Function to construct the grid for productivity (e) using Tauchen (1986) 27 | void gride(const int ne, const float ssigma_eps, const float llambda_eps, const float m, float* egrid){ 28 | 29 | // This grid is made with Tauchen (1986) 30 | const float size = ne; 31 | const float ssigma_y = sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))); 32 | const float estep = 2*ssigma_y*m / (size-1); 33 | float it = 0; 34 | 35 | for(int i = 0; i < ne; i++){ 36 | egrid[i] = (-m*sqrt(pow(ssigma_eps, 2) / (1 - pow(llambda_eps, 2))) + it*estep); 37 | it++; 38 | } 39 | } 40 | 41 | // Function to compute CDF of Normal distribution 42 | float normCDF(const float value){ 43 | return 0.5 * erfc(-value * M_SQRT1_2); 44 | } 45 | 46 | 47 | 48 | // Function to construct the transition probability matrix for productivity (P) using Tauchen (1986) 49 | void eprob(const int ne, const float ssigma_eps, const float llambda_eps, const float m, const float* egrid, float* P){ 50 | 51 | // This grid is made with Tauchen (1986) 52 | // P is: first ne elements are transition from e_0 to e_i, 53 | // second ne elementrs are from e_1 to e_i, ... 54 | const float w = egrid[1] - egrid[0]; 55 | 56 | for(int j = 0; j < ne; j++){ 57 | for(int k = 0; k < ne; k++){ 58 | if(k == 0){ 59 | P[j*ne + k] = normCDF((egrid[k] - llambda_eps*egrid[j] + (w/2))/ssigma_eps); 60 | } else if(k == ne-1){ 61 | P[j*ne + k] = 1 - normCDF((egrid[k] - llambda_eps*egrid[j] - (w/2))/ssigma_eps); 62 | } else{ 63 | 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); 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | // Data structure of state and exogenous variables 71 | struct modelState{ 72 | int ie; 73 | int ix; 74 | int ne; 75 | int nx; 76 | int T; 77 | int age; 78 | float *P; 79 | float *xgrid; 80 | float *egrid; 81 | float ssigma; 82 | float bbeta; 83 | float *V; 84 | float w; 85 | float r; 86 | }; 87 | 88 | // Function that computes value function, given vector of state variables 89 | float value(modelState currentState){ 90 | 91 | int ie = currentState.ie; 92 | int ix = currentState.ix; 93 | int ne = currentState.ne; 94 | int nx = currentState.nx; 95 | int T = currentState.T; 96 | int age = currentState.age; 97 | float *P = currentState.P; 98 | float *xgrid = currentState.xgrid; 99 | float *egrid = currentState.egrid; 100 | float ssigma = currentState.ssigma; 101 | float bbeta = currentState.bbeta; 102 | float *V = currentState.V; 103 | float w = currentState.w; 104 | float r = currentState.r; 105 | 106 | float expected; 107 | float utility; 108 | float cons; 109 | float VV = pow(-10.0,5.0); 110 | 111 | for(int ixp = 0; ixp < nx; ixp++){ 112 | 113 | expected = 0.0; 114 | if(age < T-1){ 115 | for(int iep = 0; iep < ne; iep++){ 116 | expected = expected + P[ie*ne + iep]*V[(age+1)*nx*ne + ixp*ne + iep]; 117 | } 118 | } 119 | 120 | cons = (1 + r)*xgrid[ix] + egrid[ie]*w - xgrid[ixp]; 121 | 122 | utility = pow(cons, 1-ssigma) / (1-ssigma) + bbeta*expected; 123 | 124 | if(cons <= 0){ 125 | utility = pow(-10.0, 5.0); 126 | } 127 | 128 | if(utility >= VV){ 129 | VV = utility; 130 | } 131 | } 132 | 133 | return VV; 134 | } 135 | 136 | 137 | 138 | //====================================== 139 | // MAIN MAIN MAIN 140 | //====================================== 141 | 142 | // [[Rcpp::export]] 143 | vector value(int nx, float xmin, float xmax, 144 | int ne, float ssigma_eps, float llambda_eps, float m, 145 | float ssigma, float bbeta, int T, float r, float w){ 146 | 147 | // Initialize the grid for X 148 | float xgrid[nx]; 149 | 150 | // Initialize the grid for E and the transition probability matrix 151 | float egrid[ne]; 152 | float P[ne*ne]; 153 | 154 | // Initialize value function V 155 | vector Val; 156 | Val.resize(T*nx*ne); 157 | 158 | // Initialize value function V - provisional 159 | size_t sizeV = T*ne*nx*sizeof(float); 160 | float *V; 161 | V = (float *)malloc(sizeV); 162 | 163 | // Initialize data structure of state and exogenous variables 164 | modelState currentState; 165 | 166 | 167 | //--------------------------------// 168 | // Grid creation // 169 | //--------------------------------// 170 | 171 | gridx(nx, xmin, xmax, xgrid); 172 | gride(ne, ssigma_eps, llambda_eps, m, egrid); 173 | eprob(ne, ssigma_eps, llambda_eps, m, egrid, P); 174 | 175 | // Exponential of the grid e 176 | for(int i=0; i=0; age--){ 194 | 195 | #pragma omp parallel for shared(V, age, P, xgrid, egrid, t, t0) private(currentState) 196 | for(int ix = 0; ix=0; age--){ 214 | for(int ix = 0; ix 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. `Julia_threads.jl`: Julia code with @threads parallelization 24 | 6. `Matlab_main.m`: Matlab code 25 | 7. `MPI_host_file`: MPI host file 26 | 8. `MPI_main.cpp`: C++ code for MPI 27 | 9. `Python_main.py`: Python code 28 | 10. `Python_numba_main.py`: Python code with numba parallelization 29 | 11. `Rcpp_main.cpp`: C++ code for Rcpp package in R 30 | 12. `Rcpp_main.R`: Rcpp code 31 | 13. `R_main.R`: R code 32 | 14. `Makefile`: Makefile to execute codes 33 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------