diff --git a/matlab/perfect-foresight-models/perfect_foresight_solver_core.m b/matlab/perfect-foresight-models/perfect_foresight_solver_core.m index 0aa88b233fdfe0348dee2582552c472fc7aeaf25..8d6ec41b2f41e1bf280f53f8b6b43608fbe9c036 100644 --- a/matlab/perfect-foresight-models/perfect_foresight_solver_core.m +++ b/matlab/perfect-foresight-models/perfect_foresight_solver_core.m @@ -63,7 +63,7 @@ if options_.block if M_.block_structure.time_recursive error('Internal error: can''t perform stacked perfect foresight simulation with time-recursive block decomposition') end - if options_.bytecode + if options_.bytecode && ~ismember(options_.stack_solve_algo, [1 6]) try y = bytecode('dynamic', 'block_decomposed', M_, options_, y, exo_simul, M_.params, steady_state, periods); success = true; diff --git a/matlab/perfect-foresight-models/solve_block_decomposed_problem.m b/matlab/perfect-foresight-models/solve_block_decomposed_problem.m index 4f03473c7dd138a8b9b971b89f15d385f6d4e1d8..5901ab2b7fd12500b275d4f0885719ae1e61797b 100644 --- a/matlab/perfect-foresight-models/solve_block_decomposed_problem.m +++ b/matlab/perfect-foresight-models/solve_block_decomposed_problem.m @@ -59,7 +59,11 @@ nblocks = length(M_.block_structure.block); per_block_status = struct('success', cell(1, nblocks), 'error', cell(1, nblocks), 'iterations', cell(1, nblocks)); for blk = 1:nblocks - fh_dynamic = str2func(sprintf('%s.sparse.block.dynamic_%d', M_.fname, blk)); + if options_.bytecode + fh_dynamic = @(y3n, x, params, ys, sparse_rowval, sparse_colval, sparse_colptr, T) bytecode_wrapper(y3n, x, params, ys, T, blk, M_, options_); + else + fh_dynamic = str2func(sprintf('%s.sparse.block.dynamic_%d', M_.fname, blk)); + end switch M_.block_structure.block(blk).Simulation_Type case {1, 2} % evaluate{Forward,Backward} @@ -115,3 +119,16 @@ for blk = 1:nblocks return end end + + +function [y3n, T, r, g1b] = bytecode_wrapper(y3n, x, params, ys, T, blk, M_, options_) + ypath = reshape(y3n, M_.endo_nbr, 3); + xpath = [ NaN(1, M_.exo_nbr); x; NaN(1, M_.exo_nbr) ]; + [r, g1, ypath, T] = bytecode('evaluate', 'dynamic', 'block_decomposed', ['block=' int2str(blk) ], M_, options_, ypath, xpath, params, ys, 1, true, T); + y3n = vec(ypath); + if ismember(M_.block_structure.block(blk).Simulation_Type, [3, 4, 6, 7]) % solve{Forward,Backward}{Simple,Complete} + g1b = spalloc(M_.block_structure.block(blk).mfs, M_.block_structure.block(blk).mfs, numel(g1)); + else + g1b = spalloc(M_.block_structure.block(blk).mfs, 3*M_.block_structure.block(blk).mfs, numel(g1)); + end + g1b(:, nonzeros(M_.block_structure.block(blk).bytecode_jacob_cols_to_sparse)) = g1(:, find(M_.block_structure.block(blk).bytecode_jacob_cols_to_sparse)); diff --git a/mex/sources/bytecode/Interpreter.cc b/mex/sources/bytecode/Interpreter.cc index ce06c37ff9b464dac75d1ab3740c912157b32f00..452ece6ccfba1462cf976f752948058467e52627 100644 --- a/mex/sources/bytecode/Interpreter.cc +++ b/mex/sources/bytecode/Interpreter.cc @@ -2830,261 +2830,6 @@ Interpreter::golden(double ax, double bx, double cx, double tol) return { true, xmin }; } -void -Interpreter::Solve_Matlab_Relaxation(mxArray *A_m, mxArray *b_m) -{ - double *b_m_d = mxGetPr(b_m); - if (!b_m_d) - throw FatalException{"In Solve_Matlab_Relaxation, can't retrieve b_m vector"}; - mwIndex *A_m_i = mxGetIr(A_m); - if (!A_m_i) - throw FatalException{"In Solve_Matlab_Relaxation, can't retrieve Ir vector of matrix A"}; - mwIndex *A_m_j = mxGetJc(A_m); - if (!A_m_j) - throw FatalException{"In Solve_Matlab_Relaxation, can't retrieve Jc vectior of matrix A"}; - double *A_m_d = mxGetPr(A_m); - if (!A_m_d) - throw FatalException{"In Solve_Matlab_Relaxation, can't retrieve double float data of matrix A"}; - - /* Extract submatrices from the upper-left corner of A and subvectors at the - beginning of b, so that the system looks like: - ⎛B1 C1 …⎞ ⎛b1⎞ - ⎢A2 B2 …⎥ ⎢b2⎥ - ⎢ A3 …⎥ = ⎢ …⎥ - ⎢ … …⎥ ⎢ …⎥ - ⎝ …⎠ ⎝ …⎠ - */ - mxArray *B1 = mxCreateSparse(size, size, size*size, mxREAL); - mwIndex *B1_i = mxGetIr(B1); - mwIndex *B1_j = mxGetJc(B1); - double *B1_d = mxGetPr(B1); - mxArray *C1 = mxCreateSparse(size, size, size*size, mxREAL); - mwIndex *C1_i = mxGetIr(C1); - mwIndex *C1_j = mxGetJc(C1); - double *C1_d = mxGetPr(C1); - mxArray *A2 = mxCreateSparse(size, size, size*size, mxREAL); - mwIndex *A2_i = mxGetIr(A2); - mwIndex *A2_j = mxGetJc(A2); - double *A2_d = mxGetPr(A2); - mxArray *B2 = mxCreateSparse(size, size, size*size, mxREAL); - mwIndex *B2_i = mxGetIr(B2); - mwIndex *B2_j = mxGetJc(B2); - double *B2_d = mxGetPr(B2); - mxArray *A3 = mxCreateSparse(size, size, size*size, mxREAL); - mwIndex *A3_i = mxGetIr(A3); - mwIndex *A3_j = mxGetJc(A3); - double *A3_d = mxGetPr(A3); - - mxArray *b1 = mxCreateDoubleMatrix(size, 1, mxREAL); - double *b1_d = mxGetPr(b1); - mxArray *b2 = mxCreateDoubleMatrix(size, 1, mxREAL); - double *b2_d = mxGetPr(b2); - - unsigned int nze = 0; // Counter in nonzero elements of A - unsigned int B1_nze = 0, C1_nze = 0, A2_nze = 0, B2_nze = 0, A3_nze = 0; // Same for submatrices - - for (size_t var = 0; var < static_cast<size_t>(2*size); var++) // Iterate over columns of A - { - if (var < static_cast<size_t>(size)) - { - b1_d[var] = b_m_d[var]; - - B1_j[var] = B1_nze; - A2_j[var] = A2_nze; - } - else - { - b2_d[var - size] = b_m_d[var]; - - C1_j[var - size] = C1_nze; - B2_j[var - size] = B2_nze; - A3_j[var - size] = A3_nze; - } - - while (static_cast<unsigned int>(A_m_j[var+1]) > nze) - { - size_t eq = A_m_i[nze]; - if (var < static_cast<size_t>(size)) - { - if (eq < static_cast<size_t>(size)) - { - B1_i[B1_nze] = eq; - B1_d[B1_nze] = A_m_d[nze]; - B1_nze++; - } - else // Here we know that eq < 2*size, because of the structure of A - { - A2_i[A2_nze] = eq - size; - A2_d[A2_nze] = A_m_d[nze]; - A2_nze++; - } - } - else if (var < static_cast<size_t>(2*size)) - { - if (eq < static_cast<size_t>(size)) - { - C1_i[C1_nze] = eq; - C1_d[C1_nze] = A_m_d[nze]; - C1_nze++; - } - else if (eq < static_cast<size_t>(2*size)) - { - B2_i[B2_nze] = eq - size; - B2_d[B2_nze] = A_m_d[nze]; - B2_nze++; - } - else // Here we know that eq < 3*size, because of the structure of A - { - A3_i[A3_nze] = eq - 2*size; - A3_d[A3_nze] = A_m_d[nze]; - A3_nze++; - } - } - nze++; - } - } - B1_j[size] = B1_nze; - C1_j[size] = C1_nze; - A2_j[size] = A2_nze; - B2_j[size] = B2_nze; - A3_j[size] = A3_nze; - - vector<pair<mxArray *, mxArray *>> triangular_form; - mxArray *d1 = nullptr; - for (int t = 1; t <= periods; t++) - { - mxArray *B1_inv; - mexCallMATLAB(1, &B1_inv, 1, &B1, "inv"); - - // Compute subvector d1 of the triangularized system. - mxArray *B1_inv_t = Sparse_transpose(B1_inv); - mxDestroyArray(B1_inv); - d1 = mult_SAT_B(B1_inv_t, b1); - - /* Compute block S1 of the triangularized system. - Update B1, C1, B2, A2, A3, b1 and b2 for the next relaxation iteration. - Save S1 and d1 for the subsequent backward iteration. - E.g. at the end of the first iteration, the system will look like: - ⎛ I S1 … …⎞ ⎛d1⎞ - ⎢ B1 C1 …⎥ ⎢b1⎥ - ⎢ A2 B2 …⎥ = ⎢b2⎥ - ⎢ A3 …⎥ ⎢ …⎥ - ⎝ …⎠ ⎝ …⎠ - */ - if (t < periods) - { - // Compute S1 - mxArray *S1 = Sparse_mult_SAT_SB(B1_inv_t, C1); - - // Update A2, B1, b1 - mxArray *A2_t = Sparse_transpose(A2); - mxArray *tmp = Sparse_mult_SAT_SB(A2_t, S1); - mxDestroyArray(B1); - B1 = Sparse_subtract_SA_SB(B2, tmp); - mxDestroyArray(tmp); - - tmp = mult_SAT_B(A2_t, d1); - mxDestroyArray(A2_t); - mxDestroyArray(b1); - b1 = subtract_A_B(b2, tmp); - mxDestroyArray(tmp); - - mxDestroyArray(A2); - A2 = mxDuplicateArray(A3); - - // Save S1 and d1 - triangular_form.emplace_back(S1, d1); - } - - mxDestroyArray(B1_inv_t); - - if (t < periods - 1) - { - // Update C1, B2, A3, b2 - C1_nze = B2_nze = A3_nze = 0; - for (size_t var = (t+1)*size; var < static_cast<size_t>((t+2)*size); var++) - { - b2_d[var - (t+1)*size] = b_m_d[var]; - - C1_j[var - (t+1)*size] = C1_nze; - B2_j[var - (t+1)*size] = B2_nze; - A3_j[var - (t+1)*size] = A3_nze; - - while (static_cast<unsigned int>(A_m_j[var+1]) > nze) - { - size_t eq = A_m_i[nze]; - if (eq < static_cast<size_t>((t+1) * size)) - { - C1_i[C1_nze] = eq - t*size; - C1_d[C1_nze] = A_m_d[nze]; - C1_nze++; - } - else if (eq < static_cast<size_t>((t+2)*size)) - { - B2_i[B2_nze] = eq - (t+1)*size; - B2_d[B2_nze] = A_m_d[nze]; - B2_nze++; - } - else - { - A3_i[A3_nze] = eq - (t+2)*size; - A3_d[A3_nze] = A_m_d[nze]; - A3_nze++; - } - nze++; - } - } - C1_j[size] = C1_nze; - B2_j[size] = B2_nze; - A3_j[size] = A3_nze; - } - } - - // At this point, d1 contains the solution for the last period - double *d1_d = mxGetPr(d1); - for (int i = 0; i < size; i++) - { - int eq = index_vara[i+size*(y_kmin+periods-1)]; - double yy = -(d1_d[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc * yy; - } - - // Perform backward iteration to compute the solution for other periods - for (int t = periods-2; t >= 0; t--) - { - auto [S1, d1_next] = triangular_form.back(); - triangular_form.pop_back(); - mxArray *S1_t = Sparse_transpose(S1); - mxDestroyArray(S1); - mxArray *tmp = mult_SAT_B(S1_t, d1); - mxDestroyArray(S1_t); - mxDestroyArray(d1); - d1 = subtract_A_B(d1_next, tmp); - d1_d = mxGetPr(d1); - mxDestroyArray(d1_next); - mxDestroyArray(tmp); - for (int i = 0; i < size; i++) - { - int eq = index_vara[i+size*(y_kmin+t)]; - double yy = -(d1_d[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc * yy; - } - } - - mxDestroyArray(B1); - mxDestroyArray(C1); - mxDestroyArray(A2); - mxDestroyArray(B2); - mxDestroyArray(A3); - mxDestroyArray(b1); - mxDestroyArray(b2); - mxDestroyArray(A_m); - mxDestroyArray(b_m); - mxDestroyArray(d1); -} - void Interpreter::End_Solver() { @@ -4702,6 +4447,9 @@ Interpreter::Simulate_Newton_Two_Boundaries(bool cvg, const vector_table_conditi double *Ax {nullptr}, *b {nullptr}; SuiteSparse_long *Ap = nullptr, *Ai = nullptr; + assert(stack_solve_algo == 0 || stack_solve_algo == 2 || stack_solve_algo == 3 + || stack_solve_algo == 4 || stack_solve_algo == 5); + if (isnan(res1) || isinf(res1) || (res2 > 12*g0 && iter > 0)) { if (iter == 0 || fabs(slowc_save) < 1e-8) @@ -4832,10 +4580,6 @@ Interpreter::Simulate_Newton_Two_Boundaries(bool cvg, const vector_table_conditi case 0: mexPrintf("MODEL SIMULATION: (method=Sparse LU)\n"); break; - case 1: - case 6: - mexPrintf("MODEL SIMULATION: (method=LBJ)\n"); - break; case 2: mexPrintf(preconditioner_print_out("MODEL SIMULATION: (method=GMRES)\n", preconditioner, false).c_str()); break; @@ -4890,11 +4634,6 @@ Interpreter::Simulate_Newton_Two_Boundaries(bool cvg, const vector_table_conditi Solve_LU_UMFPack_Two_Boundaries(Ap, Ai, Ax, b, vector_table_conditional_local); mxDestroyArray(x0_m); } - else if (stack_solve_algo == 1 || stack_solve_algo == 6) - { - Solve_Matlab_Relaxation(A_m, b_m); - mxDestroyArray(x0_m); - } else if (stack_solve_algo == 2) Solve_Matlab_GMRES(A_m, b_m, true, x0_m); else if (stack_solve_algo == 3) diff --git a/mex/sources/bytecode/Interpreter.hh b/mex/sources/bytecode/Interpreter.hh index 489e1f3ed5d98d91689ddda11b4772a57f15e0a6..ef2e4e5fc1404b80672f09b01c6c024a33528b98 100644 --- a/mex/sources/bytecode/Interpreter.hh +++ b/mex/sources/bytecode/Interpreter.hh @@ -184,7 +184,6 @@ private: pair<bool, double> golden(double ax, double bx, double cx, double tol); void Solve_ByteCode_Symbolic_Sparse_GaussianElimination(bool symbolic); bool Solve_ByteCode_Sparse_GaussianElimination(); - void Solve_Matlab_Relaxation(mxArray *A_m, mxArray *b_m); void Solve_LU_UMFPack_Two_Boundaries(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, const vector_table_conditional_local_type &vector_table_conditional_local); void Solve_LU_UMFPack_One_Boundary(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b); diff --git a/mex/sources/bytecode/bytecode.cc b/mex/sources/bytecode/bytecode.cc index 708cd1dd1f27fa056ee4a6ab8e36d2833e4724d1..d74811bac22d6e81f388f3983fb1996504a68b57 100644 --- a/mex/sources/bytecode/bytecode.cc +++ b/mex/sources/bytecode/bytecode.cc @@ -472,6 +472,9 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (stack_solve_algo == 7 && !steady_state && !print) mexErrMsgTxt("Bytecode: Can't use option stack_solve_algo=7"); + if ((stack_solve_algo == 1 || stack_solve_algo == 6) && !steady_state && !print && !evaluate) + mexErrMsgTxt("Bytecode: Can't use option stack_solve_algo=1 or 6"); + if (steady_state && !evaluate && !print && (solve_algo < 5 || solve_algo > 8)) mexErrMsgTxt("Bytecode: solve_algo must be between 5 and 8 when using the internal steady state solver"); diff --git a/preprocessor b/preprocessor index 086d65d98c60fd222e18778ba2570cdd00dd96c4..63f04636ee848b3c70905e3f78dd51ba25cfc506 160000 --- a/preprocessor +++ b/preprocessor @@ -1 +1 @@ -Subproject commit 086d65d98c60fd222e18778ba2570cdd00dd96c4 +Subproject commit 63f04636ee848b3c70905e3f78dd51ba25cfc506