From 846ed7e82912016a0406a07a38aafed0f4853994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Thu, 19 Oct 2023 13:56:10 -0400 Subject: [PATCH] Bytecode: merge class dynSparseMatrix into Interpreter These two classes were so entangled that their separation was meaningless. --- meson.build | 1 - mex/sources/bytecode/Interpreter.cc | 4146 ++++++++++++++++++++++++- mex/sources/bytecode/Interpreter.hh | 195 +- mex/sources/bytecode/SparseMatrix.cc | 4172 -------------------------- mex/sources/bytecode/SparseMatrix.hh | 221 -- 5 files changed, 4334 insertions(+), 4401 deletions(-) delete mode 100644 mex/sources/bytecode/SparseMatrix.cc delete mode 100644 mex/sources/bytecode/SparseMatrix.hh diff --git a/meson.build b/meson.build index 2b05a87741..4be9da1ebf 100644 --- a/meson.build +++ b/meson.build @@ -311,7 +311,6 @@ shared_module('block_trust_region', block_trust_region_src, kwargs : mex_kwargs, bytecode_src = [ 'mex/sources/bytecode/bytecode.cc', 'mex/sources/bytecode/Interpreter.cc', 'mex/sources/bytecode/Mem_Mngr.cc', - 'mex/sources/bytecode/SparseMatrix.cc', 'mex/sources/bytecode/Evaluate.cc', 'mex/sources/bytecode/BasicSymbolTable.cc' ] preprocessor_headers_dep = declare_dependency(include_directories : include_directories('preprocessor/src')) diff --git a/mex/sources/bytecode/Interpreter.cc b/mex/sources/bytecode/Interpreter.cc index ca221d0154..e7af63bbe7 100644 --- a/mex/sources/bytecode/Interpreter.cc +++ b/mex/sources/bytecode/Interpreter.cc @@ -22,6 +22,8 @@ #include <filesystem> #include <numeric> #include <cfenv> +#include <type_traits> +#include <chrono> #include "Interpreter.hh" @@ -33,9 +35,31 @@ Interpreter::Interpreter(Evaluate &evaluator_arg, double *params_arg, double *y_ int maxit_arg_, double solve_tolf_arg, double markowitz_c_arg, int minimal_solving_periods_arg, int stack_solve_algo_arg, int solve_algo_arg, bool global_temporary_terms_arg, bool print_arg, mxArray *GlobalTemporaryTerms_arg, - bool steady_state_arg, bool block_decomposed_arg, int col_x_arg, int col_y_arg, const BasicSymbolTable &symbol_table_arg, int verbosity_arg) -: dynSparseMatrix {evaluator_arg, y_size_arg, y_kmin_arg, y_kmax_arg, steady_state_arg, block_decomposed_arg, periods_arg, minimal_solving_periods_arg, symbol_table_arg, verbosity_arg} + bool steady_state_arg, bool block_decomposed_arg, int col_x_arg, int col_y_arg, const BasicSymbolTable &symbol_table_arg, int verbosity_arg) : + symbol_table {symbol_table_arg}, + steady_state {steady_state_arg}, + block_decomposed {block_decomposed_arg}, + evaluator {evaluator_arg}, + minimal_solving_periods {minimal_solving_periods_arg}, + y_size {y_size_arg}, + y_kmin {y_kmin_arg}, + y_kmax {y_kmax_arg}, + periods {periods_arg}, + verbosity {verbosity_arg} { + pivotva = nullptr; + mem_mngr.init_Mem(); + symbolic = true; + alt_symbolic = false; + alt_symbolic_count = 0; + res1a = 9.0e60; + tbreak_g = 0; + start_compare = 0; + restart = 0; + IM_i.clear(); + lu_inc_tol = 1e-10; + Symbolic = nullptr; + Numeric = nullptr; params = params_arg; y = y_arg; ya = ya_arg; @@ -941,3 +965,4121 @@ Interpreter::initializeTemporaryTerms(bool global_temporary_terms) test_mxMalloc(T, __LINE__, __FILE__, __func__, ntt*(periods+y_kmin+y_kmax)*sizeof(double)); } } + +int +Interpreter::NRow(int r) const +{ + return NbNZRow[r]; +} + +int +Interpreter::NCol(int c) const +{ + return NbNZCol[c]; +} + +int +Interpreter::At_Row(int r, NonZeroElem **first) const +{ + *first = FNZE_R[r]; + return NbNZRow[r]; +} + +int +Interpreter::Union_Row(int row1, int row2) const +{ + NonZeroElem *first1, *first2; + int n1 = At_Row(row1, &first1); + int n2 = At_Row(row2, &first2); + int i1 = 0, i2 = 0, nb_elem = 0; + while (i1 < n1 && i2 < n2) + { + if (first1->c_index == first2->c_index) + { + nb_elem++; + i1++; + i2++; + first1 = first1->NZE_R_N; + first2 = first2->NZE_R_N; + } + else if (first1->c_index < first2->c_index) + { + nb_elem++; + i1++; + first1 = first1->NZE_R_N; + } + else + { + nb_elem++; + i2++; + first2 = first2->NZE_R_N; + } + } + return nb_elem; +} + +int +Interpreter::At_Pos(int r, int c, NonZeroElem **first) const +{ + *first = FNZE_R[r]; + while ((*first)->c_index != c) + *first = (*first)->NZE_R_N; + return NbNZRow[r]; +} + +int +Interpreter::At_Col(int c, NonZeroElem **first) const +{ + *first = FNZE_C[c]; + return NbNZCol[c]; +} + +int +Interpreter::At_Col(int c, int lag, NonZeroElem **first) const +{ + *first = FNZE_C[c]; + int i = 0; + while ((*first)->lag_index != lag && *first) + *first = (*first)->NZE_C_N; + if (*first) + { + NonZeroElem *firsta = *first; + if (!firsta->NZE_C_N) + i++; + else + { + while (firsta->lag_index == lag && firsta->NZE_C_N) + { + firsta = firsta->NZE_C_N; + i++; + } + if (firsta->lag_index == lag) + i++; + } + } + return i; +} + +void +Interpreter::Delete(int r, int c) +{ + NonZeroElem *first = FNZE_R[r], *firsta = nullptr; + + while (first->c_index != c) + { + firsta = first; + first = first->NZE_R_N; + } + if (firsta) + firsta->NZE_R_N = first->NZE_R_N; + if (first == FNZE_R[r]) + FNZE_R[r] = first->NZE_R_N; + NbNZRow[r]--; + + first = FNZE_C[c]; + firsta = nullptr; + while (first->r_index != r) + { + firsta = first; + first = first->NZE_C_N; + } + + if (firsta) + firsta->NZE_C_N = first->NZE_C_N; + if (first == FNZE_C[c]) + FNZE_C[c] = first->NZE_C_N; + + u_liste.push_back(first->u_index); + mem_mngr.mxFree_NZE(first); + NbNZCol[c]--; +} + +void +Interpreter::Insert(int r, int c, int u_index, int lag_index) +{ + NonZeroElem *firstn, *first, *firsta, *a; + firstn = mem_mngr.mxMalloc_NZE(); + first = FNZE_R[r]; + firsta = nullptr; + while (first->c_index < c && (a = first->NZE_R_N)) + { + firsta = first; + first = a; + } + firstn->u_index = u_index; + firstn->r_index = r; + firstn->c_index = c; + firstn->lag_index = lag_index; + if (first->c_index > c) + { + if (first == FNZE_R[r]) + FNZE_R[r] = firstn; + if (firsta) + firsta->NZE_R_N = firstn; + firstn->NZE_R_N = first; + } + else + { + first->NZE_R_N = firstn; + firstn->NZE_R_N = nullptr; + } + NbNZRow[r]++; + first = FNZE_C[c]; + firsta = nullptr; + while (first->r_index < r && (a = first->NZE_C_N)) + { + firsta = first; + first = a; + } + if (first->r_index > r) + { + if (first == FNZE_C[c]) + FNZE_C[c] = firstn; + if (firsta) + firsta->NZE_C_N = firstn; + firstn->NZE_C_N = first; + } + else + { + first->NZE_C_N = firstn; + firstn->NZE_C_N = nullptr; + } + + NbNZCol[c]++; +} + +void +Interpreter::Close_SaveCode() +{ + SaveCode.close(); +} + +void +Interpreter::Read_SparseMatrix(const string &file_name, int Size, int periods, int y_kmin, int y_kmax, bool two_boundaries, int stack_solve_algo, int solve_algo) +{ + unsigned int eq, var; + int lag; + mem_mngr.fixe_file_name(file_name); + if (!SaveCode.is_open()) + { + filesystem::path binfile {file_name + "/model/bytecode/" + (block_decomposed ? "block/" : "") + + (steady_state ? "static" : "dynamic") + ".bin"}; + SaveCode.open(binfile, ios::in | ios::binary); + if (!SaveCode.is_open()) + throw FatalException{"In Read_SparseMatrix, " + binfile.string() + " cannot be opened"}; + } + IM_i.clear(); + if (two_boundaries) + { + if (stack_solve_algo == 5) + { + for (int i = 0; i < u_count_init-Size; i++) + { + int val; + SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); + SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); + SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); + SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); + IM_i[{ eq, var, lag }] = val; + } + for (int j = 0; j < Size; j++) + IM_i[{ j, Size*(periods+y_kmax), 0 }] = j; + } + else if ((stack_solve_algo >= 0 && stack_solve_algo <= 4) + || stack_solve_algo == 6) + { + for (int i = 0; i < u_count_init-Size; i++) + { + int val; + SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); + SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); + SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); + SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); + IM_i[{ var - lag*Size, -lag, eq }] = val; + } + for (int j = 0; j < Size; j++) + IM_i[{ Size*(periods+y_kmax), 0, j }] = j; + } + else + throw FatalException{"Invalid value for solve_algo or stack_solve_algo"}; + } + else + { + if ((stack_solve_algo == 5 && !steady_state) || (solve_algo == 5 && steady_state)) + { + for (int i = 0; i < u_count_init; i++) + { + int val; + SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); + SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); + SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); + SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); + IM_i[{ eq, var, lag }] = val; + } + } + else if ((((stack_solve_algo >= 0 && stack_solve_algo <= 4) + || stack_solve_algo == 6) && !steady_state) + || ((solve_algo >= 6 || solve_algo <= 8) && steady_state)) + { + for (int i = 0; i < u_count_init; i++) + { + int val; + SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); + SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); + SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); + SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); + IM_i[{ var - lag*Size, -lag, eq }] = val; + } + } + else + throw FatalException{"Invalid value for solve_algo or stack_solve_algo"}; + } + index_vara = static_cast<int *>(mxMalloc(Size*(periods+y_kmin+y_kmax)*sizeof(int))); + test_mxMalloc(index_vara, __LINE__, __FILE__, __func__, Size*(periods+y_kmin+y_kmax)*sizeof(int)); + for (int j = 0; j < Size; j++) + SaveCode.read(reinterpret_cast<char *>(&index_vara[j]), sizeof(*index_vara)); + if (periods+y_kmin+y_kmax > 1) + for (int i = 1; i < periods+y_kmin+y_kmax; i++) + for (int j = 0; j < Size; j++) + index_vara[j+Size*i] = index_vara[j+Size*(i-1)] + y_size; + index_equa = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(index_equa, __LINE__, __FILE__, __func__, Size*sizeof(int)); + for (int j = 0; j < Size; j++) + SaveCode.read(reinterpret_cast<char *>(&index_equa[j]), sizeof(*index_equa)); +} + +void +Interpreter::Simple_Init(int Size, const map<tuple<int, int, int>, int> &IM, bool &zero_solution) +{ + pivot = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivot, __LINE__, __FILE__, __func__, Size*sizeof(int)); + pivot_save = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivot_save, __LINE__, __FILE__, __func__, Size*sizeof(int)); + pivotk = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivotk, __LINE__, __FILE__, __func__, Size*sizeof(int)); + pivotv = static_cast<double *>(mxMalloc(Size*sizeof(double))); + test_mxMalloc(pivotv, __LINE__, __FILE__, __func__, Size*sizeof(double)); + pivotva = static_cast<double *>(mxMalloc(Size*sizeof(double))); + test_mxMalloc(pivotva, __LINE__, __FILE__, __func__, Size*sizeof(double)); + b = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(b, __LINE__, __FILE__, __func__, Size*sizeof(int)); + line_done = static_cast<bool *>(mxMalloc(Size*sizeof(bool))); + test_mxMalloc(line_done, __LINE__, __FILE__, __func__, Size*sizeof(bool)); + + mem_mngr.init_CHUNK_BLCK_SIZE(u_count); + int i = Size*sizeof(NonZeroElem *); + FNZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(FNZE_R, __LINE__, __FILE__, __func__, i); + FNZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(FNZE_C, __LINE__, __FILE__, __func__, i); + auto **temp_NZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(temp_NZE_R, __LINE__, __FILE__, __func__, i); + auto **temp_NZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(temp_NZE_C, __LINE__, __FILE__, __func__, i); + i = Size*sizeof(int); + NbNZRow = static_cast<int *>(mxMalloc(i)); + test_mxMalloc(NbNZRow, __LINE__, __FILE__, __func__, i); + NbNZCol = static_cast<int *>(mxMalloc(i)); + test_mxMalloc(NbNZCol, __LINE__, __FILE__, __func__, i); + for (i = 0; i < Size; i++) + { + line_done[i] = false; + FNZE_C[i] = nullptr; + FNZE_R[i] = nullptr; + temp_NZE_C[i] = nullptr; + temp_NZE_R[i] = nullptr; + NbNZRow[i] = 0; + NbNZCol[i] = 0; + } + int u_count1 = Size; + for (auto &[key, value] : IM) + { + auto &[eq, var, lag] = key; + if (lag == 0) /*Build the index for sparse matrix containing the jacobian : u*/ + { + NbNZRow[eq]++; + NbNZCol[var]++; + NonZeroElem *first = mem_mngr.mxMalloc_NZE(); + first->NZE_C_N = nullptr; + first->NZE_R_N = nullptr; + first->u_index = u_count1; + first->r_index = eq; + first->c_index = var; + first->lag_index = lag; + if (!FNZE_R[eq]) + FNZE_R[eq] = first; + if (!FNZE_C[var]) + FNZE_C[var] = first; + if (temp_NZE_R[eq]) + temp_NZE_R[eq]->NZE_R_N = first; + if (temp_NZE_C[var]) + temp_NZE_C[var]->NZE_C_N = first; + temp_NZE_R[eq] = first; + temp_NZE_C[var] = first; + u_count1++; + } + } + double cum_abs_sum = 0; + for (int i = 0; i < Size; i++) + { + b[i] = i; + cum_abs_sum += fabs(u[i]); + } + if (cum_abs_sum < 1e-20) + zero_solution = true; + else + zero_solution = false; + + mxFree(temp_NZE_R); + mxFree(temp_NZE_C); + u_count = u_count1; +} + +void +Interpreter::Init_Matlab_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, const mxArray *A_m, const mxArray *b_m, bool &zero_solution, const mxArray *x0_m) const +{ + double *b = mxGetPr(b_m); + if (!b) + throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve b vector"}; + double *x0 = mxGetPr(x0_m); + if (!x0) + throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve x0 vector"}; + mwIndex *Ai = mxGetIr(A_m); + if (!Ai) + throw FatalException{"In Init_Matlab_Sparse_Simple, can't allocate Ai index vector"}; + mwIndex *Aj = mxGetJc(A_m); + if (!Aj) + throw FatalException{"In Init_Matlab_Sparse_Simple, can't allocate Aj index vector"}; + double *A = mxGetPr(A_m); + if (!A) + throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve A matrix"}; + + for (int i = 0; i < y_size*(periods+y_kmin); i++) + ya[i] = y[i]; +#ifdef DEBUG + unsigned int max_nze = mxGetNzmax(A_m); +#endif + unsigned int NZE = 0; + int last_var = 0; + double cum_abs_sum = 0; + for (int i = 0; i < Size; i++) + { + b[i] = u[i]; + cum_abs_sum += fabs(b[i]); + x0[i] = y[i]; + } + if (cum_abs_sum < 1e-20) + zero_solution = true; + else + zero_solution = false; + + Aj[0] = 0; + last_var = 0; + for (auto &[key, index] : IM) + { + auto &[var, ignore, eq] = key; + if (var != last_var) + { + Aj[1+last_var] = NZE; + last_var = var; + } +#ifdef DEBUG + if (index < 0 || index >= u_count_alloc || index > Size + Size*Size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(index) + + ") out of range for u vector max = " + + to_string(Size+Size*Size) + + " allocated = " + to_string(u_count_alloc)}; + if (NZE >= max_nze) + throw FatalException{"In Init_Matlab_Sparse_Simple, exceeds the capacity of A_m sparse matrix"}; +#endif + A[NZE] = u[index]; + Ai[NZE] = eq; + NZE++; +#ifdef DEBUG + if (eq < 0 || eq >= Size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(eq) + + ") out of range for b vector"}; + if (var < 0 || var >= Size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(var) + + ") out of range for index_vara vector"}; + if (index_vara[var] < 0 || index_vara[var] >= y_size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + + to_string(index_vara[var]) + + ") out of range for y vector max=" + to_string(y_size) + +" (0)"}; +#endif + } + Aj[Size] = NZE; +} + +void +Interpreter::Init_UMFPACK_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, bool &zero_solution, const mxArray *x0_m) const +{ + *b = static_cast<double *>(mxMalloc(Size * sizeof(double))); + test_mxMalloc(*b, __LINE__, __FILE__, __func__, Size * sizeof(double)); + if (!(*b)) + throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve b vector"}; + double *x0 = mxGetPr(x0_m); + if (!x0) + throw FatalException{"In Init_UMFPACK_Sparse_Simple, can't retrieve x0 vector"}; + *Ap = static_cast<SuiteSparse_long *>(mxMalloc((Size+1) * sizeof(SuiteSparse_long))); + test_mxMalloc(*Ap, __LINE__, __FILE__, __func__, (Size+1) * sizeof(SuiteSparse_long)); + if (!(*Ap)) + throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ap index vector"}; + size_t prior_nz = IM.size(); + *Ai = static_cast<SuiteSparse_long *>(mxMalloc(prior_nz * sizeof(SuiteSparse_long))); + test_mxMalloc(*Ai, __LINE__, __FILE__, __func__, prior_nz * sizeof(SuiteSparse_long)); + if (!(*Ai)) + throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ai index vector"}; + *Ax = static_cast<double *>(mxMalloc(prior_nz * sizeof(double))); + test_mxMalloc(*Ax, __LINE__, __FILE__, __func__, prior_nz * sizeof(double)); + if (!(*Ax)) + throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve Ax matrix"}; + for (int i = 0; i < Size; i++) + { + int eq = index_vara[i]; + ya[eq+it_*y_size] = y[eq+it_*y_size]; + } +#ifdef DEBUG + unsigned int max_nze = prior_nz; //mxGetNzmax(A_m); +#endif + unsigned int NZE = 0; + int last_var = 0; + double cum_abs_sum = 0; + for (int i = 0; i < Size; i++) + { + (*b)[i] = u[i]; + cum_abs_sum += fabs((*b)[i]); + x0[i] = y[i]; + } + if (cum_abs_sum < 1e-20) + zero_solution = true; + else + zero_solution = false; + + (*Ap)[0] = 0; + last_var = 0; + for (auto &[key, index] : IM) + { + auto &[var, ignore, eq] = key; + if (var != last_var) + { + (*Ap)[1+last_var] = NZE; + last_var = var; + } +#ifdef DEBUG + if (index < 0 || index >= u_count_alloc || index > Size + Size*Size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(index) + + ") out of range for u vector max = " + + to_string(Size+Size*Size) + + " allocated = " + to_string(u_count_alloc)}; + if (NZE >= max_nze) + throw FatalException{"In Init_Matlab_Sparse_Simple, exceeds the capacity of A_m sparse matrix"}; +#endif + (*Ax)[NZE] = u[index]; + (*Ai)[NZE] = eq; + NZE++; +#ifdef DEBUG + if (eq < 0 || eq >= Size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(eq) + + ") out of range for b vector"}; + if (var < 0 || var >= Size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(var) + + ") out of range for index_vara vector"}; + if (index_vara[var] < 0 || index_vara[var] >= y_size) + throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + + to_string(index_vara[var]) + + ") out of range for y vector max=" + to_string(y_size) + + " (0)"}; +#endif + } + (*Ap)[Size] = NZE; +} + +int +Interpreter::find_exo_num(const vector<s_plan> &sconstrained_extended_path, int value) +{ + auto it = find_if(sconstrained_extended_path.begin(), sconstrained_extended_path.end(), + [=](auto v) { return v.exo_num == value; }); + if (it != sconstrained_extended_path.end()) + return it - sconstrained_extended_path.begin(); + else + return -1; +} + +int +Interpreter::find_int_date(const vector<pair<int, double>> &per_value, int value) +{ + auto it = find_if(per_value.begin(), per_value.end(), [=](auto v) { return v.first == value; }); + if (it != per_value.end()) + return it - per_value.begin(); + else + return -1; +} + +void +Interpreter::Init_UMFPACK_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, const mxArray *x0_m, const vector_table_conditional_local_type &vector_table_conditional_local, int block_num) const +{ + int n = periods * Size; + *b = static_cast<double *>(mxMalloc(n * sizeof(double))); + if (!(*b)) + throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve b vector"}; + double *x0 = mxGetPr(x0_m); + if (!x0) + throw FatalException{"In Init_UMFPACK_Sparse_Simple, can't retrieve x0 vector"}; + *Ap = static_cast<SuiteSparse_long *>(mxMalloc((n+1) * sizeof(SuiteSparse_long))); + test_mxMalloc(*Ap, __LINE__, __FILE__, __func__, (n+1) * sizeof(SuiteSparse_long)); + if (!(*Ap)) + throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ap index vector"}; + size_t prior_nz = IM.size() * periods; + *Ai = static_cast<SuiteSparse_long *>(mxMalloc(prior_nz * sizeof(SuiteSparse_long))); + test_mxMalloc(*Ai, __LINE__, __FILE__, __func__, prior_nz * sizeof(SuiteSparse_long)); + if (!(*Ai)) + throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ai index vector"}; + *Ax = static_cast<double *>(mxMalloc(prior_nz * sizeof(double))); + test_mxMalloc(*Ax, __LINE__, __FILE__, __func__, prior_nz * sizeof(double)); + if (!(*Ax)) + throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve Ax matrix"}; + for (int i = 0; i < y_size*(periods+y_kmin); i++) + ya[i] = y[i]; + unsigned int NZE = 0; + int last_var = 0; + for (int i = 0; i < periods*Size; i++) + { + (*b)[i] = 0; + x0[i] = y[index_vara[Size*y_kmin+i]]; + } + double *jacob_exo; + int row_x = 0; +#ifdef DEBUG + int col_x; +#endif + if (vector_table_conditional_local.size()) + { + jacob_exo = mxGetPr(jacobian_exo_block[block_num]); + row_x = mxGetM(jacobian_exo_block[block_num]); +#ifdef DEBUG + col_x = mxGetN(jacobian_exo_block[block_num]); +#endif + } + else + jacob_exo = nullptr; +#ifdef DEBUG + int local_index; +#endif + + bool fliped = false; + bool fliped_exogenous_derivatives_updated = false; + int flip_exo; + (*Ap)[0] = 0; + for (int t = 0; t < periods; t++) + { + last_var = -1; + int var = 0; + for (auto &[key, value] : IM) + { + var = get<0>(key); + int eq = get<2>(key)+Size*t; + int lag = -get<1>(key); + int index = value + (t-lag) * u_count_init; + if (var != last_var) + { + (*Ap)[1+last_var + t * Size] = NZE; + last_var = var; + if (var < Size*(periods+y_kmax)) + { + if (t == 0 && vector_table_conditional_local.size()) + { + fliped = vector_table_conditional_local[var].is_cond; + fliped_exogenous_derivatives_updated = false; + } + else + fliped = false; + } + else + fliped = false; + } + if (fliped) + { + if (t == 0 && var < (periods+y_kmax)*Size + && lag == 0 && vector_table_conditional_local.size()) + { + flip_exo = vector_table_conditional_local[var].var_exo; +#ifdef DEBUG + local_index = eq; +#endif + if (!fliped_exogenous_derivatives_updated) + { + fliped_exogenous_derivatives_updated = true; + for (int k = 0; k < row_x; k++) + { + if (jacob_exo[k + row_x*flip_exo] != 0) + { + (*Ax)[NZE] = jacob_exo[k + row_x*flip_exo]; + (*Ai)[NZE] = k; + NZE++; + +#ifdef DEBUG + if (local_index < 0 || local_index >= Size * periods) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(local_index) + + ") out of range for b vector"}; + if (k + row_x*flip_exo < 0 || k + row_x*flip_exo >= row_x * col_x) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(var+Size*(y_kmin+t+lag)) + + ") out of range for jacob_exo vector"}; + if (t+y_kmin+flip_exo*nb_row_x < 0 + || t+y_kmin+flip_exo*nb_row_x >= nb_row_x * this->col_x) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(index_vara[var+Size*(y_kmin+t+lag)]) + + ") out of range for x vector max=" + + to_string(nb_row_x * this->col_x)}; +#endif + u[k] -= jacob_exo[k + row_x*flip_exo] * x[t+y_kmin+flip_exo*nb_row_x]; + } + } + } + } + } + + if (var < (periods+y_kmax)*Size) + { + int ti_y_kmin = -min(t, y_kmin); + int ti_y_kmax = min(periods-(t+1), y_kmax); + int ti_new_y_kmax = min(t, y_kmax); + int ti_new_y_kmin = -min(periods-(t+1), y_kmin); + if (lag <= ti_new_y_kmax && lag >= ti_new_y_kmin) /*Build the index for sparse matrix containing the jacobian : u*/ + { +#ifdef DEBUG + if (NZE >= prior_nz) + throw FatalException{"In Init_UMFPACK_Sparse, exceeds the capacity of allocated sparse matrix"}; +#endif + if (!fliped) + { + (*Ax)[NZE] = u[index]; + (*Ai)[NZE] = eq - lag * Size; + NZE++; + } + else /*if (fliped)*/ + { +#ifdef DEBUG + if (eq - lag * Size < 0 || eq - lag * Size >= Size * periods) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(eq - lag * Size) + + ") out of range for b vector"}; + if (var+Size*(y_kmin+t) < 0 + || var+Size*(y_kmin+t) >= Size*(periods+y_kmin+y_kmax)) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(var+Size*(y_kmin+t)) + + ") out of range for index_vara vector"}; + if (index_vara[var+Size*(y_kmin+t)] < 0 + || index_vara[var+Size*(y_kmin+t)] >= y_size*(periods+y_kmin+y_kmax)) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(index_vara[var+Size*(y_kmin+t)]) + + ") out of range for y vector max=" + + to_string(y_size*(periods+y_kmin+y_kmax))}; +#endif + (*b)[eq - lag * Size] += u[index] * y[index_vara[var+Size*(y_kmin+t)]]; + } + + } + if (lag > ti_y_kmax || lag < ti_y_kmin) + { +#ifdef DEBUG + if (eq < 0 || eq >= Size * periods) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(eq) + + ") out of range for b vector"}; + if (var+Size*(y_kmin+t+lag) < 0 + || var+Size*(y_kmin+t+lag) >= Size*(periods+y_kmin+y_kmax)) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(var+Size*(y_kmin+t+lag)) + + ") out of range for index_vara vector"}; + if (index_vara[var+Size*(y_kmin+t+lag)] < 0 + || index_vara[var+Size*(y_kmin+t+lag)] >= y_size*(periods+y_kmin+y_kmax)) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + + to_string(index_vara[var+Size*(y_kmin+t+lag)]) + + ") out of range for y vector max=" + + to_string(y_size*(periods+y_kmin+y_kmax))}; +#endif + (*b)[eq] += u[index+lag*u_count_init]*y[index_vara[var+Size*(y_kmin+t+lag)]]; + } + } + else /* ...and store it in the u vector*/ + { +#ifdef DEBUG + if (index < 0 || index >= u_count_alloc) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + to_string(index) + + ") out of range for u vector"}; + if (eq < 0 || eq >= (Size*periods)) + throw FatalException{"In Init_UMFPACK_Sparse, index (" + to_string(eq) + + ") out of range for b vector"}; +#endif + (*b)[eq] += u[index]; + } + } + } + (*Ap)[Size*periods] = NZE; +#ifdef DEBUG + mexPrintf("*Ax = ["); + for (int i = 0; i < static_cast<int>(NZE); i++) + mexPrintf("%f ", (*Ax)[i]); + mexPrintf("]\n"); + + mexPrintf("*Ap = ["); + for (int i = 0; i < n+1; i++) + mexPrintf("%d ", (*Ap)[i]); + mexPrintf("]\n"); + + mexPrintf("*Ai = ["); + for (int i = 0; i < static_cast<int>(NZE); i++) + mexPrintf("%d ", (*Ai)[i]); + mexPrintf("]\n"); +#endif +} + +void +Interpreter::PrintM(int n, const double *Ax, const mwIndex *Ap, const mwIndex *Ai) +{ + int nnz = Ap[n]; + auto *A = static_cast<double *>(mxMalloc(n * n * sizeof(double))); + test_mxMalloc(A, __LINE__, __FILE__, __func__, n * n * sizeof(double)); + fill_n(A, n * n, 0); + int k = 0; + for (int i = 0; i < n; i++) + for (int j = Ap[i]; j < static_cast<int>(Ap[i + 1]); j++) + { + int row = Ai[j]; + A[row * n + i] = Ax[j]; + k++; + } + if (nnz != k) + mexPrintf("Problem nnz(%d) != number of elements(%d)\n", nnz, k); + mexPrintf("----------------------\n"); + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + mexPrintf("%-6.3f ", A[i * n + j]); + mexPrintf("\n"); + } + mxFree(A); +} + +void +Interpreter::Init_Matlab_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, mxArray *A_m, mxArray *b_m, const mxArray *x0_m) const +{ + double *b = mxGetPr(b_m); + + if (!b) + throw FatalException{"In Init_Matlab_Sparse, can't retrieve b vector"}; + double *x0 = mxGetPr(x0_m); + if (!x0) + throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve x0 vector"}; + mwIndex *Aj = mxGetJc(A_m); + if (!Aj) + throw FatalException{"In Init_Matlab_Sparse, can't allocate Aj index vector"}; + mwIndex *Ai = mxGetIr(A_m); + if (!Ai) + throw FatalException{"In Init_Matlab_Sparse, can't allocate Ai index vector"}; + double *A = mxGetPr(A_m); + if (!A) + throw FatalException{"In Init_Matlab_Sparse, can't retrieve A matrix"}; + + for (int i = 0; i < y_size*(periods+y_kmin); i++) + ya[i] = y[i]; + unsigned int NZE = 0; + int last_var = 0; + for (int i = 0; i < periods*Size; i++) + { + b[i] = 0; + x0[i] = y[index_vara[Size*y_kmin+i]]; + } + Aj[0] = 0; + for (int t = 0; t < periods; t++) + { + last_var = 0; + for (auto &[key, value] : IM) + { + int var = get<0>(key); + if (var != last_var) + { + Aj[1+last_var + t * Size] = NZE; + last_var = var; + } + int eq = get<2>(key)+Size*t; + int lag = -get<1>(key); + int index = value + (t-lag)*u_count_init; + if (var < (periods+y_kmax)*Size) + { + int ti_y_kmin = -min(t, y_kmin); + int ti_y_kmax = min(periods-(t +1), y_kmax); + int ti_new_y_kmax = min(t, y_kmax); + int ti_new_y_kmin = -min(periods-(t+1), y_kmin); + if (lag <= ti_new_y_kmax && lag >= ti_new_y_kmin) /*Build the index for sparse matrix containing the jacobian : u*/ + { +#ifdef DEBUG + if (index < 0 || index >= u_count_alloc || index > Size + Size*Size) + throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(index) + + ") out of range for u vector max = " + + to_string(Size+Size*Size) + " allocated = " + + to_string(u_count_alloc)}; + if (NZE >= prior_nz) + throw FatalException{"In Init_Matlab_Sparse, exceeds the capacity of allocated sparse matrix"}; +#endif + A[NZE] = u[index]; + Ai[NZE] = eq - lag * Size; + NZE++; + } + if (lag > ti_y_kmax || lag < ti_y_kmin) + { +#ifdef DEBUG + if (eq < 0 || eq >= Size * periods) + throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(eq) + + ") out of range for b vector"}; + if (var+Size*(y_kmin+t+lag) < 0 + || var+Size*(y_kmin+t+lag) >= Size*(periods+y_kmin+y_kmax)) + throw FatalException{"In Init_Matlab_Sparse, index (" + + to_string(var+Size*(y_kmin+t+lag)) + + ") out of range for index_vara vector"}; + if (index_vara[var+Size*(y_kmin+t+lag)] < 0 + || index_vara[var+Size*(y_kmin+t+lag)] >= y_size*(periods+y_kmin+y_kmax)) + throw FatalException{"In Init_Matlab_Sparse, index (" + + to_string(index_vara[var+Size*(y_kmin+t+lag)]) + + ") out of range for y vector max=" + + to_string(y_size*(periods+y_kmin+y_kmax))}; +#endif + b[eq] += u[index+lag*u_count_init]*y[index_vara[var+Size*(y_kmin+t+lag)]]; + } + } + else /* ...and store it in the u vector*/ + { +#ifdef DEBUG + if (index < 0 || index >= u_count_alloc) + throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(index) + + ") out of range for u vector"}; + if (eq < 0 || eq >= (Size*periods)) + throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(eq) + + ") out of range for b vector"}; +#endif + b[eq] += u[index]; + } + } + } + Aj[Size*periods] = NZE; +} + +void +Interpreter::Init_GE(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM) +{ + double tmp_b = 0.0; + pivot = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); + test_mxMalloc(pivot, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); + pivot_save = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); + test_mxMalloc(pivot_save, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); + pivotk = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); + test_mxMalloc(pivotk, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); + pivotv = static_cast<double *>(mxMalloc(Size*periods*sizeof(double))); + test_mxMalloc(pivotv, __LINE__, __FILE__, __func__, Size*periods*sizeof(double)); + pivotva = static_cast<double *>(mxMalloc(Size*periods*sizeof(double))); + test_mxMalloc(pivotva, __LINE__, __FILE__, __func__, Size*periods*sizeof(double)); + b = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); + test_mxMalloc(b, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); + line_done = static_cast<bool *>(mxMalloc(Size*periods*sizeof(bool))); + test_mxMalloc(line_done, __LINE__, __FILE__, __func__, Size*periods*sizeof(bool)); + mem_mngr.init_CHUNK_BLCK_SIZE(u_count); + int i = (periods+y_kmax+1)*Size*sizeof(NonZeroElem *); + FNZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(FNZE_R, __LINE__, __FILE__, __func__, i); + FNZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(FNZE_C, __LINE__, __FILE__, __func__, i); + auto **temp_NZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(temp_NZE_R, __LINE__, __FILE__, __func__, i); + auto **temp_NZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); + test_mxMalloc(temp_NZE_C, __LINE__, __FILE__, __func__, i); + i = (periods+y_kmax+1)*Size*sizeof(int); + NbNZRow = static_cast<int *>(mxMalloc(i)); + test_mxMalloc(NbNZRow, __LINE__, __FILE__, __func__, i); + NbNZCol = static_cast<int *>(mxMalloc(i)); + test_mxMalloc(NbNZCol, __LINE__, __FILE__, __func__, i); + + for (int i = 0; i < periods*Size; i++) + { + b[i] = 0; + line_done[i] = false; + } + for (int i = 0; i < (periods+y_kmax+1)*Size; i++) + { + FNZE_C[i] = nullptr; + FNZE_R[i] = nullptr; + temp_NZE_C[i] = nullptr; + temp_NZE_R[i] = nullptr; + NbNZRow[i] = 0; + NbNZCol[i] = 0; + } + int nnz = 0; + //pragma omp parallel for ordered private(it4, ti_y_kmin, ti_y_kmax, eq, var, lag) schedule(dynamic) + for (int t = 0; t < periods; t++) + { + int ti_y_kmin = -min(t, y_kmin); + int ti_y_kmax = min(periods-(t+1), y_kmax); + int eq = -1; + //pragma omp ordered + for (auto &[key, value] : IM) + { + int var = get<1>(key); + if (eq != get<0>(key)+Size*t) + tmp_b = 0; + eq = get<0>(key)+Size*t; + int lag = get<2>(key); + if (var < (periods+y_kmax)*Size) + { + lag = get<2>(key); + if (lag <= ti_y_kmax && lag >= ti_y_kmin) /*Build the index for sparse matrix containing the jacobian : u*/ + { + nnz++; + var += Size*t; + NbNZRow[eq]++; + NbNZCol[var]++; + NonZeroElem *first = mem_mngr.mxMalloc_NZE(); + first->NZE_C_N = nullptr; + first->NZE_R_N = nullptr; + first->u_index = value+u_count_init*t; + first->r_index = eq; + first->c_index = var; + first->lag_index = lag; + if (FNZE_R[eq] == nullptr) + FNZE_R[eq] = first; + if (FNZE_C[var] == nullptr) + FNZE_C[var] = first; + if (temp_NZE_R[eq] != nullptr) + temp_NZE_R[eq]->NZE_R_N = first; + if (temp_NZE_C[var] != nullptr) + temp_NZE_C[var]->NZE_C_N = first; + temp_NZE_R[eq] = first; + temp_NZE_C[var] = first; + } + else /*Build the additive terms ooutside the simulation periods related to the first lags and the last leads...*/ + { + if (lag < ti_y_kmin) + tmp_b += u[value+u_count_init*t]*y[index_vara[var+Size*(y_kmin+t)]]; + else + tmp_b += u[value+u_count_init*t]*y[index_vara[var+Size*(y_kmin+t)]]; + } + } + else /* ...and store it in the u vector*/ + { + b[eq] = value+u_count_init*t; + u[b[eq]] += tmp_b; + tmp_b = 0; + } + } + } + mxFree(temp_NZE_R); + mxFree(temp_NZE_C); +} + +int +Interpreter::Get_u() +{ + if (!u_liste.empty()) + { + int i = u_liste.back(); + u_liste.pop_back(); + return i; + } + else + { + if (u_count < u_count_alloc) + { + int i = u_count; + u_count++; + return i; + } + else + { + u_count_alloc += 5*u_count_alloc_save; + u = static_cast<double *>(mxRealloc(u, u_count_alloc*sizeof(double))); + if (!u) + throw FatalException{"In Get_u, memory exhausted (realloc(" + + to_string(u_count_alloc*sizeof(double)) + "))"}; + int i = u_count; + u_count++; + return i; + } + } +} + +void +Interpreter::Delete_u(int pos) +{ + u_liste.push_back(pos); +} + +void +Interpreter::Clear_u() +{ + u_liste.clear(); +} + +void +Interpreter::End_GE() +{ + mem_mngr.Free_All(); + mxFree(FNZE_R); + mxFree(FNZE_C); + mxFree(NbNZRow); + mxFree(NbNZCol); + mxFree(b); + mxFree(line_done); + mxFree(pivot); + mxFree(pivot_save); + mxFree(pivotk); + mxFree(pivotv); + mxFree(pivotva); +} + +bool +Interpreter::compare(int *save_op, int *save_opa, int *save_opaa, int beg_t, int periods, long nop4, int Size) +{ + long nop = nop4/2; + double r = 0.0; + bool OK = true; + int *diff1 = static_cast<int *>(mxMalloc(nop*sizeof(int))); + test_mxMalloc(diff1, __LINE__, __FILE__, __func__, nop*sizeof(int)); + int *diff2 = static_cast<int *>(mxMalloc(nop*sizeof(int))); + test_mxMalloc(diff2, __LINE__, __FILE__, __func__, nop*sizeof(int)); + int max_save_ops_first = -1; + long j = 0, i = 0; + while (i < nop4 && OK) + { + t_save_op_s *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[i]); + t_save_op_s *save_opa_s = reinterpret_cast<t_save_op_s *>(&save_opa[i]); + t_save_op_s *save_opaa_s = reinterpret_cast<t_save_op_s *>(&save_opaa[i]); + diff1[j] = save_op_s->first-save_opa_s->first; + max_save_ops_first = max(max_save_ops_first, save_op_s->first+diff1[j]*(periods-beg_t)); + switch (save_op_s->operat) + { + case IFLD: + case IFDIV: + OK = (save_op_s->operat == save_opa_s->operat && save_opa_s->operat == save_opaa_s->operat + && diff1[j] == (save_opa_s->first-save_opaa_s->first)); + i += 2; + break; + case IFLESS: + case IFSUB: + diff2[j] = save_op_s->second-save_opa_s->second; + OK = (save_op_s->operat == save_opa_s->operat && save_opa_s->operat == save_opaa_s->operat + && diff1[j] == (save_opa_s->first-save_opaa_s->first) + && diff2[j] == (save_opa_s->second-save_opaa_s->second)); + i += 3; + break; + default: + throw FatalException{"In compare, unknown operator = " + + to_string(save_op_s->operat)}; + } + j++; + } + // the same pivot for all remaining periods + if (OK) + { + for (int i = beg_t; i < periods; i++) + for (int j = 0; j < Size; j++) + pivot[i*Size+j] = pivot[(i-1)*Size+j]+Size; + if (max_save_ops_first >= u_count_alloc) + { + u_count_alloc += max_save_ops_first; + u = static_cast<double *>(mxRealloc(u, u_count_alloc*sizeof(double))); + if (!u) + throw FatalException{"In compare, memory exhausted (realloc(" + + to_string(u_count_alloc*sizeof(double)) + "))"}; + } + for (int t = 1; t < periods-beg_t-y_kmax; t++) + { + int i = j = 0; + while (i < nop4) + { + auto *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[i]); + double *up = &u[save_op_s->first+t*diff1[j]]; + switch (save_op_s->operat) + { + case IFLD: + r = *up; + i += 2; + break; + case IFDIV: + *up /= r; + i += 2; + break; + case IFSUB: + *up -= u[save_op_s->second+t*diff2[j]]*r;; + i += 3; + break; + case IFLESS: + *up = -u[save_op_s->second+t*diff2[j]]*r; + i += 3; + break; + } + j++; + } + } + int t1 = max(1, periods-beg_t-y_kmax); + int periods_beg_t = periods-beg_t; + for (int t = t1; t < periods_beg_t; t++) + { + int i = j = 0; + int gap = periods_beg_t-t; + while (i < nop4) + { + if (auto *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[i]); + save_op_s->lag < gap) + { + double *up = &u[save_op_s->first+t*diff1[j]]; + switch (save_op_s->operat) + { + case IFLD: + r = *up; + i += 2; + break; + case IFDIV: + *up /= r; + i += 2; + break; + case IFSUB: + *up -= u[save_op_s->second+t*diff2[j]]*r; + i += 3; + break; + case IFLESS: + *up = -u[save_op_s->second+t*diff2[j]]*r; + i += 3; + break; + } + } + else + switch (save_op_s->operat) + { + case IFLD: + case IFDIV: + i += 2; + break; + case IFSUB: + case IFLESS: + i += 3; + break; + } + j++; + } + } + } + mxFree(diff1); + mxFree(diff2); + return OK; +} + +int +Interpreter::complete(int beg_t, int Size, int periods, int *b) +{ + double yy = 0.0; + + int size_of_save_code = (1+y_kmax)*Size*(Size+1+4)/2*4; + int *save_code = static_cast<int *>(mxMalloc(size_of_save_code*sizeof(int))); + test_mxMalloc(save_code, __LINE__, __FILE__, __func__, size_of_save_code*sizeof(int)); + int size_of_diff = (1+y_kmax)*Size*(Size+1+4); + int *diff = static_cast<int *>(mxMalloc(size_of_diff*sizeof(int))); + test_mxMalloc(diff, __LINE__, __FILE__, __func__, size_of_diff*sizeof(int)); + long cal_y = y_size*y_kmin; + + long i = (beg_t+1)*Size-1; + long nop = 0; + for (long j = i; j > i-Size; j--) + { + long pos = pivot[j]; + NonZeroElem *first; + long nb_var = At_Row(pos, &first); + first = first->NZE_R_N; + nb_var--; + save_code[nop] = IFLDZ; + save_code[nop+1] = 0; + save_code[nop+2] = 0; + save_code[nop+3] = 0; +#ifdef DEBUG + if ((nop+3) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); +#endif + nop += 4; + for (long k = 0; k < nb_var; k++) + { + save_code[nop] = IFMUL; + save_code[nop+1] = index_vara[first->c_index]+cal_y; + save_code[nop+2] = first->u_index; + save_code[nop+3] = first->lag_index; +#ifdef DEBUG + if ((nop+3) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); +#endif + nop += 4; + first = first->NZE_R_N; + } + save_code[nop] = IFADD; + save_code[nop+1] = b[pos]; + save_code[nop+2] = 0; + save_code[nop+3] = 0; +#ifdef DEBUG + if ((nop+3) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); +#endif + nop += 4; + save_code[nop] = IFSTP; + save_code[nop+1] = index_vara[j]+y_size*y_kmin; + save_code[nop+2] = 0; + save_code[nop+3] = 0; +#ifdef DEBUG + if ((nop+2) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); +#endif + nop += 4; + } + i = beg_t*Size-1; + long nop1 = 0, nopa = 0; + for (long j = i; j > i-Size; j--) + { + long pos = pivot[j]; + NonZeroElem *first; + long nb_var = At_Row(pos, &first); + first = first->NZE_R_N; + nb_var--; + diff[nopa] = 0; + diff[nopa+1] = 0; + nopa += 2; + nop1 += 4; + for (long k = 0; k < nb_var; k++) + { + diff[nopa] = save_code[nop1+1]-(index_vara[first->c_index]+cal_y); + diff[nopa+1] = save_code[nop1+2]-(first->u_index); +#ifdef DEBUG + if ((nop1+2) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop1+2, size_of_save_code); + if ((nopa+1) >= size_of_diff) + mexPrintf("out of diff[%d] (bound=%d)\n", nopa+2, size_of_diff); +#endif + nopa += 2; + nop1 += 4; + first = first->NZE_R_N; + } + diff[nopa] = save_code[nop1+1]-(b[pos]); + diff[nopa+1] = 0; +#ifdef DEBUG + if ((nop1+3) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop1+2, size_of_save_code); + if ((nopa+1) >= size_of_diff) + mexPrintf("out of diff[%d] (bound=%d)\n", nopa+2, size_of_diff); +#endif + nopa += 2; + nop1 += 4; + diff[nopa] = save_code[nop1+1]-(index_vara[j]+y_size*y_kmin); + diff[nopa+1] = 0; +#ifdef DEBUG + if ((nop1+4) >= size_of_save_code) + mexPrintf("out of save_code[%d] (bound=%d)\n", nop1+2, size_of_save_code); + if ((nopa+1) >= size_of_diff) + mexPrintf("out of diff[%d] (bound=%d)\n", nopa+2, size_of_diff); +#endif + nopa += 2; + nop1 += 4; + } + long max_var = (periods+y_kmin)*y_size; + long min_var = y_kmin*y_size; + for (int t = periods+y_kmin-1; t >= beg_t+y_kmin; t--) + { + int j = 0, k; + int ti = t-y_kmin-beg_t; + for (int i = 0; i < nop; i += 4) + { + switch (save_code[i]) + { + case IFLDZ: + yy = 0; + break; + case IFMUL: + k = save_code[i+1]+ti*diff[j]; + if (k < max_var && k > min_var) + yy += y[k]*u[save_code[i+2]+ti*diff[j+1]]; + break; + case IFADD: + yy = -(yy+u[save_code[i+1]+ti*diff[j]]); + break; + case IFSTP: + k = save_code[i+1]+ti*diff[j]; + double err = yy - y[k]; + y[k] += slowc*(err); + break; + } + j += 2; + } + } + mxFree(save_code); + mxFree(diff); + return (beg_t); +} + +void +Interpreter::bksub(int tbreak, int last_period, int Size, double slowc_l) +{ + for (int i = 0; i < y_size*(periods+y_kmin); i++) + y[i] = ya[i]; + if (symbolic && tbreak) + last_period = complete(tbreak, Size, periods, b); + else + last_period = periods; + for (int t = last_period+y_kmin-1; t >= y_kmin; t--) + { + int ti = (t-y_kmin)*Size; + int cal = y_kmin*Size; + int cal_y = y_size*y_kmin; + for (int i = ti-1; i >= ti-Size; i--) + { + int j = i+cal; + int pos = pivot[i+Size]; + NonZeroElem *first; + int nb_var = At_Row(pos, &first); + first = first->NZE_R_N; + nb_var--; + int eq = index_vara[j]+y_size; + double yy = 0; + for (int k = 0; k < nb_var; k++) + { + yy += y[index_vara[first->c_index]+cal_y]*u[first->u_index]; + first = first->NZE_R_N; + } + yy = -(yy+y[eq]+u[b[pos]]); + direction[eq] = yy; + y[eq] += slowc_l*yy; + } + } +} + +void +Interpreter::simple_bksub(int it_, int Size, double slowc_l) +{ + for (int i = 0; i < y_size; i++) + y[i+it_*y_size] = ya[i+it_*y_size]; + for (int i = Size-1; i >= 0; i--) + { + int pos = pivot[i]; + NonZeroElem *first; + int nb_var = At_Row(pos, &first); + first = first->NZE_R_N; + nb_var--; + int eq = index_vara[i]; + double yy = 0; + for (int k = 0; k < nb_var; k++) + { + yy += y[index_vara[first->c_index]+it_*y_size]*u[first->u_index]; + first = first->NZE_R_N; + } + yy = -(yy+y[eq+it_*y_size]+u[b[pos]]); + direction[eq+it_*y_size] = yy; + y[eq+it_*y_size] += slowc_l*yy; + } +} + +mxArray * +Interpreter::subtract_A_B(const mxArray *A_m, const mxArray *B_m) +{ + size_t n_A = mxGetN(A_m); + size_t m_A = mxGetM(A_m); + double *A_d = mxGetPr(A_m); + size_t n_B = mxGetN(B_m); + double *B_d = mxGetPr(B_m); + mxArray *C_m = mxCreateDoubleMatrix(m_A, n_B, mxREAL); + double *C_d = mxGetPr(C_m); + for (int j = 0; j < static_cast<int>(n_A); j++) + for (unsigned int i = 0; i < m_A; i++) + { + size_t index = j*m_A+i; + C_d[index] = A_d[index] - B_d[index]; + } + return C_m; +} + +mxArray * +Interpreter::Sparse_subtract_SA_SB(const mxArray *A_m, const mxArray *B_m) +{ + size_t n_A = mxGetN(A_m); + size_t m_A = mxGetM(A_m); + mwIndex *A_i = mxGetIr(A_m); + mwIndex *A_j = mxGetJc(A_m); + size_t total_nze_A = A_j[n_A]; + double *A_d = mxGetPr(A_m); + size_t n_B = mxGetN(B_m); + mwIndex *B_i = mxGetIr(B_m); + mwIndex *B_j = mxGetJc(B_m); + size_t total_nze_B = B_j[n_B]; + double *B_d = mxGetPr(B_m); + mxArray *C_m = mxCreateSparse(m_A, n_B, m_A*n_B, mxREAL); + mwIndex *C_i = mxGetIr(C_m); + mwIndex *C_j = mxGetJc(C_m); + double *C_d = mxGetPr(C_m); + unsigned int nze_B = 0, nze_C = 0, nze_A = 0; + unsigned int A_col = 0, B_col = 0, C_col = 0; + C_j[C_col] = 0; + while (nze_A < total_nze_A || nze_B < total_nze_B) + { + while (nze_A >= static_cast<unsigned int>(A_j[A_col+1]) && (nze_A < total_nze_A)) + A_col++; + size_t A_row = A_i[nze_A]; + while (nze_B >= static_cast<unsigned int>(B_j[B_col+1]) && (nze_B < total_nze_B)) + B_col++; + size_t B_row = B_i[nze_B]; + if (A_col == B_col) + { + if (A_row == B_row && (nze_B < total_nze_B && nze_A < total_nze_A)) + { + C_d[nze_C] = A_d[nze_A++] - B_d[nze_B++]; + C_i[nze_C] = A_row; + while (C_col < A_col) + C_j[++C_col] = nze_C; + C_j[A_col+1] = nze_C++; + C_col = A_col; + } + else if ((A_row < B_row && nze_A < total_nze_A) || nze_B == total_nze_B) + { + C_d[nze_C] = A_d[nze_A++]; + C_i[nze_C] = A_row; + while (C_col < A_col) + C_j[++C_col] = nze_C; + C_j[A_col+1] = nze_C++; + C_col = A_col; + } + else + { + C_d[nze_C] = -B_d[nze_B++]; + C_i[nze_C] = B_row; + while (C_col < B_col) + C_j[++C_col] = nze_C; + C_j[B_col+1] = nze_C++; + C_col = B_col; + } + } + else if ((A_col < B_col && nze_A < total_nze_A) || nze_B == total_nze_B) + { + C_d[nze_C] = A_d[nze_A++]; + C_i[nze_C] = A_row; + while (C_col < A_col) + C_j[++C_col] = nze_C; + C_j[A_col+1] = nze_C++; + C_col = A_col; + } + else + { + C_d[nze_C] = -B_d[nze_B++]; + C_i[nze_C] = B_row; + while (C_col < B_col) + C_j[++C_col] = nze_C; + C_j[B_col+1] = nze_C++; + C_col = B_col; + } + } + while (C_col < n_B) + C_j[++C_col] = nze_C; + mxSetNzmax(C_m, nze_C); + return C_m; +} + +mxArray * +Interpreter::mult_SAT_B(const mxArray *A_m, const mxArray *B_m) +{ + size_t n_A = mxGetN(A_m); + mwIndex *A_i = mxGetIr(A_m); + mwIndex *A_j = mxGetJc(A_m); + double *A_d = mxGetPr(A_m); + size_t n_B = mxGetN(B_m); + double *B_d = mxGetPr(B_m); + mxArray *C_m = mxCreateDoubleMatrix(n_A, n_B, mxREAL); + double *C_d = mxGetPr(C_m); + for (int j = 0; j < static_cast<int>(n_B); j++) + for (unsigned int i = 0; i < n_A; i++) + { + double sum = 0; + size_t nze_A = A_j[i]; + while (nze_A < static_cast<unsigned int>(A_j[i+1])) + { + size_t i_A = A_i[nze_A]; + sum += A_d[nze_A++] * B_d[i_A]; + } + C_d[j*n_A+i] = sum; + } + return C_m; +} + +mxArray * +Interpreter::Sparse_mult_SAT_B(const mxArray *A_m, const mxArray *B_m) +{ + size_t n_A = mxGetN(A_m); + mwIndex *A_i = mxGetIr(A_m); + mwIndex *A_j = mxGetJc(A_m); + double *A_d = mxGetPr(A_m); + size_t n_B = mxGetN(B_m); + size_t m_B = mxGetM(B_m); + double *B_d = mxGetPr(B_m); + mxArray *C_m = mxCreateSparse(n_A, n_B, n_A*n_B, mxREAL); + mwIndex *C_i = mxGetIr(C_m); + mwIndex *C_j = mxGetJc(C_m); + double *C_d = mxGetPr(C_m); + unsigned int nze_C = 0; + //unsigned int nze_A = 0; + unsigned int C_col = 0; + C_j[C_col] = 0; + //#pragma omp parallel for + for (unsigned int j = 0; j < n_B; j++) + for (unsigned int i = 0; i < n_A; i++) + { + double sum = 0; + size_t nze_A = A_j[i]; + while (nze_A < static_cast<unsigned int>(A_j[i+1])) + { + size_t i_A = A_i[nze_A]; + sum += A_d[nze_A++] * B_d[i_A]; + } + if (fabs(sum) > 1e-10) + { + C_d[nze_C] = sum; + C_i[nze_C] = i; + while (C_col < j) + C_j[++C_col] = nze_C; + nze_C++; + } + } + while (C_col < m_B) + C_j[++C_col] = nze_C; + mxSetNzmax(C_m, nze_C); + return C_m; +} + +mxArray * +Interpreter::Sparse_mult_SAT_SB(const mxArray *A_m, const mxArray *B_m) +{ + size_t n_A = mxGetN(A_m); + mwIndex *A_i = mxGetIr(A_m); + mwIndex *A_j = mxGetJc(A_m); + double *A_d = mxGetPr(A_m); + size_t n_B = mxGetN(B_m); + mwIndex *B_i = mxGetIr(B_m); + mwIndex *B_j = mxGetJc(B_m); + double *B_d = mxGetPr(B_m); + mxArray *C_m = mxCreateSparse(n_A, n_B, n_A*n_B, mxREAL); + mwIndex *C_i = mxGetIr(C_m); + mwIndex *C_j = mxGetJc(C_m); + double *C_d = mxGetPr(C_m); + size_t nze_B = 0, nze_C = 0, nze_A = 0; + unsigned int C_col = 0; + C_j[C_col] = 0; + for (unsigned int j = 0; j < n_B; j++) + for (unsigned int i = 0; i < n_A; i++) + { + double sum = 0; + nze_B = B_j[j]; + nze_A = A_j[i]; + while (nze_A < static_cast<unsigned int>(A_j[i+1]) && nze_B < static_cast<unsigned int>(B_j[j+1])) + { + size_t i_A = A_i[nze_A]; + size_t i_B = B_i[nze_B]; + if (i_A == i_B) + sum += A_d[nze_A++] * B_d[nze_B++]; + else if (i_A < i_B) + nze_A++; + else + nze_B++; + } + if (fabs(sum) > 1e-10) + { + C_d[nze_C] = sum; + C_i[nze_C] = i; + while (C_col < j) + C_j[++C_col] = nze_C; + nze_C++; + } + } + while (C_col < n_B) + C_j[++C_col] = nze_C; + mxSetNzmax(C_m, nze_C); + return C_m; +} + +mxArray * +Interpreter::Sparse_transpose(const mxArray *A_m) +{ + size_t n_A = mxGetN(A_m); + size_t m_A = mxGetM(A_m); + mwIndex *A_i = mxGetIr(A_m); + mwIndex *A_j = mxGetJc(A_m); + size_t total_nze_A = A_j[n_A]; + double *A_d = mxGetPr(A_m); + mxArray *C_m = mxCreateSparse(n_A, m_A, total_nze_A, mxREAL); + mwIndex *C_i = mxGetIr(C_m); + mwIndex *C_j = mxGetJc(C_m); + double *C_d = mxGetPr(C_m); + unsigned int nze_C = 0, nze_A = 0; + fill_n(C_j, m_A+1, 0); + map<pair<mwIndex, unsigned int>, double> B2; + for (unsigned int i = 0; i < n_A; i++) + while (nze_A < static_cast<unsigned int>(A_j[i+1])) + { + C_j[A_i[nze_A]+1]++; + B2[{ A_i[nze_A], i }] = A_d[nze_A]; + nze_A++; + } + for (unsigned int i = 0; i < m_A; i++) + C_j[i+1] += C_j[i]; + for (auto &[key, val] : B2) + { + C_d[nze_C] = val; + C_i[nze_C++] = key.second; + } + return C_m; +} + +void +Interpreter::compute_block_time(int Per_u_, bool evaluate, bool no_derivatives) +{ +#ifdef DEBUG + mexPrintf("compute_block_time\n"); +#endif + double *jacob {nullptr}, *jacob_exo {nullptr}, *jacob_exo_det {nullptr}; + if (evaluate) + { + jacob = mxGetPr(jacobian_block[block_num]); + if (!steady_state) + { + jacob_exo = mxGetPr(jacobian_exo_block[block_num]); + jacob_exo_det = mxGetPr(jacobian_det_exo_block[block_num]); + } + } + + try + { + evaluator.evaluateBlock(it_, y, ya, y_size, x, nb_row_x, params, steady_y, u, Per_u_, T, periods+y_kmin+y_kmax, TEF, TEFD, TEFDD, r, g1, jacob, jacob_exo, jacob_exo_det, evaluate, no_derivatives); + } + catch (FloatingPointException &e) + { + res1 = numeric_limits<double>::quiet_NaN(); + if (verbosity >= 2) + mexPrintf("%s\n %s\n", e.message.c_str(), e.location.c_str()); + } +} + +bool +Interpreter::compute_complete(bool no_derivatives, double &_res1, double &_res2, double &_max_res, int &_max_res_idx) +{ + bool result; + res1 = 0; + compute_block_time(0, false, no_derivatives); + if (!(isnan(res1) || isinf(res1))) + { + _res1 = 0; + _res2 = 0; + _max_res = 0; + for (int i = 0; i < size; i++) + { + double rr; + rr = r[i]; + if (max_res < fabs(rr)) + { + _max_res = fabs(rr); + _max_res_idx = i; + } + _res2 += rr*rr; + _res1 += fabs(rr); + } + result = true; + } + else + result = false; + return result; +} + +bool +Interpreter::compute_complete(double lambda, double *crit) +{ + double res1_ = 0, res2_ = 0, max_res_ = 0; + int max_res_idx_ = 0; + if (steady_state) + { + it_ = 0; + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + y[eq] = ya[eq] + lambda * direction[eq]; + } + Per_u_ = 0; + Per_y_ = 0; + if (compute_complete(true, res1, res2, max_res, max_res_idx)) + res2_ = res2; + else + return false; + } + else + { + for (int it = y_kmin; it < periods+y_kmin; it++) + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + y[eq+it*y_size] = ya[eq+it*y_size] + lambda * direction[eq+it*y_size]; + } + for (it_ = y_kmin; it_ < periods+y_kmin; it_++) + { + Per_u_ = (it_-y_kmin)*u_count_int; + Per_y_ = it_*y_size; + if (compute_complete(true, res1, res2, max_res, max_res_idx)) + { + res2_ += res2; + res1_ += res1; + if (max_res > max_res_) + { + max_res = max_res_; + max_res_idx = max_res_idx_; + } + } + else + return false; + } + it_ = periods+y_kmin-1; // Do not leave it_ in inconsistent state + } + if (verbosity >= 2) + mexPrintf(" lambda=%e, res2=%e\n", lambda, res2_); + *crit = res2_/2; + return true; +} + +bool +Interpreter::mnbrak(double *ax, double *bx, double *cx, double *fa, double *fb, double *fc) +{ + constexpr double GOLD = 1.618034; + constexpr double GLIMIT = 100.0; + constexpr double TINY = 1.0e-20; + + auto sign = [](double a, double b) { return b >= 0.0 ? fabs(a) : -fabs(a); }; + + if (verbosity >= 2) + mexPrintf("bracketing *ax=%f, *bx=%f\n", *ax, *bx); + if (!compute_complete(*ax, fa)) + return false; + if (!compute_complete(*bx, fb)) + return false; + if (*fb > *fa) + { + swap(*ax, *bx); + swap(*fa, *fb); + } + *cx = (*bx)+GOLD*(*bx-*ax); + if (!compute_complete(*cx, fc)) + return false; + while (*fb > *fc) + { + double r = (*bx-*ax)*(*fb-*fc); + double q = (*bx-*cx)*(*fb-*fa); + double u = (*bx)-((*bx-*cx)*q-(*bx-*ax)*r) + /(2.0*sign(fmax(fabs(q-r), TINY), q-r)); + double ulim = (*bx)+GLIMIT*(*cx-*bx); + double fu; + if ((*bx-u)*(u-*cx) > 0.0) + { + if (!compute_complete(u, &fu)) + return false; + if (fu < *fc) + { + *ax = (*bx); + *bx = u; + *fa = (*fb); + *fb = fu; + return true; + } + else if (fu > *fb) + { + *cx = u; + *fc = fu; + return true; + } + u = (*cx)+GOLD*(*cx-*bx); + if (!compute_complete(u, &fu)) + return false; + } + else if ((*cx-u)*(u-ulim) > 0.0) + { + if (!compute_complete(u, &fu)) + return false; + if (fu < *fc) + { + *bx = *cx; + *cx = u; + u = *cx+GOLD*(*cx-*bx); + *fb = *fc; + *fc = fu; + if (!compute_complete(u, &fu)) + return false; + } + } + else if ((u-ulim)*(ulim-*cx) >= 0.0) + { + u = ulim; + if (!compute_complete(u, &fu)) + return false; + } + else + { + u = (*cx)+GOLD*(*cx-*bx); + if (!compute_complete(u, &fu)) + return false; + } + *ax = *bx; + *bx = *cx; + *cx = u; + *fa = *fb; + *fb = *fc; + *fc = fu; + } + return true; +} + +bool +Interpreter::golden(double ax, double bx, double cx, double tol, double solve_tolf, double *xmin) +{ + const double R = 0.61803399; + const double C = (1.0-R); + if (verbosity >= 2) + mexPrintf("golden\n"); + int iter = 0, max_iter = 100; + double f1, f2, x1, x2; + double x0 = ax; + double x3 = cx; + if (fabs(cx-bx) > fabs(bx-ax)) + { + x1 = bx; + x2 = bx+C*(cx-bx); + } + else + { + x2 = bx; + x1 = bx-C*(bx-ax); + } + if (!compute_complete(x1, &f1)) + return false; + if (!compute_complete(x2, &f2)) + return false; + while (fabs(x3-x0) > tol*(fabs(x1)+fabs(x2)) && f1 > solve_tolf && f2 > solve_tolf + && iter < max_iter && abs(x1 - x2) > 1e-4) + { + if (f2 < f1) + { + x0 = x1; + x1 = x2; + x2 = R*x1+C*x3; + f1 = f2; + if (!compute_complete(x2, &f2)) + return false; + } + else + { + x3 = x2; + x2 = x1; + x1 = R*x2+C*x0; + f2 = f1; + if (!compute_complete(x1, &f1)) + return false; + } + iter++; + } + if (f1 < f2) + { + *xmin = x1; + return true; + } + else + { + *xmin = x2; + return true; + } +} + +void +Interpreter::Solve_Matlab_Relaxation(mxArray *A_m, mxArray *b_m, unsigned int Size, double slowc_l) +{ + 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 < 2*Size; var++) // Iterate over columns of A + { + if (var < 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 < Size) + { + if (eq < 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 < 2*Size) + { + if (eq < Size) + { + C1_i[C1_nze] = eq; + C1_d[C1_nze] = A_m_d[nze]; + C1_nze++; + } + else if (eq < 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 < (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 < (t+1) * Size) + { + C1_i[C1_nze] = eq - t*Size; + C1_d[C1_nze] = A_m_d[nze]; + C1_nze++; + } + else if (eq < (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 (unsigned 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_l * 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 (unsigned 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_l * 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_Matlab_LU_UMFPack() +{ + if (Symbolic) + { + umfpack_dl_free_symbolic(&Symbolic); + Symbolic = nullptr; + } + if (Numeric) + { + umfpack_dl_free_numeric(&Numeric); + Numeric = nullptr; + } +} + +void +Interpreter::End_Solver() +{ + if (((stack_solve_algo == 0 || stack_solve_algo == 4) && !steady_state) + || (solve_algo == 6 && steady_state)) + End_Matlab_LU_UMFPack(); +} + +void +Interpreter::Printfull_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, const double *b, int n) +{ + double A[n*n]; + for (int i = 0; i < n*n; i++) + A[i] = 0; + int k = 0; + for (int i = 0; i < n; i++) + for (int j = Ap[i]; j < Ap[i+1]; j++) + A[Ai[j] * n + i] = Ax[k++]; + for (int i = 0; i < n; i++) + { + for (int j = 0; j < n; j++) + mexPrintf("%4.1f ", A[i*n+j]); + mexPrintf(" %6.3f\n", b[i]); + } +} + +void +Interpreter::Print_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, int n) +{ + int k = 0; + for (int i = 0; i < n; i++) + for (int j = Ap[i]; j < Ap[i+1]; j++) + mexPrintf("(%d, %d) %f\n", Ai[j]+1, i+1, Ax[k++]); +} + +void +Interpreter::Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_, const vector_table_conditional_local_type &vector_table_conditional_local) +{ + SuiteSparse_long sys = 0; + double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO], res[n]; + + umfpack_dl_defaults(Control); + SuiteSparse_long status = 0; + if (iter == 0) + { + if (Symbolic) + umfpack_dl_free_symbolic(&Symbolic); + status = umfpack_dl_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info); + if (status != UMFPACK_OK) + { + umfpack_dl_report_info(Control, Info); + umfpack_dl_report_status(Control, status); + throw FatalException{"umfpack_dl_symbolic failed"}; + } + } + if (Numeric) + umfpack_dl_free_numeric(&Numeric); + status = umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); + if (status != UMFPACK_OK) + { + umfpack_dl_report_info(Control, Info); + umfpack_dl_report_status(Control, status); + throw FatalException{"umfpack_dl_numeric failed"}; + } + status = umfpack_dl_solve(sys, Ap, Ai, Ax, res, b, Numeric, Control, Info); + if (status != UMFPACK_OK) + { + umfpack_dl_report_info(Control, Info); + umfpack_dl_report_status(Control, status); + throw FatalException{"umfpack_dl_solve failed"}; + } + + if (vector_table_conditional_local.size()) + { + if (is_two_boundaries) + for (int t = 0; t < n / Size; t++) + if (t == 0) + { + for (int i = 0; i < Size; i++) + { + bool fliped = vector_table_conditional_local[i].is_cond; + if (fliped) + { + int eq = index_vara[i+Size*(y_kmin)]; + int flip_exo = vector_table_conditional_local[i].var_exo; + double yy = -(res[i] + x[y_kmin + flip_exo*nb_row_x]); + direction[eq] = 0; + x[flip_exo*nb_row_x + y_kmin] += slowc_l * yy; + } + else + { + int eq = index_vara[i+Size*(y_kmin)]; + double yy = -(res[i] + y[eq]); + direction[eq] = yy; + y[eq] += slowc_l * yy; + } + } + } + else + { + for (int i = 0; i < Size; i++) + { + int eq = index_vara[i+Size*(t + y_kmin)]; + double yy = -(res[i + Size * t] + y[eq]); + direction[eq] = yy; + y[eq] += slowc_l * yy; + } + } + else + for (int i = 0; i < n; i++) + { + int eq = index_vara[i]; + double yy = -(res[i] + y[eq+it_*y_size]); + direction[eq] = yy; + y[eq+it_*y_size] += slowc_l * yy; + } + } + else + { + if (is_two_boundaries) + for (int i = 0; i < n; i++) + { + int eq = index_vara[i+Size*y_kmin]; + double yy = -(res[i] + y[eq]); + direction[eq] = yy; + y[eq] += slowc_l * yy; + } + else + for (int i = 0; i < n; i++) + { + int eq = index_vara[i]; + double yy = -(res[i] + y[eq+it_*y_size]); + direction[eq] = yy; + y[eq+it_*y_size] += slowc_l * yy; + } + } + + mxFree(Ap); + mxFree(Ai); + mxFree(Ax); + mxFree(b); +} + +void +Interpreter::Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_) +{ + SuiteSparse_long sys = 0; + double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO], res[n]; + + umfpack_dl_defaults(Control); + SuiteSparse_long status = 0; + if (iter == 0) + { + if (Symbolic) + umfpack_dl_free_symbolic(&Symbolic); + status = umfpack_dl_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info); + if (status != UMFPACK_OK) + { + umfpack_dl_report_info(Control, Info); + umfpack_dl_report_status(Control, status); + throw FatalException{"umfpack_dl_symbolic failed"}; + } + } + if (Numeric) + umfpack_dl_free_numeric(&Numeric); + status = umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); + if (status != UMFPACK_OK) + { + umfpack_dl_report_info(Control, Info); + umfpack_dl_report_status(Control, status); + throw FatalException{"umfpack_dl_numeric failed"}; + } + status = umfpack_dl_solve(sys, Ap, Ai, Ax, res, b, Numeric, Control, Info); + if (status != UMFPACK_OK) + { + umfpack_dl_report_info(Control, Info); + umfpack_dl_report_status(Control, status); + throw FatalException{"umfpack_dl_solve failed"}; + } + + if (is_two_boundaries) + for (int i = 0; i < n; i++) + { + int eq = index_vara[i+Size*y_kmin]; + double yy = -(res[i] + y[eq]); + direction[eq] = yy; + y[eq] += slowc_l * yy; + } + else + for (int i = 0; i < n; i++) + { + int eq = index_vara[i]; + double yy = -(res[i] + y[eq+it_*y_size]); + direction[eq] = yy; + y[eq+it_*y_size] += slowc_l * yy; + } + mxFree(Ap); + mxFree(Ai); + mxFree(Ax); + mxFree(b); +} + +void +Interpreter::Solve_Matlab_GMRES(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m) +{ + size_t n = mxGetM(A_m); + const char *field_names[] = {"droptol", "type"}; + mwSize dims[1] = { 1 }; + mxArray *Setup = mxCreateStructArray(1, dims, std::extent_v<decltype(field_names)>, field_names); + mxSetFieldByNumber(Setup, 0, 0, mxCreateDoubleScalar(lu_inc_tol)); + mxSetFieldByNumber(Setup, 0, 1, mxCreateString("ilutp")); + mxArray *lhs0[2]; + mxArray *rhs0[] = { A_m, Setup }; + if (mexCallMATLAB(std::extent_v<decltype(lhs0)>, lhs0, std::extent_v<decltype(rhs0)>, rhs0, "ilu")) + throw FatalException("In GMRES, the incomplete LU decomposition (ilu) has failed"); + mxArray *L1 = lhs0[0]; + mxArray *U1 = lhs0[1]; + /*[za,flag1] = gmres(g1a,b,Blck_size,1e-6,Blck_size*periods,L1,U1);*/ + mxArray *rhs[] = { A_m, b_m, mxCreateDoubleScalar(Size), mxCreateDoubleScalar(1e-6), + mxCreateDoubleScalar(static_cast<double>(n)), L1, U1, x0_m }; + mxArray *lhs[2]; + mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "gmres"); + mxArray *z = lhs[0]; + mxArray *flag = lhs[1]; + double *flag1 = mxGetPr(flag); + mxDestroyArray(rhs0[1]); + mxDestroyArray(rhs[2]); + mxDestroyArray(rhs[3]); + mxDestroyArray(rhs[4]); + mxDestroyArray(rhs[5]); + mxDestroyArray(rhs[6]); + if (*flag1 > 0) + { + if (*flag1 == 1) + mexWarnMsgTxt(("Error in bytecode: No convergence inside GMRES, in block " + + to_string(block+1)).c_str()); + else if (*flag1 == 2) + mexWarnMsgTxt(("Error in bytecode: Preconditioner is ill-conditioned, in block " + + to_string(block+1)).c_str()); + else if (*flag1 == 3) + mexWarnMsgTxt(("Error in bytecode: GMRES stagnated (Two consecutive iterates were the same.), in block " + + to_string(block+1)).c_str()); + lu_inc_tol /= 10; + } + else + { + double *res = mxGetPr(z); + if (is_two_boundaries) + for (int i = 0; i < static_cast<int>(n); i++) + { + int eq = index_vara[i+Size*y_kmin]; + double yy = -(res[i] + y[eq]); + direction[eq] = yy; + y[eq] += slowc * yy; + } + else + for (int i = 0; i < static_cast<int>(n); i++) + { + int eq = index_vara[i]; + double yy = -(res[i] + y[eq+it_*y_size]); + direction[eq] = yy; + y[eq+it_*y_size] += slowc * yy; + } + } + mxDestroyArray(A_m); + mxDestroyArray(b_m); + mxDestroyArray(x0_m); + mxDestroyArray(z); + mxDestroyArray(flag); +} + +void +Interpreter::Solve_Matlab_BiCGStab(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m, int preconditioner) +{ + /* precond = 0 => Jacobi + precond = 1 => Incomplet LU decomposition*/ + size_t n = mxGetM(A_m); + mxArray *L1 = nullptr, *U1 = nullptr, *Diag = nullptr; + + if (preconditioner == 0) + { + mxArray *lhs0[1]; + mxArray *rhs0[] = { A_m, mxCreateDoubleScalar(0) }; + mexCallMATLAB(std::extent_v<decltype(lhs0)>, lhs0, std::extent_v<decltype(rhs0)>, rhs0, "spdiags"); + mxArray *tmp = lhs0[0]; + double *tmp_val = mxGetPr(tmp); + Diag = mxCreateSparse(n, n, n, mxREAL); + mwIndex *Diag_i = mxGetIr(Diag); + mwIndex *Diag_j = mxGetJc(Diag); + double *Diag_val = mxGetPr(Diag); + for (size_t i = 0; i < n; i++) + { + Diag_val[i] = tmp_val[i]; + Diag_j[i] = i; + Diag_i[i] = i; + } + Diag_j[n] = n; + } + else if (preconditioner == 1) + { + /*[L1, U1] = ilu(g1a=;*/ + const char *field_names[] = {"type", "droptol", "milu", "udiag", "thresh"}; + const int type = 0, droptol = 1, milu = 2, udiag = 3, thresh = 4; + mwSize dims[1] = { static_cast<mwSize>(1) }; + mxArray *Setup = mxCreateStructArray(1, dims, std::extent_v<decltype(field_names)>, field_names); + mxSetFieldByNumber(Setup, 0, type, mxCreateString("ilutp")); + mxSetFieldByNumber(Setup, 0, droptol, mxCreateDoubleScalar(lu_inc_tol)); + mxSetFieldByNumber(Setup, 0, milu, mxCreateString("off")); + mxSetFieldByNumber(Setup, 0, udiag, mxCreateDoubleScalar(0)); + mxSetFieldByNumber(Setup, 0, thresh, mxCreateDoubleScalar(1)); + mxArray *lhs0[2]; + mxArray *rhs0[] = { A_m, Setup }; + if (mexCallMATLAB(std::extent_v<decltype(lhs0)>, lhs0, std::extent_v<decltype(rhs0)>, rhs0, "ilu")) + throw FatalException{"In BiCGStab, the incomplete LU decomposition (ilu) has failed"}; + L1 = lhs0[0]; + U1 = lhs0[1]; + mxDestroyArray(Setup); + } + double flags = 2; + mxArray *z = nullptr; + if (steady_state) /*Octave BicStab algorihtm involves a 0 division in case of a preconditionner equal to the LU decomposition of A matrix*/ + { + mxArray *res = mult_SAT_B(Sparse_transpose(A_m), x0_m); + double *resid = mxGetPr(res); + double *b = mxGetPr(b_m); + for (int i = 0; i < static_cast<int>(n); i++) + resid[i] = b[i] - resid[i]; + mxArray *lhs[1]; + mxArray *rhs[] = { L1, res }; + mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "mldivide"); + mxArray *rhs2[] = { U1, lhs[0] }; + mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs2)>, rhs2, "mldivide"); + z = lhs[0]; + double *phat = mxGetPr(z); + double *x0 = mxGetPr(x0_m); + for (int i = 0; i < static_cast<int>(n); i++) + phat[i] = x0[i] + phat[i]; + + /*Check the solution*/ + res = mult_SAT_B(Sparse_transpose(A_m), z); + resid = mxGetPr(res); + double cum_abs = 0; + for (int i = 0; i < static_cast<int>(n); i++) + { + resid[i] = b[i] - resid[i]; + cum_abs += fabs(resid[i]); + } + if (cum_abs > 1e-7) + flags = 2; + else + flags = 0; + mxDestroyArray(res); + } + + if (flags == 2) + { + if (preconditioner == 0) + { + /*[za,flag1] = bicgstab(g1a,b,1e-6,Blck_size*periods,L1,U1);*/ + mxArray *rhs[] = { A_m, b_m, mxCreateDoubleScalar(1e-6), + mxCreateDoubleScalar(static_cast<double>(n)), Diag }; + mxArray *lhs[2]; + mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "bicgstab"); + z = lhs[0]; + mxArray *flag = lhs[1]; + double *flag1 = mxGetPr(flag); + flags = flag1[0]; + mxDestroyArray(flag); + mxDestroyArray(rhs[2]); + mxDestroyArray(rhs[3]); + mxDestroyArray(rhs[4]); + } + else if (preconditioner == 1) + { + /*[za,flag1] = bicgstab(g1a,b,1e-6,Blck_size*periods,L1,U1);*/ + mxArray *rhs[] = { A_m, b_m, mxCreateDoubleScalar(1e-6), + mxCreateDoubleScalar(static_cast<double>(n)), L1, U1, x0_m }; + mxArray *lhs[2]; + mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "bicgstab"); + z = lhs[0]; + mxArray *flag = lhs[1]; + double *flag1 = mxGetPr(flag); + flags = flag1[0]; + mxDestroyArray(flag); + mxDestroyArray(rhs[2]); + mxDestroyArray(rhs[3]); + mxDestroyArray(rhs[4]); + mxDestroyArray(rhs[5]); + } + } + + if (flags > 0) + { + if (flags == 1) + mexWarnMsgTxt(("Error in bytecode: No convergence inside BiCGStab, in block " + + to_string(block+1)).c_str()); + else if (flags == 2) + mexWarnMsgTxt(("Error in bytecode: Preconditioner is ill-conditioned, in block " + + to_string(block+1)).c_str()); + else if (flags == 3) + mexWarnMsgTxt(("Error in bytecode: BiCGStab stagnated (Two consecutive iterates were the same.), in block " + + to_string(block+1)).c_str()); + lu_inc_tol /= 10; + } + else + { + double *res = mxGetPr(z); + if (is_two_boundaries) + for (int i = 0; i < static_cast<int>(n); i++) + { + int eq = index_vara[i+Size*y_kmin]; + double yy = -(res[i] + y[eq]); + direction[eq] = yy; + y[eq] += slowc * yy; + } + else + for (int i = 0; i < static_cast<int>(n); i++) + { + int eq = index_vara[i]; + double yy = -(res[i] + y[eq+it_*y_size]); + direction[eq] = yy; + y[eq+it_*y_size] += slowc * yy; + } + } + mxDestroyArray(A_m); + mxDestroyArray(b_m); + mxDestroyArray(x0_m); + mxDestroyArray(z); +} + +void +Interpreter::Singular_display(int block, int Size) +{ + bool zero_solution; + Simple_Init(Size, IM_i, zero_solution); + mxArray *rhs[] = { mxCreateDoubleMatrix(Size, Size, mxREAL) }; + double *pind = mxGetPr(rhs[0]); + for (int j = 0; j < Size * Size; j++) + pind[j] = 0.0; + for (int ii = 0; ii < Size; ii++) + { + NonZeroElem *first; + int nb_eq = At_Col(ii, &first); + for (int j = 0; j < nb_eq; j++) + { + int k = first->u_index; + int jj = first->r_index; + pind[ii * Size + jj] = u[k]; + first = first->NZE_C_N; + } + } + mxArray *lhs[3]; + mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "svd"); + mxArray *SVD_u = lhs[0]; + mxArray *SVD_s = lhs[1]; + double *SVD_ps = mxGetPr(SVD_s); + double *SVD_pu = mxGetPr(SVD_u); + for (int i = 0; i < Size; i++) + if (abs(SVD_ps[i * (1 + Size)]) < 1e-12) + { + mexPrintf(" The following equations form a linear combination:\n "); + double max_u = 0; + for (int j = 0; j < Size; j++) + if (abs(SVD_pu[j + i * Size]) > abs(max_u)) + max_u = SVD_pu[j + i * Size]; + vector<int> equ_list; + for (int j = 0; j < Size; j++) + { + double rr = SVD_pu[j + i * Size] / max_u; + if (rr < -1e-10) + { + equ_list.push_back(j); + if (rr != -1) + mexPrintf(" - %3.2f*Dequ_%d_dy", abs(rr), j+1); + else + mexPrintf(" - Dequ_%d_dy", j+1); + } + else if (rr > 1e-10) + { + equ_list.push_back(j); + if (j > 0) + if (rr != 1) + mexPrintf(" + %3.2f*Dequ_%d_dy", rr, j+1); + else + mexPrintf(" + Dequ_%d_dy", j+1); + else if (rr != 1) + mexPrintf(" %3.2f*Dequ_%d_dy", rr, j+1); + else + mexPrintf(" Dequ_%d_dy", j+1); + } + } + mexPrintf(" = 0\n"); + } + mxDestroyArray(lhs[0]); + mxDestroyArray(lhs[1]); + mxDestroyArray(lhs[2]); + if (block > 1) + throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system in block " + + to_string(block+1)}; + else + throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system"}; +} + +bool +Interpreter::Solve_ByteCode_Sparse_GaussianElimination(int Size, int blck, int it_) +{ + int pivj = 0, pivk = 0; + NonZeroElem **bc = static_cast<NonZeroElem **>(mxMalloc(Size*sizeof(*bc))); + test_mxMalloc(bc, __LINE__, __FILE__, __func__, Size*sizeof(*bc)); + double *piv_v = static_cast<double *>(mxMalloc(Size*sizeof(double))); + test_mxMalloc(piv_v, __LINE__, __FILE__, __func__, Size*sizeof(double)); + int *pivj_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivj_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); + int *pivk_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivk_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); + int *NR = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(NR, __LINE__, __FILE__, __func__, Size*sizeof(int)); + + for (int i = 0; i < Size; i++) + { + /*finding the max-pivot*/ + double piv = 0, piv_abs = 0; + NonZeroElem *first; + int nb_eq = At_Col(i, &first); + int l = 0; + int N_max = 0; + bool one = false; + for (int j = 0; j < nb_eq; j++) + { + if (!line_done[first->r_index]) + { + int k = first->u_index; + int jj = first->r_index; + int NRow_jj = NRow(jj); + + piv_v[l] = u[k]; + double piv_fabs = fabs(u[k]); + pivj_v[l] = jj; + pivk_v[l] = k; + NR[l] = NRow_jj; + if (NRow_jj == 1 && !one) + { + one = true; + piv_abs = piv_fabs; + N_max = NRow_jj; + } + if (!one) + { + if (piv_fabs > piv_abs) + piv_abs = piv_fabs; + if (NRow_jj > N_max) + N_max = NRow_jj; + } + else if (NRow_jj == 1) + { + if (piv_fabs > piv_abs) + piv_abs = piv_fabs; + if (NRow_jj > N_max) + N_max = NRow_jj; + } + l++; + } + first = first->NZE_C_N; + } + if (piv_abs < eps) + { + mxFree(piv_v); + mxFree(pivj_v); + mxFree(pivk_v); + mxFree(NR); + mxFree(bc); + if (steady_state) + { + if (verbosity >= 1) + { + if (blck > 1) + mexPrintf("Error: singular system in Simulate_NG in block %d\n", blck+1); + else + mexPrintf("Error: singular system in Simulate_NG"); + } + return true; + } + else + { + if (blck > 1) + throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system in block " + + to_string(blck+1)}; + else + throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system"}; + } + } + double markovitz = 0, markovitz_max = -9e70; + if (!one) + for (int j = 0; j < l; j++) + { + if (N_max > 0 && NR[j] > 0) + { + if (fabs(piv_v[j]) > 0) + { + if (markowitz_c > 0) + markovitz = exp(log(fabs(piv_v[j])/piv_abs) + -markowitz_c*log(static_cast<double>(NR[j]) + /static_cast<double>(N_max))); + else + markovitz = fabs(piv_v[j])/piv_abs; + } + else + markovitz = 0; + } + else + markovitz = fabs(piv_v[j])/piv_abs; + if (markovitz > markovitz_max) + { + piv = piv_v[j]; + pivj = pivj_v[j]; //Line number + pivk = pivk_v[j]; //positi + markovitz_max = markovitz; + } + } + else + for (int j = 0; j < l; j++) + { + if (N_max > 0 && NR[j] > 0) + { + if (fabs(piv_v[j]) > 0) + { + if (markowitz_c > 0) + markovitz = exp(log(fabs(piv_v[j])/piv_abs) + -markowitz_c*log(static_cast<double>(NR[j]) + /static_cast<double>(N_max))); + else + markovitz = fabs(piv_v[j])/piv_abs; + } + else + markovitz = 0; + } + else + markovitz = fabs(piv_v[j])/piv_abs; + if (NR[j] == 1) + { + piv = piv_v[j]; + pivj = pivj_v[j]; //Line number + pivk = pivk_v[j]; //positi + markovitz_max = markovitz; + } + } + pivot[i] = pivj; + pivotk[i] = pivk; + pivotv[i] = piv; + line_done[pivj] = true; + + /*divide all the non zeros elements of the line pivj by the max_pivot*/ + int nb_var = At_Row(pivj, &first); + for (int j = 0; j < nb_var; j++) + { + u[first->u_index] /= piv; + first = first->NZE_R_N; + } + u[b[pivj]] /= piv; + /*subtract the elements on the non treated lines*/ + nb_eq = At_Col(i, &first); + NonZeroElem *first_piva; + int nb_var_piva = At_Row(pivj, &first_piva); + int nb_eq_todo = 0; + for (int j = 0; j < nb_eq && first; j++) + { + if (!line_done[first->r_index]) + bc[nb_eq_todo++] = first; + first = first->NZE_C_N; + } + for (int j = 0; j < nb_eq_todo; j++) + { + first = bc[j]; + int row = first->r_index; + double first_elem = u[first->u_index]; + + int nb_var_piv = nb_var_piva; + NonZeroElem *first_piv = first_piva; + NonZeroElem *first_sub; + int nb_var_sub = At_Row(row, &first_sub); + int l_sub = 0, l_piv = 0; + int sub_c_index = first_sub->c_index, piv_c_index = first_piv->c_index; + while (l_sub < nb_var_sub || l_piv < nb_var_piv) + if (l_sub < nb_var_sub && (sub_c_index < piv_c_index || l_piv >= nb_var_piv)) + { + first_sub = first_sub->NZE_R_N; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size; + l_sub++; + } + else if (sub_c_index > piv_c_index || l_sub >= nb_var_sub) + { + int tmp_u_count = Get_u(); + Insert(row, first_piv->c_index, tmp_u_count, 0); + u[tmp_u_count] = -u[first_piv->u_index]*first_elem; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size; + l_piv++; + } + else + { + if (i == sub_c_index) + { + NonZeroElem *firsta = first; + NonZeroElem *first_suba = first_sub->NZE_R_N; + Delete(first_sub->r_index, first_sub->c_index); + first = firsta->NZE_C_N; + first_sub = first_suba; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size; + l_sub++; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size; + l_piv++; + } + else + { + u[first_sub->u_index] -= u[first_piv->u_index]*first_elem; + first_sub = first_sub->NZE_R_N; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size; + l_sub++; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size; + l_piv++; + } + } + u[b[row]] -= u[b[pivj]]*first_elem; + } + } + double slowc_lbx = slowc; + for (int i = 0; i < y_size; i++) + ya[i+it_*y_size] = y[i+it_*y_size]; + + slowc_save = slowc; + simple_bksub(it_, Size, slowc_lbx); + End_GE(); + mxFree(piv_v); + mxFree(pivj_v); + mxFree(pivk_v); + mxFree(NR); + mxFree(bc); + return false; +} + +void +Interpreter::Solve_ByteCode_Symbolic_Sparse_GaussianElimination(int Size, bool symbolic, int Block_number) +{ + /*Triangularisation at each period of a block using a simple gaussian Elimination*/ + int *save_op = nullptr, *save_opa = nullptr, *save_opaa = nullptr; + long int nop = 0, nopa = 0; + bool record = false; + + int pivj = 0, pivk = 0; + int tbreak = 0, last_period = periods; + + double *piv_v = static_cast<double *>(mxMalloc(Size*sizeof(double))); + test_mxMalloc(piv_v, __LINE__, __FILE__, __func__, Size*sizeof(double)); + int *pivj_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivj_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); + int *pivk_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(pivk_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); + int *NR = static_cast<int *>(mxMalloc(Size*sizeof(int))); + test_mxMalloc(NR, __LINE__, __FILE__, __func__, Size*sizeof(int)); + NonZeroElem **bc = static_cast<NonZeroElem **>(mxMalloc(Size*sizeof(NonZeroElem *))); + test_mxMalloc(bc, __LINE__, __FILE__, __func__, Size*sizeof(NonZeroElem *)); + + for (int t = 0; t < periods; t++) + { +#ifdef MATLAB_MEX_FILE + if (utIsInterruptPending()) + throw UserException{}; +#endif + + if (record && symbolic) + { + save_op = static_cast<int *>(mxMalloc(nop*sizeof(int))); + test_mxMalloc(save_op, __LINE__, __FILE__, __func__, nop*sizeof(int)); + nopa = nop; + } + nop = 0; + Clear_u(); + int ti = t*Size; + for (int i = ti; i < Size+ti; i++) + { + /*finding the max-pivot*/ + double piv = 0, piv_abs = 0; + NonZeroElem *first; + int nb_eq = At_Col(i, 0, &first); + if ((symbolic && t <= start_compare) || !symbolic) + { + int l = 0, N_max = 0; + bool one = false; + piv_abs = 0; + for (int j = 0; j < nb_eq; j++) + { + if (!line_done[first->r_index]) + { + int k = first->u_index; + int jj = first->r_index; + int NRow_jj = NRow(jj); + piv_v[l] = u[k]; + double piv_fabs = fabs(u[k]); + pivj_v[l] = jj; + pivk_v[l] = k; + NR[l] = NRow_jj; + if (NRow_jj == 1 && !one) + { + one = true; + piv_abs = piv_fabs; + N_max = NRow_jj; + } + if (!one) + { + if (piv_fabs > piv_abs) + piv_abs = piv_fabs; + if (NRow_jj > N_max) + N_max = NRow_jj; + } + else if (NRow_jj == 1) + { + if (piv_fabs > piv_abs) + piv_abs = piv_fabs; + if (NRow_jj > N_max) + N_max = NRow_jj; + } + l++; + } + first = first->NZE_C_N; + } + double markovitz = 0, markovitz_max = -9e70; + int NR_max = 0; + if (!one) + for (int j = 0; j < l; j++) + { + if (N_max > 0 && NR[j] > 0) + { + if (fabs(piv_v[j]) > 0) + { + if (markowitz_c > 0) + markovitz = exp(log(fabs(piv_v[j])/piv_abs) + -markowitz_c*log(static_cast<double>(NR[j]) + /static_cast<double>(N_max))); + else + markovitz = fabs(piv_v[j])/piv_abs; + } + else + markovitz = 0; + } + else + markovitz = fabs(piv_v[j])/piv_abs; + if (markovitz > markovitz_max) + { + piv = piv_v[j]; + pivj = pivj_v[j]; //Line number + pivk = pivk_v[j]; //positi + markovitz_max = markovitz; + NR_max = NR[j]; + } + } + else + for (int j = 0; j < l; j++) + { + if (N_max > 0 && NR[j] > 0) + { + if (fabs(piv_v[j]) > 0) + { + if (markowitz_c > 0) + markovitz = exp(log(fabs(piv_v[j])/piv_abs) + -markowitz_c*log(static_cast<double>(NR[j]) + /static_cast<double>(N_max))); + else + markovitz = fabs(piv_v[j])/piv_abs; + } + else + markovitz = 0; + } + else + markovitz = fabs(piv_v[j])/piv_abs; + if (NR[j] == 1) + { + piv = piv_v[j]; + pivj = pivj_v[j]; //Line number + pivk = pivk_v[j]; //positi + markovitz_max = markovitz; + NR_max = NR[j]; + } + } + if (fabs(piv) < eps && verbosity >= 1) + mexPrintf("==> Error NR_max=%d, N_max=%d and piv=%f, piv_abs=%f, markovitz_max=%f\n", NR_max, N_max, piv, piv_abs, markovitz_max); + if (NR_max == 0 && verbosity >= 1) + mexPrintf("==> Error NR_max=0 and piv=%f, markovitz_max=%f\n", piv, markovitz_max); + pivot[i] = pivj; + pivot_save[i] = pivj; + pivotk[i] = pivk; + pivotv[i] = piv; + } + else + { + pivj = pivot[i-Size]+Size; + pivot[i] = pivj; + At_Pos(pivj, i, &first); + pivk = first->u_index; + piv = u[pivk]; + piv_abs = fabs(piv); + } + line_done[pivj] = true; + + if (record && symbolic) + { + if (nop+1 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + t_save_op_s *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[nop]); + save_op_s->operat = IFLD; + save_op_s->first = pivk; + save_op_s->lag = 0; + nop += 2; + if (piv_abs < eps) + { + if (Block_number > 1) + throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system in block " + + to_string(Block_number+1)}; + else + throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system"}; + } + /*divide all the non zeros elements of the line pivj by the max_pivot*/ + int nb_var = At_Row(pivj, &first); + for (int j = 0; j < nb_var; j++) + { + u[first->u_index] /= piv; + if (nop+j*2+1 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[nop+j*2]); + save_op_s->operat = IFDIV; + save_op_s->first = first->u_index; + save_op_s->lag = first->lag_index; + first = first->NZE_R_N; + } + nop += nb_var*2; + u[b[pivj]] /= piv; + if (nop+1 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[nop]); + save_op_s->operat = IFDIV; + save_op_s->first = b[pivj]; + save_op_s->lag = 0; + nop += 2; + // Subtract the elements on the non treated lines + nb_eq = At_Col(i, &first); + NonZeroElem *first_piva; + int nb_var_piva = At_Row(pivj, &first_piva); + + int nb_eq_todo = 0; + for (int j = 0; j < nb_eq && first; j++) + { + if (!line_done[first->r_index]) + bc[nb_eq_todo++] = first; + first = first->NZE_C_N; + } + for (int j = 0; j < nb_eq_todo; j++) + { + t_save_op_s *save_op_s_l; + NonZeroElem *first = bc[j]; + int row = first->r_index; + double first_elem = u[first->u_index]; + if (nop+1 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); + save_op_s_l->operat = IFLD; + save_op_s_l->first = first->u_index; + save_op_s_l->lag = abs(first->lag_index); + nop += 2; + + int nb_var_piv = nb_var_piva; + NonZeroElem *first_piv = first_piva; + NonZeroElem *first_sub; + int nb_var_sub = At_Row(row, &first_sub); + int l_sub = 0; + int l_piv = 0; + int sub_c_index = first_sub->c_index; + int piv_c_index = first_piv->c_index; + int tmp_lag = first_sub->lag_index; + while (l_sub < nb_var_sub /*=NRow(row)*/ || l_piv < nb_var_piv) + { + if (l_sub < nb_var_sub && (sub_c_index < piv_c_index || l_piv >= nb_var_piv)) + { + /* There is no nonzero element at row pivot for this + column ⇒ Nothing to do for the current element got to + next column */ + first_sub = first_sub->NZE_R_N; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size*periods; + l_sub++; + } + else if (sub_c_index > piv_c_index || l_sub >= nb_var_sub) + { + // There is an nonzero element at row pivot but not at the current row=> insert a negative element in the current row + int tmp_u_count = Get_u(); + int lag = first_piv->c_index/Size-row/Size; + Insert(row, first_piv->c_index, tmp_u_count, lag); + u[tmp_u_count] = -u[first_piv->u_index]*first_elem; + if (nop+2 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); + save_op_s_l->operat = IFLESS; + save_op_s_l->first = tmp_u_count; + save_op_s_l->second = first_piv->u_index; + save_op_s_l->lag = max(first_piv->lag_index, abs(tmp_lag)); + nop += 3; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size*periods; + l_piv++; + } + else /*first_sub->c_index==first_piv->c_index*/ + { + if (i == sub_c_index) + { + NonZeroElem *firsta = first; + NonZeroElem *first_suba = first_sub->NZE_R_N; + Delete(first_sub->r_index, first_sub->c_index); + first = firsta->NZE_C_N; + first_sub = first_suba; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size*periods; + l_sub++; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size*periods; + l_piv++; + } + else + { + u[first_sub->u_index] -= u[first_piv->u_index]*first_elem; + if (nop+3 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); + save_op_s_l->operat = IFSUB; + save_op_s_l->first = first_sub->u_index; + save_op_s_l->second = first_piv->u_index; + save_op_s_l->lag = max(abs(tmp_lag), first_piv->lag_index); + nop += 3; + first_sub = first_sub->NZE_R_N; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size*periods; + l_sub++; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size*periods; + l_piv++; + } + } + } + u[b[row]] -= u[b[pivj]]*first_elem; + + if (nop+3 >= nopa) + { + nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); + save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); + } + save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); + save_op_s_l->operat = IFSUB; + save_op_s_l->first = b[row]; + save_op_s_l->second = b[pivj]; + save_op_s_l->lag = abs(tmp_lag); + nop += 3; + } + } + else if (symbolic) + { + nop += 2; + if (piv_abs < eps) + { + if (Block_number > 1) + throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system in block " + + to_string(Block_number+1)}; + else + throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system"}; + } + // Divide all the non zeros elements of the line pivj by the max_pivot + int nb_var = At_Row(pivj, &first); + for (int j = 0; j < nb_var; j++) + { + u[first->u_index] /= piv; + first = first->NZE_R_N; + } + nop += nb_var*2; + u[b[pivj]] /= piv; + nop += 2; + // Subtract the elements on the non treated lines + nb_eq = At_Col(i, &first); + NonZeroElem *first_piva; + int nb_var_piva = At_Row(pivj, &first_piva); + + int nb_eq_todo = 0; + for (int j = 0; j < nb_eq && first; j++) + { + if (!line_done[first->r_index]) + bc[nb_eq_todo++] = first; + first = first->NZE_C_N; + } + for (int j = 0; j < nb_eq_todo; j++) + { + NonZeroElem *first = bc[j]; + int row = first->r_index; + double first_elem = u[first->u_index]; + nop += 2; + int nb_var_piv = nb_var_piva; + NonZeroElem *first_piv = first_piva; + NonZeroElem *first_sub; + int nb_var_sub = At_Row(row, &first_sub); + int l_sub = 0; + int l_piv = 0; + int sub_c_index = first_sub->c_index; + int piv_c_index = first_piv->c_index; + while (l_sub < nb_var_sub /*= NRow(row)*/ || l_piv < nb_var_piv) + { + if (l_sub < nb_var_sub && (sub_c_index < piv_c_index || l_piv >= nb_var_piv)) + { + /* There is no nonzero element at row pivot for this + column ⇒ Nothing to do for the current element got to + next column */ + first_sub = first_sub->NZE_R_N; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size*periods; + l_sub++; + } + else if (sub_c_index > piv_c_index || l_sub >= nb_var_sub) + { + /* There is an nonzero element at row pivot but not + at the current row ⇒ insert a negative element in the + current row */ + int tmp_u_count = Get_u(); + int lag = first_piv->c_index/Size-row/Size; + Insert(row, first_piv->c_index, tmp_u_count, lag); + u[tmp_u_count] = -u[first_piv->u_index]*first_elem; + nop += 3; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size*periods; + l_piv++; + } + else /*first_sub->c_index==first_piv->c_index*/ + { + if (i == sub_c_index) + { + NonZeroElem *firsta = first; + NonZeroElem *first_suba = first_sub->NZE_R_N; + Delete(first_sub->r_index, first_sub->c_index); + first = firsta->NZE_C_N; + first_sub = first_suba; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size*periods; + l_sub++; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size*periods; + l_piv++; + } + else + { + u[first_sub->u_index] -= u[first_piv->u_index]*first_elem; + nop += 3; + first_sub = first_sub->NZE_R_N; + if (first_sub) + sub_c_index = first_sub->c_index; + else + sub_c_index = Size*periods; + l_sub++; + first_piv = first_piv->NZE_R_N; + if (first_piv) + piv_c_index = first_piv->c_index; + else + piv_c_index = Size*periods; + l_piv++; + } + } + } + u[b[row]] -= u[b[pivj]]*first_elem; + nop += 3; + } + } + } + if (symbolic) + { + if (t > static_cast<int>(periods*0.35)) + { + symbolic = false; + mxFree(save_opaa); + mxFree(save_opa); + mxFree(save_op); + } + else if (record && nop == nop1) + { + if (t > static_cast<int>(periods*0.35)) + { + symbolic = false; + if (save_opaa) + { + mxFree(save_opaa); + save_opaa = nullptr; + } + if (save_opa) + { + mxFree(save_opa); + save_opa = nullptr; + } + if (save_op) + { + mxFree(save_op); + save_op = nullptr; + } + } + else if (save_opa && save_opaa) + { + if (compare(save_op, save_opa, save_opaa, t, periods, nop, Size)) + { + tbreak = t; + tbreak_g = tbreak; + break; + } + } + if (save_opa) + { + if (save_opaa) + { + mxFree(save_opaa); + save_opaa = nullptr; + } + save_opaa = save_opa; + } + save_opa = save_op; + } + else + { + if (nop == nop1) + record = true; + else + { + record = false; + if (save_opa) + { + mxFree(save_opa); + save_opa = nullptr; + } + if (save_opaa) + { + mxFree(save_opaa); + save_opaa = nullptr; + } + } + } + nop1 = nop; + } + } + mxFree(bc); + mxFree(piv_v); + mxFree(pivj_v); + mxFree(pivk_v); + mxFree(NR); + if (symbolic) + { + if (save_op) + mxFree(save_op); + if (save_opa) + mxFree(save_opa); + if (save_opaa) + mxFree(save_opaa); + } + + // The backward substitution + double slowc_lbx = slowc; + for (int i = 0; i < y_size*(periods+y_kmin); i++) + ya[i] = y[i]; + slowc_save = slowc; + bksub(tbreak, last_period, Size, slowc_lbx); + End_GE(); +} + +void +Interpreter::Check_and_Correct_Previous_Iteration(int y_size, int size) +{ + if (isnan(res1) || isinf(res1) || (res2 > g0 && iter > 0)) + { + while (isnan(res1) || isinf(res1)) + { + prev_slowc_save = slowc_save; + slowc_save /= 1.1; + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; + } + compute_complete(true, res1, res2, max_res, max_res_idx); + } + + while (res2 > g0 && slowc_save > 1e-1) + { + prev_slowc_save = slowc_save; + slowc_save /= 1.5; + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; + } + compute_complete(true, res1, res2, max_res, max_res_idx); + } + if (verbosity >= 2) + mexPrintf("Error: Simulation diverging, trying to correct it using slowc=%f\n", slowc_save); + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; + } + compute_complete(false, res1, res2, max_res, max_res_idx); + } + else + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; + } + slowc_save = slowc; +} + +bool +Interpreter::Simulate_One_Boundary(int block_num, int y_size, int size) +{ + mxArray *b_m = nullptr, *A_m = nullptr, *x0_m = nullptr; + SuiteSparse_long *Ap = nullptr, *Ai = nullptr; + double *Ax = nullptr, *b = nullptr; + int preconditioner = 1; + + try_at_iteration = 0; + Clear_u(); + bool singular_system = false; + u_count_alloc_save = u_count_alloc; + + if (isnan(res1) || isinf(res1)) + { +#ifdef DEBUG + for (int j = 0; j < y_size; j++) + { + bool select = false; + for (int i = 0; i < size; i++) + if (j == index_vara[i]) + { + select = true; + break; + } + if (select) + mexPrintf("-> variable %s (%d) at time %d = %f direction = %f\n", get_variable(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); + else + mexPrintf(" variable %s (%d) at time %d = %f direction = %f\n", get_variable(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); + } +#endif + if (steady_state) + { + if (verbosity >= 1) + { + if (iter == 0) + mexPrintf(" the initial values of endogenous variables are too far from the solution.\nChange them!\n"); + else + mexPrintf(" dynare cannot improve the simulation in block %d at time %d (variable %d)\n", block_num+1, it_+1, index_vara[max_res_idx]+1); + mexEvalString("drawnow;"); + } + } + else + { + if (iter == 0) + throw FatalException{"In Simulate_One_Boundary, The initial values of endogenous variables are too far from the solution. Change them!"}; + else + throw FatalException{"In Simulate_One_Boundary, Dynare cannot improve the simulation in block " + + to_string(block_num+1) + " at time " + to_string(it_+1) + + " (variable " + to_string(index_vara[max_res_idx]+1)}; + } + } + + if (verbosity >= 1) + { + if (steady_state) + { + switch (solve_algo) + { + case 5: + mexPrintf("MODEL STEADY STATE: (method=Sparse Gaussian Elimination)\n"); + break; + case 6: + mexPrintf("MODEL STEADY STATE: (method=Sparse LU)\n"); + break; + case 7: + mexPrintf(preconditioner_print_out("MODEL STEADY STATE: (method=GMRES)\n", preconditioner, true).c_str()); + break; + case 8: + mexPrintf(preconditioner_print_out("MODEL STEADY STATE: (method=BiCGStab)\n", preconditioner, true).c_str()); + break; + } + } + + mexPrintf("------------------------------------\n"); + mexPrintf(" Iteration no. %d\n", iter+1); + mexPrintf(" Inf-norm error = %.3e\n", static_cast<double>(max_res)); + mexPrintf(" 2-norm error = %.3e\n", static_cast<double>(sqrt(res2))); + mexPrintf(" 1-norm error = %.3e\n", static_cast<double>(res1)); + mexPrintf("------------------------------------\n"); + } + bool zero_solution; + + if ((solve_algo == 5 && steady_state) || (stack_solve_algo == 5 && !steady_state)) + Simple_Init(size, IM_i, zero_solution); + else + { + x0_m = mxCreateDoubleMatrix(size, 1, mxREAL); + if (!x0_m) + throw FatalException{"In Simulate_One_Boundary, can't allocate x0_m vector"}; + if (!((solve_algo == 6 && steady_state) + || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 + || stack_solve_algo == 6) && !steady_state))) + { + b_m = mxCreateDoubleMatrix(size, 1, mxREAL); + if (!b_m) + throw FatalException{"In Simulate_One_Boundary, can't allocate b_m vector"}; + A_m = mxCreateSparse(size, size, min(static_cast<int>(IM_i.size()*2), size * size), mxREAL); + if (!A_m) + throw FatalException{"In Simulate_One_Boundary, can't allocate A_m matrix"}; + Init_Matlab_Sparse_Simple(size, IM_i, A_m, b_m, zero_solution, x0_m); + } + else + { + Init_UMFPACK_Sparse_Simple(size, IM_i, &Ap, &Ai, &Ax, &b, zero_solution, x0_m); + if (Ap_save[size] != Ap[size]) + { + mxFree(Ai_save); + mxFree(Ax_save); + Ai_save = static_cast<SuiteSparse_long *>(mxMalloc(Ap[size] * sizeof(SuiteSparse_long))); + test_mxMalloc(Ai_save, __LINE__, __FILE__, __func__, Ap[size] * sizeof(SuiteSparse_long)); + Ax_save = static_cast<double *>(mxMalloc(Ap[size] * sizeof(double))); + test_mxMalloc(Ax_save, __LINE__, __FILE__, __func__, Ap[size] * sizeof(double)); + } + copy_n(Ap, size + 1, Ap_save); + copy_n(Ai, Ap[size], Ai_save); + copy_n(Ax, Ap[size], Ax_save); + copy_n(b, size, b_save); + } + } + if (zero_solution) + for (int i = 0; i < size; i++) + { + int eq = index_vara[i]; + double yy = -(y[eq+it_*y_size]); + direction[eq] = yy; + y[eq+it_*y_size] += slowc * yy; + } + else + { + if ((solve_algo == 5 && steady_state) || (stack_solve_algo == 5 && !steady_state)) + singular_system = Solve_ByteCode_Sparse_GaussianElimination(size, block_num, it_); + else if ((solve_algo == 7 && steady_state) || (stack_solve_algo == 2 && !steady_state)) + Solve_Matlab_GMRES(A_m, b_m, size, slowc, block_num, false, it_, x0_m); + else if ((solve_algo == 8 && steady_state) || (stack_solve_algo == 3 && !steady_state)) + Solve_Matlab_BiCGStab(A_m, b_m, size, slowc, block_num, false, it_, x0_m, preconditioner); + else if ((solve_algo == 6 && steady_state) || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 || stack_solve_algo == 6) && !steady_state)) + { + Solve_LU_UMFPack(Ap, Ai, Ax, b, size, size, slowc, false, it_); + mxDestroyArray(x0_m); + } + } + return singular_system; +} + +bool +Interpreter::solve_linear(int block_num, int y_size, int size, int iter) +{ + bool cvg = false; + compute_complete(false, res1, res2, max_res, max_res_idx); + cvg = (max_res < solve_tolf); + if (!cvg || isnan(res1) || isinf(res1)) + { + if (iter) + Check_and_Correct_Previous_Iteration(y_size, size); + bool singular_system = Simulate_One_Boundary(block_num, y_size, size); + if (singular_system && verbosity >= 1) + Singular_display(block_num, size); + } + return cvg; +} + +void +Interpreter::solve_non_linear(int block_num, int y_size, int size) +{ + max_res_idx = 0; + bool cvg = false; + iter = 0; + glambda2 = g0 = very_big; + while (!cvg && iter < maxit_) + { + cvg = solve_linear(block_num, y_size, size, iter); + g0 = res2; + iter++; + } + if (!cvg) + { + if (steady_state) + throw FatalException{"In Solve Forward/Backward Complete, convergence not achieved in block " + + to_string(block_num+1) + ", after " + to_string(iter) + + " iterations"}; + else + throw FatalException{"In Solve Forward/Backward Complete, convergence not achieved in block " + + to_string(block_num+1) + ", at time " + to_string(it_) + + ", after " + to_string(iter) + " iterations"}; + } +} + +void +Interpreter::Simulate_Newton_One_Boundary(bool forward) +{ + g1 = static_cast<double *>(mxMalloc(size*size*sizeof(double))); + test_mxMalloc(g1, __LINE__, __FILE__, __func__, size*size*sizeof(double)); + r = static_cast<double *>(mxMalloc(size*sizeof(double))); + test_mxMalloc(r, __LINE__, __FILE__, __func__, size*sizeof(double)); + iter = 0; + if ((solve_algo == 6 && steady_state) + || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 || stack_solve_algo == 6) && !steady_state)) + { + Ap_save = static_cast<SuiteSparse_long *>(mxMalloc((size + 1) * sizeof(SuiteSparse_long))); + test_mxMalloc(Ap_save, __LINE__, __FILE__, __func__, (size + 1) * sizeof(SuiteSparse_long)); + Ap_save[size] = 0; + Ai_save = static_cast<SuiteSparse_long *>(mxMalloc(1 * sizeof(SuiteSparse_long))); + test_mxMalloc(Ai_save, __LINE__, __FILE__, __func__, 1 * sizeof(SuiteSparse_long)); + Ax_save = static_cast<double *>(mxMalloc(1 * sizeof(double))); + test_mxMalloc(Ax_save, __LINE__, __FILE__, __func__, 1 * sizeof(double)); + b_save = static_cast<double *>(mxMalloc((size) * sizeof(SuiteSparse_long))); + test_mxMalloc(b_save, __LINE__, __FILE__, __func__, (size) * sizeof(SuiteSparse_long)); + } + if (steady_state) + { + it_ = 0; + if (!is_linear) + solve_non_linear(block_num, y_size, size); + else + solve_linear(block_num, y_size, size, 0); + } + else if (forward) + { + if (!is_linear) + for (it_ = y_kmin; it_ < periods+y_kmin; it_++) + solve_non_linear(block_num, y_size, size); + else + for (it_ = y_kmin; it_ < periods+y_kmin; it_++) + solve_linear(block_num, y_size, size, 0); + } + else + { + if (!is_linear) + for (it_ = periods+y_kmin-1; it_ >= y_kmin; it_--) + solve_non_linear(block_num, y_size, size); + else + for (it_ = periods+y_kmin-1; it_ >= y_kmin; it_--) + solve_linear(block_num, y_size, size, 0); + } + if ((solve_algo == 6 && steady_state) + || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 || stack_solve_algo == 6) && !steady_state)) + { + mxFree(Ap_save); + mxFree(Ai_save); + mxFree(Ax_save); + mxFree(b_save); + } + mxFree(g1); + mxFree(r); +} + +string +Interpreter::preconditioner_print_out(string s, int preconditioner, bool ss) +{ + int n = s.length(); + string tmp = ", preconditioner="; + switch (preconditioner) + { + case 0: + if (ss) + tmp.append("Jacobi on static jacobian"); + else + tmp.append("Jacobi on dynamic jacobian"); + break; + case 1: + if (ss) + tmp.append("incomplete lutp on static jacobian"); + else + tmp.append("incomplete lu0 on dynamic jacobian"); + break; + case 2: + tmp.append("incomplete lutp on dynamic jacobian"); + break; + case 3: + tmp.append("lu on static jacobian"); + break; + } + s.insert(n - 2, tmp); + return s; +} + +void +Interpreter::Simulate_Newton_Two_Boundaries(int blck, int y_size, int y_kmin, int y_kmax,int Size, int periods, bool cvg, int minimal_solving_periods, int stack_solve_algo, const vector_table_conditional_local_type &vector_table_conditional_local) +{ + double top = 0.5; + double bottom = 0.1; + int preconditioner = 2; + if (start_compare == 0) + start_compare = y_kmin; + u_count_alloc_save = u_count_alloc; + auto t1 { chrono::high_resolution_clock::now() }; + nop1 = 0; + mxArray *b_m = nullptr, *A_m = nullptr, *x0_m = nullptr; + double *Ax = nullptr, *b; + SuiteSparse_long *Ap = nullptr, *Ai = nullptr; + + if (isnan(res1) || isinf(res1) || (res2 > 12*g0 && iter > 0)) + { + if (iter == 0 || fabs(slowc_save) < 1e-8) + { + if (verbosity >= 2) + mexPrintf("res1 = %f, res2 = %f g0 = %f iter = %d\n", res1, res2, g0, iter); + for (int j = 0; j < y_size; j++) + { + bool select = false; + for (int i = 0; i < Size; i++) + if (j == index_vara[i]) + { + select = true; + break; + } + if (verbosity >= 2) + { + if (select) + mexPrintf("-> variable %s (%d) at time %d = %f direction = %f\n", symbol_table.getName(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); + else + mexPrintf(" variable %s (%d) at time %d = %f direction = %f\n", symbol_table.getName(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); + } + } + if (iter == 0) + throw FatalException{"In Simulate_Newton_Two_Boundaries, the initial values of endogenous variables are too far from the solution. Change them!"}; + else + throw FatalException{"In Simulate_Newton_Two_Boundaries, dynare cannot improve the simulation in block " + + to_string(blck+1) + " at time " + to_string(it_+1) + + " (variable " + to_string(index_vara[max_res_idx]+1) + + " = " + to_string(max_res) + ")"}; + } + if (!(isnan(res1) || isinf(res1)) && !(isnan(g0) || isinf(g0)) + && (stack_solve_algo == 4 || stack_solve_algo == 5)) + { + if (try_at_iteration == 0) + { + prev_slowc_save = slowc_save; + slowc_save = max(-gp0 / (2 * (res2 - g0 - gp0)), bottom); + } + else + { + double t1 = res2 - gp0 * slowc_save - g0; + double t2 = glambda2 - gp0 * prev_slowc_save - g0; + double a = (1/(slowc_save * slowc_save) * t1 + - 1/(prev_slowc_save * prev_slowc_save) * t2) + / (slowc_save - prev_slowc_save); + double b = (-prev_slowc_save/(slowc_save * slowc_save) * t1 + + slowc_save/(prev_slowc_save * prev_slowc_save) * t2) + / (slowc_save - prev_slowc_save); + prev_slowc_save = slowc_save; + slowc_save = max(min(-b + sqrt(b*b - 3 * a * gp0) / (3 * a), + top * slowc_save), bottom * slowc_save); + } + glambda2 = res2; + try_at_iteration++; + if (slowc_save <= bottom) + { + for (int i = 0; i < y_size*(periods+y_kmin); i++) + y[i] = ya[i]+direction[i]; + g0 = res2; + gp0 = -res2; + try_at_iteration = 0; + iter--; + return; + } + } + else + { + prev_slowc_save = slowc_save; + slowc_save /= 1.05; + } + if (verbosity >= 2) + { + if (isnan(res1) || isinf(res1)) + mexPrintf("The model cannot be evaluated, trying to correct it using slowc=%f\n", slowc_save); + else + mexPrintf("Simulation diverging, trying to correct it using slowc=%f\n", slowc_save); + } + for (int i = 0; i < y_size*(periods+y_kmin); i++) + y[i] = ya[i]+slowc_save*direction[i]; + iter--; + return; + } + u_count += u_count_init; + if (stack_solve_algo == 5) + { + if (alt_symbolic && alt_symbolic_count < alt_symbolic_count_max) + { + if (verbosity >= 2) + mexPrintf("Pivoting method will be applied only to the first periods.\n"); + alt_symbolic = false; + symbolic = true; + markowitz_c = markowitz_c_s; + alt_symbolic_count++; + } + if (res1/res1a-1 > -0.3 && symbolic && iter > 0) + { + if (restart > 2) + { + if (verbosity >= 2) + mexPrintf("Divergence or slowdown occurred during simulation.\nIn the next iteration, pivoting method will be applied to all periods.\n"); + symbolic = false; + alt_symbolic = true; + markowitz_c_s = markowitz_c; + markowitz_c = 0; + } + else + { + if (verbosity >= 2) + mexPrintf("Divergence or slowdown occurred during simulation.\nIn the next iteration, pivoting method will be applied for a longer period.\n"); + start_compare = min(tbreak_g, periods); + restart++; + } + } + else + { + start_compare = max(y_kmin, minimal_solving_periods); + restart = 0; + } + } + res1a = res1; + if (verbosity >= 1) + { + if (iter == 0) + { + switch (stack_solve_algo) + { + 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; + case 3: + mexPrintf(preconditioner_print_out("MODEL SIMULATION: (method=BiCGStab)\n", preconditioner, false).c_str()); + break; + case 4: + mexPrintf("MODEL SIMULATION: (method=Sparse LU & optimal path length)\n"); + break; + case 5: + mexPrintf("MODEL SIMULATION: (method=Sparse Gaussian Elimination)\n"); + break; + } + } + mexPrintf("------------------------------------\n"); + mexPrintf(" Iteration no. %d\n", iter+1); + mexPrintf(" Inf-norm error = %.3e\n", static_cast<double>(max_res)); + mexPrintf(" 2-norm error = %.3e\n", static_cast<double>(sqrt(res2))); + mexPrintf(" 1-norm error = %.3e\n", static_cast<double>(res1)); + mexPrintf("------------------------------------\n"); + mexEvalString("drawnow;"); + } + if (cvg) + return; + else + { + if (stack_solve_algo == 5) + Init_GE(periods, y_kmin, y_kmax, Size, IM_i); + else + { + x0_m = mxCreateDoubleMatrix(periods*Size, 1, mxREAL); + if (!x0_m) + throw FatalException{"In Simulate_Newton_Two_Boundaries, can't allocate x0_m vector"}; + if (stack_solve_algo == 0 || stack_solve_algo == 4) + Init_UMFPACK_Sparse(periods, y_kmin, y_kmax, Size, IM_i, &Ap, &Ai, &Ax, &b, x0_m, vector_table_conditional_local, blck); + else + { + b_m = mxCreateDoubleMatrix(periods*Size, 1, mxREAL); + if (!b_m) + throw FatalException{"In Simulate_Newton_Two_Boundaries, can't allocate b_m vector"}; + if (stack_solve_algo != 0 && stack_solve_algo != 4) + { + A_m = mxCreateSparse(periods*Size, periods*Size, IM_i.size()* periods*2, mxREAL); + if (!A_m) + throw FatalException{"In Simulate_Newton_Two_Boundaries, can't allocate A_m matrix"}; + } + Init_Matlab_Sparse(periods, y_kmin, y_kmax, Size, IM_i, A_m, b_m, x0_m); + } + } + if (stack_solve_algo == 0 || stack_solve_algo == 4) + { + Solve_LU_UMFPack(Ap, Ai, Ax, b, Size * periods, Size, slowc, true, 0, vector_table_conditional_local); + mxDestroyArray(x0_m); + } + else if (stack_solve_algo == 1 || stack_solve_algo == 6) + { + Solve_Matlab_Relaxation(A_m, b_m, Size, slowc); + mxDestroyArray(x0_m); + } + else if (stack_solve_algo == 2) + Solve_Matlab_GMRES(A_m, b_m, Size, slowc, blck, true, 0, x0_m); + else if (stack_solve_algo == 3) + Solve_Matlab_BiCGStab(A_m, b_m, Size, slowc, blck, true, 0, x0_m, 1); + else if (stack_solve_algo == 5) + Solve_ByteCode_Symbolic_Sparse_GaussianElimination(Size, symbolic, blck); + } + using FloatSeconds = chrono::duration<double, chrono::seconds::period>; + auto t2 { chrono::high_resolution_clock::now() }; + if (verbosity >= 1) + { + mexPrintf("(** %.2f seconds **)\n", FloatSeconds{t2 - t1}.count()); + mexEvalString("drawnow;"); + } + if (!steady_state && stack_solve_algo == 4) + { + double ax = -0.1, bx = 1.1, cx = 0.5, fa, fb, fc, xmin; + + if (!mnbrak(&ax, &bx, &cx, &fa, &fb, &fc)) + return; + if (!golden(ax, bx, cx, 1e-1, solve_tolf, &xmin)) + return; + slowc = xmin; + if (verbosity >= 1) + { + auto t3 { chrono::high_resolution_clock::now() }; + mexPrintf("(** %.2f seconds **)\n", FloatSeconds{t3 - t2}.count()); + mexEvalString("drawnow;"); + } + } + if (tbreak_g == 0) + tbreak_g = periods; +} + +void +Interpreter::fixe_u(double **u, int u_count_int, int max_lag_plus_max_lead_plus_1) +{ + u_count = u_count_int * periods; + u_count_alloc = 2*u_count; +#ifdef DEBUG + mexPrintf("fixe_u : alloc(%d double)\n", u_count_alloc); +#endif + *u = static_cast<double *>(mxMalloc(u_count_alloc*sizeof(double))); + test_mxMalloc(*u, __LINE__, __FILE__, __func__, u_count_alloc*sizeof(double)); +#ifdef DEBUG + mexPrintf("*u=%d\n", *u); +#endif + fill_n(*u, u_count_alloc, 0); + u_count_init = max_lag_plus_max_lead_plus_1; +} diff --git a/mex/sources/bytecode/Interpreter.hh b/mex/sources/bytecode/Interpreter.hh index 7dacfbe7e2..151ab3c528 100644 --- a/mex/sources/bytecode/Interpreter.hh +++ b/mex/sources/bytecode/Interpreter.hh @@ -23,33 +23,219 @@ #include <vector> #include <string> #include <cstddef> +#include <utility> +#include <map> +#include <tuple> +#include <stack> +#include <fstream> +#include "dynumfpack.h" #include "dynmex.h" #include "ErrorHandling.hh" -#include "SparseMatrix.hh" +#include "Mem_Mngr.hh" +#include "Evaluate.hh" using namespace std; +struct t_save_op_s +{ + short int lag, operat; + int first, second; +}; + +struct s_plan +{ + string var, exo; + int var_num, exo_num; + vector<pair<int, double>> per_value; + vector<double> value; +}; + +struct table_conditional_local_type +{ + bool is_cond; + int var_exo, var_endo; + double constrained_value; +}; +using vector_table_conditional_local_type = vector<table_conditional_local_type>; +using table_conditional_global_type = map<int, vector_table_conditional_local_type>; + +constexpr int IFLD = 0, IFDIV = 1, IFLESS = 2, IFSUB = 3, IFLDZ = 4, IFMUL = 5, IFSTP = 6, IFADD = 7; +constexpr double eps = 1e-15, very_big = 1e24; +constexpr int alt_symbolic_count_max = 1; +constexpr double mem_increasing_factor = 1.1; + constexpr int NO_ERROR_ON_EXIT {0}, ERROR_ON_EXIT {1}; -class Interpreter : public dynSparseMatrix +class Interpreter { private: + double g0, gp0, glambda2; + int try_at_iteration; + + void *Symbolic {nullptr}, *Numeric {nullptr}; + + const BasicSymbolTable &symbol_table; + const bool steady_state; // Whether this is a static or dynamic model + + // Whether to use the block-decomposed version of the bytecode file + bool block_decomposed; + + Evaluate &evaluator; + + fstream SaveCode; + + Mem_Mngr mem_mngr; + vector<int> u_liste; + int *NbNZRow, *NbNZCol; + NonZeroElem **FNZE_R, **FNZE_C; + int u_count_init; + + int *pivot, *pivotk, *pivot_save; + double *pivotv, *pivotva; + int *b; + bool *line_done; + bool symbolic, alt_symbolic; + int alt_symbolic_count; + double markowitz_c_s; + double res1a; + long int nop1; + map<tuple<int, int, int>, int> IM_i; + int u_count_alloc, u_count_alloc_save; + double slowc, slowc_save, prev_slowc_save, markowitz_c; + int *index_equa; // Actually unused + int u_count, tbreak_g; + int iter; + int start_compare; + int restart; + double lu_inc_tol; + + SuiteSparse_long *Ap_save, *Ai_save; + double *Ax_save, *b_save; + + int stack_solve_algo, solve_algo; + int minimal_solving_periods; + int Per_u_, Per_y_; + int maxit_; + double *direction; + double solve_tolf; + // 1-norm error, square of 2-norm error, ∞-norm error + double res1, res2, max_res; + int max_res_idx; + int *index_vara; + + double *y, *ya; + int y_size; + double *T; + int nb_row_x; + int y_kmin, y_kmax, periods; + double *x, *params; + double *u; + double *steady_y; + double *g1, *r, *res; + vector<mxArray *> jacobian_block, jacobian_exo_block, jacobian_det_exo_block; + mxArray *GlobalTemporaryTerms; + int it_; + map<int, double> TEF; + map<pair<int, int>, double> TEFD; + map<tuple<int, int, int>, double> TEFDD; + + // Information about the current block + int block_num; // Index of the current block + int size; // Size of the current block + BlockSimulationType type; + bool is_linear; + int u_count_int; + vector<Block_contain_type> Block_Contain; + + int verbosity; // Corresponds to options_.verbosity + vector<int> previous_block_exogenous; bool global_temporary_terms; bool print; // Whether the “print” command is requested int col_x, col_y; vector<double> residual; + void evaluate_over_periods(bool forward); void solve_simple_one_periods(); void solve_simple_over_periods(bool forward); void compute_complete_2b(bool no_derivatives, double *_res1, double *_res2, double *_max_res, int *_max_res_idx); void initializeTemporaryTerms(bool global_temporary_terms); -protected: void evaluate_a_block(bool initialization, bool single_block, const string &bin_base_name); int simulate_a_block(const vector_table_conditional_local_type &vector_table_conditional_local, bool single_block, const string &bin_base_name); string elastic(string str, unsigned int len, bool left); + void check_for_controlled_exo_validity(int current_block, const vector<s_plan> &sconstrained_extended_path); + pair<bool, vector<int>> MainLoop(const string &bin_basename, bool evaluate, int block, bool constrained, const vector<s_plan> &sconstrained_extended_path, const vector_table_conditional_local_type &vector_table_conditional_local); + void Simulate_Newton_Two_Boundaries(int blck, int y_size, int y_kmin, int y_kmax, int Size, int periods, bool cvg, int minimal_solving_periods, int stack_solve_algo, const vector_table_conditional_local_type &vector_table_conditional_local); + void Simulate_Newton_One_Boundary(bool forward); + void fixe_u(double **u, int u_count_int, int max_lag_plus_max_lead_plus_1); + void Read_SparseMatrix(const string &file_name, int Size, int periods, int y_kmin, int y_kmax, bool two_boundaries, int stack_solve_algo, int solve_algo); + void Singular_display(int block, int Size); + void End_Solver(); + static int find_exo_num(const vector<s_plan> &sconstrained_extended_path, int value); + static int find_int_date(const vector<pair<int, double>> &per_value, int value); + void Init_GE(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM); + void Init_Matlab_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, mxArray *A_m, mxArray *b_m, const mxArray *x0_m) const; + void Init_UMFPACK_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, const mxArray *x0_m, const vector_table_conditional_local_type &vector_table_conditional_local, int block_num) const; + void Init_Matlab_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, const mxArray *A_m, const mxArray *b_m, bool &zero_solution, const mxArray *x0_m) const; + void Init_UMFPACK_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, bool &zero_solution, const mxArray *x0_m) const; + void Simple_Init(int Size, const map<tuple<int, int, int>, int> &IM, bool &zero_solution); + void End_GE(); + bool mnbrak(double *ax, double *bx, double *cx, double *fa, double *fb, double *fc); + bool golden(double ax, double bx, double cx, double tol, double solve_tolf, double *xmin); + void Solve_ByteCode_Symbolic_Sparse_GaussianElimination(int Size, bool symbolic, int Block_number); + bool Solve_ByteCode_Sparse_GaussianElimination(int Size, int blck, int it_); + void Solve_Matlab_Relaxation(mxArray *A_m, mxArray *b_m, unsigned int Size, double slowc_l); + static void Print_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, int n); + static void Printfull_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, const double *b, int n); + static void PrintM(int n, const double *Ax, const mwIndex *Ap, const mwIndex *Ai); + void Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_, const vector_table_conditional_local_type &vector_table_conditional_local); + void Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_); + + void End_Matlab_LU_UMFPack(); + void Solve_Matlab_GMRES(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m); + void Solve_Matlab_BiCGStab(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m, int precond); + void Check_and_Correct_Previous_Iteration(int y_size, int size); + bool Simulate_One_Boundary(int blck, int y_size, int size); + bool solve_linear(int block_num, int y_size, int size, int iter); + void solve_non_linear(int block_num, int y_size, int size); + string preconditioner_print_out(string s, int preconditioner, bool ss); + bool compare(int *save_op, int *save_opa, int *save_opaa, int beg_t, int periods, long nop4, int Size); + void Insert(int r, int c, int u_index, int lag_index); + void Delete(int r, int c); + int At_Row(int r, NonZeroElem **first) const; + int At_Pos(int r, int c, NonZeroElem **first) const; + int At_Col(int c, NonZeroElem **first) const; + int At_Col(int c, int lag, NonZeroElem **first) const; + int NRow(int r) const; + int NCol(int c) const; + int Union_Row(int row1, int row2) const; + int Get_u(); + void Delete_u(int pos); + void Clear_u(); + + int complete(int beg_t, int Size, int periods, int *b); + void bksub(int tbreak, int last_period, int Size, double slowc_l); + void simple_bksub(int it_, int Size, double slowc_l); + // Computes Aᵀ where A is are sparse. The result is sparse. + static mxArray *Sparse_transpose(const mxArray *A_m); + // Computes Aᵀ·B where A and B are sparse. The result is sparse. + static mxArray *Sparse_mult_SAT_SB(const mxArray *A_m, const mxArray *B_m); + // Computes Aᵀ·B where A is sparse and B is dense. The result is sparse. + static mxArray *Sparse_mult_SAT_B(const mxArray *A_m, const mxArray *B_m); + // Computes Aᵀ·B where A is sparse and B is dense. The result is dense. + static mxArray *mult_SAT_B(const mxArray *A_m, const mxArray *B_m); + // Computes A−B where A and B are sparse. The result is sparse. + static mxArray *Sparse_subtract_SA_SB(const mxArray *A_m, const mxArray *B_m); + // Computes A−B where A and B are dense. The result is dense. + static mxArray *subtract_A_B(const mxArray *A_m, const mxArray *B_m); + + void compute_block_time(int Per_u_, bool evaluate, bool no_derivatives); + bool compute_complete(bool no_derivatives, double &res1, double &res2, double &max_res, int &max_res_idx); + + bool compute_complete(double lambda, double *crit); + public: Interpreter(Evaluate &evaluator_arg, double *params_arg, double *y_arg, double *ya_arg, double *x_arg, double *steady_y_arg, double *direction_arg, int y_size_arg, @@ -60,8 +246,7 @@ public: bool steady_state_arg, bool block_decomposed_arg, int col_x_arg, int col_y_arg, const BasicSymbolTable &symbol_table_arg, int verbosity_arg); pair<bool, vector<int>> extended_path(const string &file_name, bool evaluate, int block, int nb_periods, const vector<s_plan> &sextended_path, const vector<s_plan> &sconstrained_extended_path, const vector<string> &dates, const table_conditional_global_type &table_conditional_global); pair<bool, vector<int>> compute_blocks(const string &file_name, bool evaluate, int block); - void check_for_controlled_exo_validity(int current_block, const vector<s_plan> &sconstrained_extended_path); - pair<bool, vector<int>> MainLoop(const string &bin_basename, bool evaluate, int block, bool constrained, const vector<s_plan> &sconstrained_extended_path, const vector_table_conditional_local_type &vector_table_conditional_local); + void Close_SaveCode(); inline mxArray * get_jacob(int block_num) const diff --git a/mex/sources/bytecode/SparseMatrix.cc b/mex/sources/bytecode/SparseMatrix.cc deleted file mode 100644 index fca24529a2..0000000000 --- a/mex/sources/bytecode/SparseMatrix.cc +++ /dev/null @@ -1,4172 +0,0 @@ -/* - * Copyright © 2007-2023 Dynare Team - * - * This file is part of Dynare. - * - * Dynare is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Dynare is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Dynare. If not, see <https://www.gnu.org/licenses/>. - */ - -#include <sstream> -#include <algorithm> -#include <filesystem> -#include <type_traits> -#include <chrono> - -#include "SparseMatrix.hh" - -dynSparseMatrix::dynSparseMatrix(Evaluate &evaluator_arg, int y_size_arg, int y_kmin_arg, int y_kmax_arg, bool steady_state_arg, bool block_decomposed_arg, int periods_arg, - int minimal_solving_periods_arg, const BasicSymbolTable &symbol_table_arg, int verbosity_arg) : - symbol_table {symbol_table_arg}, - steady_state {steady_state_arg}, - block_decomposed {block_decomposed_arg}, - evaluator {evaluator_arg}, - minimal_solving_periods {minimal_solving_periods_arg}, - y_size {y_size_arg}, - y_kmin {y_kmin_arg}, - y_kmax {y_kmax_arg}, - periods {periods_arg}, - verbosity {verbosity_arg} -{ - pivotva = nullptr; - mem_mngr.init_Mem(); - symbolic = true; - alt_symbolic = false; - alt_symbolic_count = 0; - res1a = 9.0e60; - tbreak_g = 0; - start_compare = 0; - restart = 0; - IM_i.clear(); - lu_inc_tol = 1e-10; - Symbolic = nullptr; - Numeric = nullptr; -} - -int -dynSparseMatrix::NRow(int r) const -{ - return NbNZRow[r]; -} - -int -dynSparseMatrix::NCol(int c) const -{ - return NbNZCol[c]; -} - -int -dynSparseMatrix::At_Row(int r, NonZeroElem **first) const -{ - *first = FNZE_R[r]; - return NbNZRow[r]; -} - -int -dynSparseMatrix::Union_Row(int row1, int row2) const -{ - NonZeroElem *first1, *first2; - int n1 = At_Row(row1, &first1); - int n2 = At_Row(row2, &first2); - int i1 = 0, i2 = 0, nb_elem = 0; - while (i1 < n1 && i2 < n2) - { - if (first1->c_index == first2->c_index) - { - nb_elem++; - i1++; - i2++; - first1 = first1->NZE_R_N; - first2 = first2->NZE_R_N; - } - else if (first1->c_index < first2->c_index) - { - nb_elem++; - i1++; - first1 = first1->NZE_R_N; - } - else - { - nb_elem++; - i2++; - first2 = first2->NZE_R_N; - } - } - return nb_elem; -} - -int -dynSparseMatrix::At_Pos(int r, int c, NonZeroElem **first) const -{ - *first = FNZE_R[r]; - while ((*first)->c_index != c) - *first = (*first)->NZE_R_N; - return NbNZRow[r]; -} - -int -dynSparseMatrix::At_Col(int c, NonZeroElem **first) const -{ - *first = FNZE_C[c]; - return NbNZCol[c]; -} - -int -dynSparseMatrix::At_Col(int c, int lag, NonZeroElem **first) const -{ - *first = FNZE_C[c]; - int i = 0; - while ((*first)->lag_index != lag && *first) - *first = (*first)->NZE_C_N; - if (*first) - { - NonZeroElem *firsta = *first; - if (!firsta->NZE_C_N) - i++; - else - { - while (firsta->lag_index == lag && firsta->NZE_C_N) - { - firsta = firsta->NZE_C_N; - i++; - } - if (firsta->lag_index == lag) - i++; - } - } - return i; -} - -void -dynSparseMatrix::Delete(int r, int c) -{ - NonZeroElem *first = FNZE_R[r], *firsta = nullptr; - - while (first->c_index != c) - { - firsta = first; - first = first->NZE_R_N; - } - if (firsta) - firsta->NZE_R_N = first->NZE_R_N; - if (first == FNZE_R[r]) - FNZE_R[r] = first->NZE_R_N; - NbNZRow[r]--; - - first = FNZE_C[c]; - firsta = nullptr; - while (first->r_index != r) - { - firsta = first; - first = first->NZE_C_N; - } - - if (firsta) - firsta->NZE_C_N = first->NZE_C_N; - if (first == FNZE_C[c]) - FNZE_C[c] = first->NZE_C_N; - - u_liste.push_back(first->u_index); - mem_mngr.mxFree_NZE(first); - NbNZCol[c]--; -} - -void -dynSparseMatrix::Insert(int r, int c, int u_index, int lag_index) -{ - NonZeroElem *firstn, *first, *firsta, *a; - firstn = mem_mngr.mxMalloc_NZE(); - first = FNZE_R[r]; - firsta = nullptr; - while (first->c_index < c && (a = first->NZE_R_N)) - { - firsta = first; - first = a; - } - firstn->u_index = u_index; - firstn->r_index = r; - firstn->c_index = c; - firstn->lag_index = lag_index; - if (first->c_index > c) - { - if (first == FNZE_R[r]) - FNZE_R[r] = firstn; - if (firsta) - firsta->NZE_R_N = firstn; - firstn->NZE_R_N = first; - } - else - { - first->NZE_R_N = firstn; - firstn->NZE_R_N = nullptr; - } - NbNZRow[r]++; - first = FNZE_C[c]; - firsta = nullptr; - while (first->r_index < r && (a = first->NZE_C_N)) - { - firsta = first; - first = a; - } - if (first->r_index > r) - { - if (first == FNZE_C[c]) - FNZE_C[c] = firstn; - if (firsta) - firsta->NZE_C_N = firstn; - firstn->NZE_C_N = first; - } - else - { - first->NZE_C_N = firstn; - firstn->NZE_C_N = nullptr; - } - - NbNZCol[c]++; -} - -void -dynSparseMatrix::Close_SaveCode() -{ - SaveCode.close(); -} - -void -dynSparseMatrix::Read_SparseMatrix(const string &file_name, int Size, int periods, int y_kmin, int y_kmax, bool two_boundaries, int stack_solve_algo, int solve_algo) -{ - unsigned int eq, var; - int lag; - mem_mngr.fixe_file_name(file_name); - if (!SaveCode.is_open()) - { - filesystem::path binfile {file_name + "/model/bytecode/" + (block_decomposed ? "block/" : "") - + (steady_state ? "static" : "dynamic") + ".bin"}; - SaveCode.open(binfile, ios::in | ios::binary); - if (!SaveCode.is_open()) - throw FatalException{"In Read_SparseMatrix, " + binfile.string() + " cannot be opened"}; - } - IM_i.clear(); - if (two_boundaries) - { - if (stack_solve_algo == 5) - { - for (int i = 0; i < u_count_init-Size; i++) - { - int val; - SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); - SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); - SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); - SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); - IM_i[{ eq, var, lag }] = val; - } - for (int j = 0; j < Size; j++) - IM_i[{ j, Size*(periods+y_kmax), 0 }] = j; - } - else if ((stack_solve_algo >= 0 && stack_solve_algo <= 4) - || stack_solve_algo == 6) - { - for (int i = 0; i < u_count_init-Size; i++) - { - int val; - SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); - SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); - SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); - SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); - IM_i[{ var - lag*Size, -lag, eq }] = val; - } - for (int j = 0; j < Size; j++) - IM_i[{ Size*(periods+y_kmax), 0, j }] = j; - } - else - throw FatalException{"Invalid value for solve_algo or stack_solve_algo"}; - } - else - { - if ((stack_solve_algo == 5 && !steady_state) || (solve_algo == 5 && steady_state)) - { - for (int i = 0; i < u_count_init; i++) - { - int val; - SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); - SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); - SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); - SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); - IM_i[{ eq, var, lag }] = val; - } - } - else if ((((stack_solve_algo >= 0 && stack_solve_algo <= 4) - || stack_solve_algo == 6) && !steady_state) - || ((solve_algo >= 6 || solve_algo <= 8) && steady_state)) - { - for (int i = 0; i < u_count_init; i++) - { - int val; - SaveCode.read(reinterpret_cast<char *>(&eq), sizeof(eq)); - SaveCode.read(reinterpret_cast<char *>(&var), sizeof(var)); - SaveCode.read(reinterpret_cast<char *>(&lag), sizeof(lag)); - SaveCode.read(reinterpret_cast<char *>(&val), sizeof(val)); - IM_i[{ var - lag*Size, -lag, eq }] = val; - } - } - else - throw FatalException{"Invalid value for solve_algo or stack_solve_algo"}; - } - index_vara = static_cast<int *>(mxMalloc(Size*(periods+y_kmin+y_kmax)*sizeof(int))); - test_mxMalloc(index_vara, __LINE__, __FILE__, __func__, Size*(periods+y_kmin+y_kmax)*sizeof(int)); - for (int j = 0; j < Size; j++) - SaveCode.read(reinterpret_cast<char *>(&index_vara[j]), sizeof(*index_vara)); - if (periods+y_kmin+y_kmax > 1) - for (int i = 1; i < periods+y_kmin+y_kmax; i++) - for (int j = 0; j < Size; j++) - index_vara[j+Size*i] = index_vara[j+Size*(i-1)] + y_size; - index_equa = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(index_equa, __LINE__, __FILE__, __func__, Size*sizeof(int)); - for (int j = 0; j < Size; j++) - SaveCode.read(reinterpret_cast<char *>(&index_equa[j]), sizeof(*index_equa)); -} - -void -dynSparseMatrix::Simple_Init(int Size, const map<tuple<int, int, int>, int> &IM, bool &zero_solution) -{ - pivot = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivot, __LINE__, __FILE__, __func__, Size*sizeof(int)); - pivot_save = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivot_save, __LINE__, __FILE__, __func__, Size*sizeof(int)); - pivotk = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivotk, __LINE__, __FILE__, __func__, Size*sizeof(int)); - pivotv = static_cast<double *>(mxMalloc(Size*sizeof(double))); - test_mxMalloc(pivotv, __LINE__, __FILE__, __func__, Size*sizeof(double)); - pivotva = static_cast<double *>(mxMalloc(Size*sizeof(double))); - test_mxMalloc(pivotva, __LINE__, __FILE__, __func__, Size*sizeof(double)); - b = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(b, __LINE__, __FILE__, __func__, Size*sizeof(int)); - line_done = static_cast<bool *>(mxMalloc(Size*sizeof(bool))); - test_mxMalloc(line_done, __LINE__, __FILE__, __func__, Size*sizeof(bool)); - - mem_mngr.init_CHUNK_BLCK_SIZE(u_count); - int i = Size*sizeof(NonZeroElem *); - FNZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(FNZE_R, __LINE__, __FILE__, __func__, i); - FNZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(FNZE_C, __LINE__, __FILE__, __func__, i); - auto **temp_NZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(temp_NZE_R, __LINE__, __FILE__, __func__, i); - auto **temp_NZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(temp_NZE_C, __LINE__, __FILE__, __func__, i); - i = Size*sizeof(int); - NbNZRow = static_cast<int *>(mxMalloc(i)); - test_mxMalloc(NbNZRow, __LINE__, __FILE__, __func__, i); - NbNZCol = static_cast<int *>(mxMalloc(i)); - test_mxMalloc(NbNZCol, __LINE__, __FILE__, __func__, i); - for (i = 0; i < Size; i++) - { - line_done[i] = false; - FNZE_C[i] = nullptr; - FNZE_R[i] = nullptr; - temp_NZE_C[i] = nullptr; - temp_NZE_R[i] = nullptr; - NbNZRow[i] = 0; - NbNZCol[i] = 0; - } - int u_count1 = Size; - for (auto &[key, value] : IM) - { - auto &[eq, var, lag] = key; - if (lag == 0) /*Build the index for sparse matrix containing the jacobian : u*/ - { - NbNZRow[eq]++; - NbNZCol[var]++; - NonZeroElem *first = mem_mngr.mxMalloc_NZE(); - first->NZE_C_N = nullptr; - first->NZE_R_N = nullptr; - first->u_index = u_count1; - first->r_index = eq; - first->c_index = var; - first->lag_index = lag; - if (!FNZE_R[eq]) - FNZE_R[eq] = first; - if (!FNZE_C[var]) - FNZE_C[var] = first; - if (temp_NZE_R[eq]) - temp_NZE_R[eq]->NZE_R_N = first; - if (temp_NZE_C[var]) - temp_NZE_C[var]->NZE_C_N = first; - temp_NZE_R[eq] = first; - temp_NZE_C[var] = first; - u_count1++; - } - } - double cum_abs_sum = 0; - for (int i = 0; i < Size; i++) - { - b[i] = i; - cum_abs_sum += fabs(u[i]); - } - if (cum_abs_sum < 1e-20) - zero_solution = true; - else - zero_solution = false; - - mxFree(temp_NZE_R); - mxFree(temp_NZE_C); - u_count = u_count1; -} - -void -dynSparseMatrix::Init_Matlab_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, const mxArray *A_m, const mxArray *b_m, bool &zero_solution, const mxArray *x0_m) const -{ - double *b = mxGetPr(b_m); - if (!b) - throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve b vector"}; - double *x0 = mxGetPr(x0_m); - if (!x0) - throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve x0 vector"}; - mwIndex *Ai = mxGetIr(A_m); - if (!Ai) - throw FatalException{"In Init_Matlab_Sparse_Simple, can't allocate Ai index vector"}; - mwIndex *Aj = mxGetJc(A_m); - if (!Aj) - throw FatalException{"In Init_Matlab_Sparse_Simple, can't allocate Aj index vector"}; - double *A = mxGetPr(A_m); - if (!A) - throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve A matrix"}; - - for (int i = 0; i < y_size*(periods+y_kmin); i++) - ya[i] = y[i]; -#ifdef DEBUG - unsigned int max_nze = mxGetNzmax(A_m); -#endif - unsigned int NZE = 0; - int last_var = 0; - double cum_abs_sum = 0; - for (int i = 0; i < Size; i++) - { - b[i] = u[i]; - cum_abs_sum += fabs(b[i]); - x0[i] = y[i]; - } - if (cum_abs_sum < 1e-20) - zero_solution = true; - else - zero_solution = false; - - Aj[0] = 0; - last_var = 0; - for (auto &[key, index] : IM) - { - auto &[var, ignore, eq] = key; - if (var != last_var) - { - Aj[1+last_var] = NZE; - last_var = var; - } -#ifdef DEBUG - if (index < 0 || index >= u_count_alloc || index > Size + Size*Size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(index) - + ") out of range for u vector max = " - + to_string(Size+Size*Size) - + " allocated = " + to_string(u_count_alloc)}; - if (NZE >= max_nze) - throw FatalException{"In Init_Matlab_Sparse_Simple, exceeds the capacity of A_m sparse matrix"}; -#endif - A[NZE] = u[index]; - Ai[NZE] = eq; - NZE++; -#ifdef DEBUG - if (eq < 0 || eq >= Size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(eq) - + ") out of range for b vector"}; - if (var < 0 || var >= Size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(var) - + ") out of range for index_vara vector"}; - if (index_vara[var] < 0 || index_vara[var] >= y_size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" - + to_string(index_vara[var]) - + ") out of range for y vector max=" + to_string(y_size) - +" (0)"}; -#endif - } - Aj[Size] = NZE; -} - -void -dynSparseMatrix::Init_UMFPACK_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, bool &zero_solution, const mxArray *x0_m) const -{ - *b = static_cast<double *>(mxMalloc(Size * sizeof(double))); - test_mxMalloc(*b, __LINE__, __FILE__, __func__, Size * sizeof(double)); - if (!(*b)) - throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve b vector"}; - double *x0 = mxGetPr(x0_m); - if (!x0) - throw FatalException{"In Init_UMFPACK_Sparse_Simple, can't retrieve x0 vector"}; - *Ap = static_cast<SuiteSparse_long *>(mxMalloc((Size+1) * sizeof(SuiteSparse_long))); - test_mxMalloc(*Ap, __LINE__, __FILE__, __func__, (Size+1) * sizeof(SuiteSparse_long)); - if (!(*Ap)) - throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ap index vector"}; - size_t prior_nz = IM.size(); - *Ai = static_cast<SuiteSparse_long *>(mxMalloc(prior_nz * sizeof(SuiteSparse_long))); - test_mxMalloc(*Ai, __LINE__, __FILE__, __func__, prior_nz * sizeof(SuiteSparse_long)); - if (!(*Ai)) - throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ai index vector"}; - *Ax = static_cast<double *>(mxMalloc(prior_nz * sizeof(double))); - test_mxMalloc(*Ax, __LINE__, __FILE__, __func__, prior_nz * sizeof(double)); - if (!(*Ax)) - throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve Ax matrix"}; - for (int i = 0; i < Size; i++) - { - int eq = index_vara[i]; - ya[eq+it_*y_size] = y[eq+it_*y_size]; - } -#ifdef DEBUG - unsigned int max_nze = prior_nz; //mxGetNzmax(A_m); -#endif - unsigned int NZE = 0; - int last_var = 0; - double cum_abs_sum = 0; - for (int i = 0; i < Size; i++) - { - (*b)[i] = u[i]; - cum_abs_sum += fabs((*b)[i]); - x0[i] = y[i]; - } - if (cum_abs_sum < 1e-20) - zero_solution = true; - else - zero_solution = false; - - (*Ap)[0] = 0; - last_var = 0; - for (auto &[key, index] : IM) - { - auto &[var, ignore, eq] = key; - if (var != last_var) - { - (*Ap)[1+last_var] = NZE; - last_var = var; - } -#ifdef DEBUG - if (index < 0 || index >= u_count_alloc || index > Size + Size*Size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(index) - + ") out of range for u vector max = " - + to_string(Size+Size*Size) - + " allocated = " + to_string(u_count_alloc)}; - if (NZE >= max_nze) - throw FatalException{"In Init_Matlab_Sparse_Simple, exceeds the capacity of A_m sparse matrix"}; -#endif - (*Ax)[NZE] = u[index]; - (*Ai)[NZE] = eq; - NZE++; -#ifdef DEBUG - if (eq < 0 || eq >= Size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(eq) - + ") out of range for b vector"}; - if (var < 0 || var >= Size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" + to_string(var) - + ") out of range for index_vara vector"}; - if (index_vara[var] < 0 || index_vara[var] >= y_size) - throw FatalException{"In Init_Matlab_Sparse_Simple, index (" - + to_string(index_vara[var]) - + ") out of range for y vector max=" + to_string(y_size) - + " (0)"}; -#endif - } - (*Ap)[Size] = NZE; -} - -int -dynSparseMatrix::find_exo_num(const vector<s_plan> &sconstrained_extended_path, int value) -{ - auto it = find_if(sconstrained_extended_path.begin(), sconstrained_extended_path.end(), - [=](auto v) { return v.exo_num == value; }); - if (it != sconstrained_extended_path.end()) - return it - sconstrained_extended_path.begin(); - else - return -1; -} - -int -dynSparseMatrix::find_int_date(const vector<pair<int, double>> &per_value, int value) -{ - auto it = find_if(per_value.begin(), per_value.end(), [=](auto v) { return v.first == value; }); - if (it != per_value.end()) - return it - per_value.begin(); - else - return -1; -} - -void -dynSparseMatrix::Init_UMFPACK_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, const mxArray *x0_m, const vector_table_conditional_local_type &vector_table_conditional_local, int block_num) const -{ - int n = periods * Size; - *b = static_cast<double *>(mxMalloc(n * sizeof(double))); - if (!(*b)) - throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve b vector"}; - double *x0 = mxGetPr(x0_m); - if (!x0) - throw FatalException{"In Init_UMFPACK_Sparse_Simple, can't retrieve x0 vector"}; - *Ap = static_cast<SuiteSparse_long *>(mxMalloc((n+1) * sizeof(SuiteSparse_long))); - test_mxMalloc(*Ap, __LINE__, __FILE__, __func__, (n+1) * sizeof(SuiteSparse_long)); - if (!(*Ap)) - throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ap index vector"}; - size_t prior_nz = IM.size() * periods; - *Ai = static_cast<SuiteSparse_long *>(mxMalloc(prior_nz * sizeof(SuiteSparse_long))); - test_mxMalloc(*Ai, __LINE__, __FILE__, __func__, prior_nz * sizeof(SuiteSparse_long)); - if (!(*Ai)) - throw FatalException{"In Init_UMFPACK_Sparse, can't allocate Ai index vector"}; - *Ax = static_cast<double *>(mxMalloc(prior_nz * sizeof(double))); - test_mxMalloc(*Ax, __LINE__, __FILE__, __func__, prior_nz * sizeof(double)); - if (!(*Ax)) - throw FatalException{"In Init_UMFPACK_Sparse, can't retrieve Ax matrix"}; - for (int i = 0; i < y_size*(periods+y_kmin); i++) - ya[i] = y[i]; - unsigned int NZE = 0; - int last_var = 0; - for (int i = 0; i < periods*Size; i++) - { - (*b)[i] = 0; - x0[i] = y[index_vara[Size*y_kmin+i]]; - } - double *jacob_exo; - int row_x = 0; -#ifdef DEBUG - int col_x; -#endif - if (vector_table_conditional_local.size()) - { - jacob_exo = mxGetPr(jacobian_exo_block[block_num]); - row_x = mxGetM(jacobian_exo_block[block_num]); -#ifdef DEBUG - col_x = mxGetN(jacobian_exo_block[block_num]); -#endif - } - else - jacob_exo = nullptr; -#ifdef DEBUG - int local_index; -#endif - - bool fliped = false; - bool fliped_exogenous_derivatives_updated = false; - int flip_exo; - (*Ap)[0] = 0; - for (int t = 0; t < periods; t++) - { - last_var = -1; - int var = 0; - for (auto &[key, value] : IM) - { - var = get<0>(key); - int eq = get<2>(key)+Size*t; - int lag = -get<1>(key); - int index = value + (t-lag) * u_count_init; - if (var != last_var) - { - (*Ap)[1+last_var + t * Size] = NZE; - last_var = var; - if (var < Size*(periods+y_kmax)) - { - if (t == 0 && vector_table_conditional_local.size()) - { - fliped = vector_table_conditional_local[var].is_cond; - fliped_exogenous_derivatives_updated = false; - } - else - fliped = false; - } - else - fliped = false; - } - if (fliped) - { - if (t == 0 && var < (periods+y_kmax)*Size - && lag == 0 && vector_table_conditional_local.size()) - { - flip_exo = vector_table_conditional_local[var].var_exo; -#ifdef DEBUG - local_index = eq; -#endif - if (!fliped_exogenous_derivatives_updated) - { - fliped_exogenous_derivatives_updated = true; - for (int k = 0; k < row_x; k++) - { - if (jacob_exo[k + row_x*flip_exo] != 0) - { - (*Ax)[NZE] = jacob_exo[k + row_x*flip_exo]; - (*Ai)[NZE] = k; - NZE++; - -#ifdef DEBUG - if (local_index < 0 || local_index >= Size * periods) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(local_index) - + ") out of range for b vector"}; - if (k + row_x*flip_exo < 0 || k + row_x*flip_exo >= row_x * col_x) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(var+Size*(y_kmin+t+lag)) - + ") out of range for jacob_exo vector"}; - if (t+y_kmin+flip_exo*nb_row_x < 0 - || t+y_kmin+flip_exo*nb_row_x >= nb_row_x * this->col_x) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(index_vara[var+Size*(y_kmin+t+lag)]) - + ") out of range for x vector max=" - + to_string(nb_row_x * this->col_x)}; -#endif - u[k] -= jacob_exo[k + row_x*flip_exo] * x[t+y_kmin+flip_exo*nb_row_x]; - } - } - } - } - } - - if (var < (periods+y_kmax)*Size) - { - int ti_y_kmin = -min(t, y_kmin); - int ti_y_kmax = min(periods-(t+1), y_kmax); - int ti_new_y_kmax = min(t, y_kmax); - int ti_new_y_kmin = -min(periods-(t+1), y_kmin); - if (lag <= ti_new_y_kmax && lag >= ti_new_y_kmin) /*Build the index for sparse matrix containing the jacobian : u*/ - { -#ifdef DEBUG - if (NZE >= prior_nz) - throw FatalException{"In Init_UMFPACK_Sparse, exceeds the capacity of allocated sparse matrix"}; -#endif - if (!fliped) - { - (*Ax)[NZE] = u[index]; - (*Ai)[NZE] = eq - lag * Size; - NZE++; - } - else /*if (fliped)*/ - { -#ifdef DEBUG - if (eq - lag * Size < 0 || eq - lag * Size >= Size * periods) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(eq - lag * Size) - + ") out of range for b vector"}; - if (var+Size*(y_kmin+t) < 0 - || var+Size*(y_kmin+t) >= Size*(periods+y_kmin+y_kmax)) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(var+Size*(y_kmin+t)) - + ") out of range for index_vara vector"}; - if (index_vara[var+Size*(y_kmin+t)] < 0 - || index_vara[var+Size*(y_kmin+t)] >= y_size*(periods+y_kmin+y_kmax)) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(index_vara[var+Size*(y_kmin+t)]) - + ") out of range for y vector max=" - + to_string(y_size*(periods+y_kmin+y_kmax))}; -#endif - (*b)[eq - lag * Size] += u[index] * y[index_vara[var+Size*(y_kmin+t)]]; - } - - } - if (lag > ti_y_kmax || lag < ti_y_kmin) - { -#ifdef DEBUG - if (eq < 0 || eq >= Size * periods) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(eq) - + ") out of range for b vector"}; - if (var+Size*(y_kmin+t+lag) < 0 - || var+Size*(y_kmin+t+lag) >= Size*(periods+y_kmin+y_kmax)) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(var+Size*(y_kmin+t+lag)) - + ") out of range for index_vara vector"}; - if (index_vara[var+Size*(y_kmin+t+lag)] < 0 - || index_vara[var+Size*(y_kmin+t+lag)] >= y_size*(periods+y_kmin+y_kmax)) - throw FatalException{"In Init_UMFPACK_Sparse, index (" - + to_string(index_vara[var+Size*(y_kmin+t+lag)]) - + ") out of range for y vector max=" - + to_string(y_size*(periods+y_kmin+y_kmax))}; -#endif - (*b)[eq] += u[index+lag*u_count_init]*y[index_vara[var+Size*(y_kmin+t+lag)]]; - } - } - else /* ...and store it in the u vector*/ - { -#ifdef DEBUG - if (index < 0 || index >= u_count_alloc) - throw FatalException{"In Init_UMFPACK_Sparse, index (" + to_string(index) - + ") out of range for u vector"}; - if (eq < 0 || eq >= (Size*periods)) - throw FatalException{"In Init_UMFPACK_Sparse, index (" + to_string(eq) - + ") out of range for b vector"}; -#endif - (*b)[eq] += u[index]; - } - } - } - (*Ap)[Size*periods] = NZE; -#ifdef DEBUG - mexPrintf("*Ax = ["); - for (int i = 0; i < static_cast<int>(NZE); i++) - mexPrintf("%f ", (*Ax)[i]); - mexPrintf("]\n"); - - mexPrintf("*Ap = ["); - for (int i = 0; i < n+1; i++) - mexPrintf("%d ", (*Ap)[i]); - mexPrintf("]\n"); - - mexPrintf("*Ai = ["); - for (int i = 0; i < static_cast<int>(NZE); i++) - mexPrintf("%d ", (*Ai)[i]); - mexPrintf("]\n"); -#endif -} - -void -dynSparseMatrix::PrintM(int n, const double *Ax, const mwIndex *Ap, const mwIndex *Ai) -{ - int nnz = Ap[n]; - auto *A = static_cast<double *>(mxMalloc(n * n * sizeof(double))); - test_mxMalloc(A, __LINE__, __FILE__, __func__, n * n * sizeof(double)); - fill_n(A, n * n, 0); - int k = 0; - for (int i = 0; i < n; i++) - for (int j = Ap[i]; j < static_cast<int>(Ap[i + 1]); j++) - { - int row = Ai[j]; - A[row * n + i] = Ax[j]; - k++; - } - if (nnz != k) - mexPrintf("Problem nnz(%d) != number of elements(%d)\n", nnz, k); - mexPrintf("----------------------\n"); - for (int i = 0; i < n; i++) - { - for (int j = 0; j < n; j++) - mexPrintf("%-6.3f ", A[i * n + j]); - mexPrintf("\n"); - } - mxFree(A); -} - -void -dynSparseMatrix::Init_Matlab_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, mxArray *A_m, mxArray *b_m, const mxArray *x0_m) const -{ - double *b = mxGetPr(b_m); - - if (!b) - throw FatalException{"In Init_Matlab_Sparse, can't retrieve b vector"}; - double *x0 = mxGetPr(x0_m); - if (!x0) - throw FatalException{"In Init_Matlab_Sparse_Simple, can't retrieve x0 vector"}; - mwIndex *Aj = mxGetJc(A_m); - if (!Aj) - throw FatalException{"In Init_Matlab_Sparse, can't allocate Aj index vector"}; - mwIndex *Ai = mxGetIr(A_m); - if (!Ai) - throw FatalException{"In Init_Matlab_Sparse, can't allocate Ai index vector"}; - double *A = mxGetPr(A_m); - if (!A) - throw FatalException{"In Init_Matlab_Sparse, can't retrieve A matrix"}; - - for (int i = 0; i < y_size*(periods+y_kmin); i++) - ya[i] = y[i]; - unsigned int NZE = 0; - int last_var = 0; - for (int i = 0; i < periods*Size; i++) - { - b[i] = 0; - x0[i] = y[index_vara[Size*y_kmin+i]]; - } - Aj[0] = 0; - for (int t = 0; t < periods; t++) - { - last_var = 0; - for (auto &[key, value] : IM) - { - int var = get<0>(key); - if (var != last_var) - { - Aj[1+last_var + t * Size] = NZE; - last_var = var; - } - int eq = get<2>(key)+Size*t; - int lag = -get<1>(key); - int index = value + (t-lag)*u_count_init; - if (var < (periods+y_kmax)*Size) - { - int ti_y_kmin = -min(t, y_kmin); - int ti_y_kmax = min(periods-(t +1), y_kmax); - int ti_new_y_kmax = min(t, y_kmax); - int ti_new_y_kmin = -min(periods-(t+1), y_kmin); - if (lag <= ti_new_y_kmax && lag >= ti_new_y_kmin) /*Build the index for sparse matrix containing the jacobian : u*/ - { -#ifdef DEBUG - if (index < 0 || index >= u_count_alloc || index > Size + Size*Size) - throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(index) - + ") out of range for u vector max = " - + to_string(Size+Size*Size) + " allocated = " - + to_string(u_count_alloc)}; - if (NZE >= prior_nz) - throw FatalException{"In Init_Matlab_Sparse, exceeds the capacity of allocated sparse matrix"}; -#endif - A[NZE] = u[index]; - Ai[NZE] = eq - lag * Size; - NZE++; - } - if (lag > ti_y_kmax || lag < ti_y_kmin) - { -#ifdef DEBUG - if (eq < 0 || eq >= Size * periods) - throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(eq) - + ") out of range for b vector"}; - if (var+Size*(y_kmin+t+lag) < 0 - || var+Size*(y_kmin+t+lag) >= Size*(periods+y_kmin+y_kmax)) - throw FatalException{"In Init_Matlab_Sparse, index (" - + to_string(var+Size*(y_kmin+t+lag)) - + ") out of range for index_vara vector"}; - if (index_vara[var+Size*(y_kmin+t+lag)] < 0 - || index_vara[var+Size*(y_kmin+t+lag)] >= y_size*(periods+y_kmin+y_kmax)) - throw FatalException{"In Init_Matlab_Sparse, index (" - + to_string(index_vara[var+Size*(y_kmin+t+lag)]) - + ") out of range for y vector max=" - + to_string(y_size*(periods+y_kmin+y_kmax))}; -#endif - b[eq] += u[index+lag*u_count_init]*y[index_vara[var+Size*(y_kmin+t+lag)]]; - } - } - else /* ...and store it in the u vector*/ - { -#ifdef DEBUG - if (index < 0 || index >= u_count_alloc) - throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(index) - + ") out of range for u vector"}; - if (eq < 0 || eq >= (Size*periods)) - throw FatalException{"In Init_Matlab_Sparse, index (" + to_string(eq) - + ") out of range for b vector"}; -#endif - b[eq] += u[index]; - } - } - } - Aj[Size*periods] = NZE; -} - -void -dynSparseMatrix::Init_GE(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM) -{ - double tmp_b = 0.0; - pivot = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); - test_mxMalloc(pivot, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); - pivot_save = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); - test_mxMalloc(pivot_save, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); - pivotk = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); - test_mxMalloc(pivotk, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); - pivotv = static_cast<double *>(mxMalloc(Size*periods*sizeof(double))); - test_mxMalloc(pivotv, __LINE__, __FILE__, __func__, Size*periods*sizeof(double)); - pivotva = static_cast<double *>(mxMalloc(Size*periods*sizeof(double))); - test_mxMalloc(pivotva, __LINE__, __FILE__, __func__, Size*periods*sizeof(double)); - b = static_cast<int *>(mxMalloc(Size*periods*sizeof(int))); - test_mxMalloc(b, __LINE__, __FILE__, __func__, Size*periods*sizeof(int)); - line_done = static_cast<bool *>(mxMalloc(Size*periods*sizeof(bool))); - test_mxMalloc(line_done, __LINE__, __FILE__, __func__, Size*periods*sizeof(bool)); - mem_mngr.init_CHUNK_BLCK_SIZE(u_count); - int i = (periods+y_kmax+1)*Size*sizeof(NonZeroElem *); - FNZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(FNZE_R, __LINE__, __FILE__, __func__, i); - FNZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(FNZE_C, __LINE__, __FILE__, __func__, i); - auto **temp_NZE_R = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(temp_NZE_R, __LINE__, __FILE__, __func__, i); - auto **temp_NZE_C = static_cast<NonZeroElem **>(mxMalloc(i)); - test_mxMalloc(temp_NZE_C, __LINE__, __FILE__, __func__, i); - i = (periods+y_kmax+1)*Size*sizeof(int); - NbNZRow = static_cast<int *>(mxMalloc(i)); - test_mxMalloc(NbNZRow, __LINE__, __FILE__, __func__, i); - NbNZCol = static_cast<int *>(mxMalloc(i)); - test_mxMalloc(NbNZCol, __LINE__, __FILE__, __func__, i); - - for (int i = 0; i < periods*Size; i++) - { - b[i] = 0; - line_done[i] = false; - } - for (int i = 0; i < (periods+y_kmax+1)*Size; i++) - { - FNZE_C[i] = nullptr; - FNZE_R[i] = nullptr; - temp_NZE_C[i] = nullptr; - temp_NZE_R[i] = nullptr; - NbNZRow[i] = 0; - NbNZCol[i] = 0; - } - int nnz = 0; - //pragma omp parallel for ordered private(it4, ti_y_kmin, ti_y_kmax, eq, var, lag) schedule(dynamic) - for (int t = 0; t < periods; t++) - { - int ti_y_kmin = -min(t, y_kmin); - int ti_y_kmax = min(periods-(t+1), y_kmax); - int eq = -1; - //pragma omp ordered - for (auto &[key, value] : IM) - { - int var = get<1>(key); - if (eq != get<0>(key)+Size*t) - tmp_b = 0; - eq = get<0>(key)+Size*t; - int lag = get<2>(key); - if (var < (periods+y_kmax)*Size) - { - lag = get<2>(key); - if (lag <= ti_y_kmax && lag >= ti_y_kmin) /*Build the index for sparse matrix containing the jacobian : u*/ - { - nnz++; - var += Size*t; - NbNZRow[eq]++; - NbNZCol[var]++; - NonZeroElem *first = mem_mngr.mxMalloc_NZE(); - first->NZE_C_N = nullptr; - first->NZE_R_N = nullptr; - first->u_index = value+u_count_init*t; - first->r_index = eq; - first->c_index = var; - first->lag_index = lag; - if (FNZE_R[eq] == nullptr) - FNZE_R[eq] = first; - if (FNZE_C[var] == nullptr) - FNZE_C[var] = first; - if (temp_NZE_R[eq] != nullptr) - temp_NZE_R[eq]->NZE_R_N = first; - if (temp_NZE_C[var] != nullptr) - temp_NZE_C[var]->NZE_C_N = first; - temp_NZE_R[eq] = first; - temp_NZE_C[var] = first; - } - else /*Build the additive terms ooutside the simulation periods related to the first lags and the last leads...*/ - { - if (lag < ti_y_kmin) - tmp_b += u[value+u_count_init*t]*y[index_vara[var+Size*(y_kmin+t)]]; - else - tmp_b += u[value+u_count_init*t]*y[index_vara[var+Size*(y_kmin+t)]]; - } - } - else /* ...and store it in the u vector*/ - { - b[eq] = value+u_count_init*t; - u[b[eq]] += tmp_b; - tmp_b = 0; - } - } - } - mxFree(temp_NZE_R); - mxFree(temp_NZE_C); -} - -int -dynSparseMatrix::Get_u() -{ - if (!u_liste.empty()) - { - int i = u_liste.back(); - u_liste.pop_back(); - return i; - } - else - { - if (u_count < u_count_alloc) - { - int i = u_count; - u_count++; - return i; - } - else - { - u_count_alloc += 5*u_count_alloc_save; - u = static_cast<double *>(mxRealloc(u, u_count_alloc*sizeof(double))); - if (!u) - throw FatalException{"In Get_u, memory exhausted (realloc(" - + to_string(u_count_alloc*sizeof(double)) + "))"}; - int i = u_count; - u_count++; - return i; - } - } -} - -void -dynSparseMatrix::Delete_u(int pos) -{ - u_liste.push_back(pos); -} - -void -dynSparseMatrix::Clear_u() -{ - u_liste.clear(); -} - -void -dynSparseMatrix::End_GE() -{ - mem_mngr.Free_All(); - mxFree(FNZE_R); - mxFree(FNZE_C); - mxFree(NbNZRow); - mxFree(NbNZCol); - mxFree(b); - mxFree(line_done); - mxFree(pivot); - mxFree(pivot_save); - mxFree(pivotk); - mxFree(pivotv); - mxFree(pivotva); -} - -bool -dynSparseMatrix::compare(int *save_op, int *save_opa, int *save_opaa, int beg_t, int periods, long nop4, int Size) -{ - long nop = nop4/2; - double r = 0.0; - bool OK = true; - int *diff1 = static_cast<int *>(mxMalloc(nop*sizeof(int))); - test_mxMalloc(diff1, __LINE__, __FILE__, __func__, nop*sizeof(int)); - int *diff2 = static_cast<int *>(mxMalloc(nop*sizeof(int))); - test_mxMalloc(diff2, __LINE__, __FILE__, __func__, nop*sizeof(int)); - int max_save_ops_first = -1; - long j = 0, i = 0; - while (i < nop4 && OK) - { - t_save_op_s *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[i]); - t_save_op_s *save_opa_s = reinterpret_cast<t_save_op_s *>(&save_opa[i]); - t_save_op_s *save_opaa_s = reinterpret_cast<t_save_op_s *>(&save_opaa[i]); - diff1[j] = save_op_s->first-save_opa_s->first; - max_save_ops_first = max(max_save_ops_first, save_op_s->first+diff1[j]*(periods-beg_t)); - switch (save_op_s->operat) - { - case IFLD: - case IFDIV: - OK = (save_op_s->operat == save_opa_s->operat && save_opa_s->operat == save_opaa_s->operat - && diff1[j] == (save_opa_s->first-save_opaa_s->first)); - i += 2; - break; - case IFLESS: - case IFSUB: - diff2[j] = save_op_s->second-save_opa_s->second; - OK = (save_op_s->operat == save_opa_s->operat && save_opa_s->operat == save_opaa_s->operat - && diff1[j] == (save_opa_s->first-save_opaa_s->first) - && diff2[j] == (save_opa_s->second-save_opaa_s->second)); - i += 3; - break; - default: - throw FatalException{"In compare, unknown operator = " - + to_string(save_op_s->operat)}; - } - j++; - } - // the same pivot for all remaining periods - if (OK) - { - for (int i = beg_t; i < periods; i++) - for (int j = 0; j < Size; j++) - pivot[i*Size+j] = pivot[(i-1)*Size+j]+Size; - if (max_save_ops_first >= u_count_alloc) - { - u_count_alloc += max_save_ops_first; - u = static_cast<double *>(mxRealloc(u, u_count_alloc*sizeof(double))); - if (!u) - throw FatalException{"In compare, memory exhausted (realloc(" - + to_string(u_count_alloc*sizeof(double)) + "))"}; - } - for (int t = 1; t < periods-beg_t-y_kmax; t++) - { - int i = j = 0; - while (i < nop4) - { - auto *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[i]); - double *up = &u[save_op_s->first+t*diff1[j]]; - switch (save_op_s->operat) - { - case IFLD: - r = *up; - i += 2; - break; - case IFDIV: - *up /= r; - i += 2; - break; - case IFSUB: - *up -= u[save_op_s->second+t*diff2[j]]*r;; - i += 3; - break; - case IFLESS: - *up = -u[save_op_s->second+t*diff2[j]]*r; - i += 3; - break; - } - j++; - } - } - int t1 = max(1, periods-beg_t-y_kmax); - int periods_beg_t = periods-beg_t; - for (int t = t1; t < periods_beg_t; t++) - { - int i = j = 0; - int gap = periods_beg_t-t; - while (i < nop4) - { - if (auto *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[i]); - save_op_s->lag < gap) - { - double *up = &u[save_op_s->first+t*diff1[j]]; - switch (save_op_s->operat) - { - case IFLD: - r = *up; - i += 2; - break; - case IFDIV: - *up /= r; - i += 2; - break; - case IFSUB: - *up -= u[save_op_s->second+t*diff2[j]]*r; - i += 3; - break; - case IFLESS: - *up = -u[save_op_s->second+t*diff2[j]]*r; - i += 3; - break; - } - } - else - switch (save_op_s->operat) - { - case IFLD: - case IFDIV: - i += 2; - break; - case IFSUB: - case IFLESS: - i += 3; - break; - } - j++; - } - } - } - mxFree(diff1); - mxFree(diff2); - return OK; -} - -int -dynSparseMatrix::complete(int beg_t, int Size, int periods, int *b) -{ - double yy = 0.0; - - int size_of_save_code = (1+y_kmax)*Size*(Size+1+4)/2*4; - int *save_code = static_cast<int *>(mxMalloc(size_of_save_code*sizeof(int))); - test_mxMalloc(save_code, __LINE__, __FILE__, __func__, size_of_save_code*sizeof(int)); - int size_of_diff = (1+y_kmax)*Size*(Size+1+4); - int *diff = static_cast<int *>(mxMalloc(size_of_diff*sizeof(int))); - test_mxMalloc(diff, __LINE__, __FILE__, __func__, size_of_diff*sizeof(int)); - long cal_y = y_size*y_kmin; - - long i = (beg_t+1)*Size-1; - long nop = 0; - for (long j = i; j > i-Size; j--) - { - long pos = pivot[j]; - NonZeroElem *first; - long nb_var = At_Row(pos, &first); - first = first->NZE_R_N; - nb_var--; - save_code[nop] = IFLDZ; - save_code[nop+1] = 0; - save_code[nop+2] = 0; - save_code[nop+3] = 0; -#ifdef DEBUG - if ((nop+3) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); -#endif - nop += 4; - for (long k = 0; k < nb_var; k++) - { - save_code[nop] = IFMUL; - save_code[nop+1] = index_vara[first->c_index]+cal_y; - save_code[nop+2] = first->u_index; - save_code[nop+3] = first->lag_index; -#ifdef DEBUG - if ((nop+3) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); -#endif - nop += 4; - first = first->NZE_R_N; - } - save_code[nop] = IFADD; - save_code[nop+1] = b[pos]; - save_code[nop+2] = 0; - save_code[nop+3] = 0; -#ifdef DEBUG - if ((nop+3) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); -#endif - nop += 4; - save_code[nop] = IFSTP; - save_code[nop+1] = index_vara[j]+y_size*y_kmin; - save_code[nop+2] = 0; - save_code[nop+3] = 0; -#ifdef DEBUG - if ((nop+2) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop+2, size_of_save_code); -#endif - nop += 4; - } - i = beg_t*Size-1; - long nop1 = 0, nopa = 0; - for (long j = i; j > i-Size; j--) - { - long pos = pivot[j]; - NonZeroElem *first; - long nb_var = At_Row(pos, &first); - first = first->NZE_R_N; - nb_var--; - diff[nopa] = 0; - diff[nopa+1] = 0; - nopa += 2; - nop1 += 4; - for (long k = 0; k < nb_var; k++) - { - diff[nopa] = save_code[nop1+1]-(index_vara[first->c_index]+cal_y); - diff[nopa+1] = save_code[nop1+2]-(first->u_index); -#ifdef DEBUG - if ((nop1+2) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop1+2, size_of_save_code); - if ((nopa+1) >= size_of_diff) - mexPrintf("out of diff[%d] (bound=%d)\n", nopa+2, size_of_diff); -#endif - nopa += 2; - nop1 += 4; - first = first->NZE_R_N; - } - diff[nopa] = save_code[nop1+1]-(b[pos]); - diff[nopa+1] = 0; -#ifdef DEBUG - if ((nop1+3) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop1+2, size_of_save_code); - if ((nopa+1) >= size_of_diff) - mexPrintf("out of diff[%d] (bound=%d)\n", nopa+2, size_of_diff); -#endif - nopa += 2; - nop1 += 4; - diff[nopa] = save_code[nop1+1]-(index_vara[j]+y_size*y_kmin); - diff[nopa+1] = 0; -#ifdef DEBUG - if ((nop1+4) >= size_of_save_code) - mexPrintf("out of save_code[%d] (bound=%d)\n", nop1+2, size_of_save_code); - if ((nopa+1) >= size_of_diff) - mexPrintf("out of diff[%d] (bound=%d)\n", nopa+2, size_of_diff); -#endif - nopa += 2; - nop1 += 4; - } - long max_var = (periods+y_kmin)*y_size; - long min_var = y_kmin*y_size; - for (int t = periods+y_kmin-1; t >= beg_t+y_kmin; t--) - { - int j = 0, k; - int ti = t-y_kmin-beg_t; - for (int i = 0; i < nop; i += 4) - { - switch (save_code[i]) - { - case IFLDZ: - yy = 0; - break; - case IFMUL: - k = save_code[i+1]+ti*diff[j]; - if (k < max_var && k > min_var) - yy += y[k]*u[save_code[i+2]+ti*diff[j+1]]; - break; - case IFADD: - yy = -(yy+u[save_code[i+1]+ti*diff[j]]); - break; - case IFSTP: - k = save_code[i+1]+ti*diff[j]; - double err = yy - y[k]; - y[k] += slowc*(err); - break; - } - j += 2; - } - } - mxFree(save_code); - mxFree(diff); - return (beg_t); -} - -void -dynSparseMatrix::bksub(int tbreak, int last_period, int Size, double slowc_l) -{ - for (int i = 0; i < y_size*(periods+y_kmin); i++) - y[i] = ya[i]; - if (symbolic && tbreak) - last_period = complete(tbreak, Size, periods, b); - else - last_period = periods; - for (int t = last_period+y_kmin-1; t >= y_kmin; t--) - { - int ti = (t-y_kmin)*Size; - int cal = y_kmin*Size; - int cal_y = y_size*y_kmin; - for (int i = ti-1; i >= ti-Size; i--) - { - int j = i+cal; - int pos = pivot[i+Size]; - NonZeroElem *first; - int nb_var = At_Row(pos, &first); - first = first->NZE_R_N; - nb_var--; - int eq = index_vara[j]+y_size; - double yy = 0; - for (int k = 0; k < nb_var; k++) - { - yy += y[index_vara[first->c_index]+cal_y]*u[first->u_index]; - first = first->NZE_R_N; - } - yy = -(yy+y[eq]+u[b[pos]]); - direction[eq] = yy; - y[eq] += slowc_l*yy; - } - } -} - -void -dynSparseMatrix::simple_bksub(int it_, int Size, double slowc_l) -{ - for (int i = 0; i < y_size; i++) - y[i+it_*y_size] = ya[i+it_*y_size]; - for (int i = Size-1; i >= 0; i--) - { - int pos = pivot[i]; - NonZeroElem *first; - int nb_var = At_Row(pos, &first); - first = first->NZE_R_N; - nb_var--; - int eq = index_vara[i]; - double yy = 0; - for (int k = 0; k < nb_var; k++) - { - yy += y[index_vara[first->c_index]+it_*y_size]*u[first->u_index]; - first = first->NZE_R_N; - } - yy = -(yy+y[eq+it_*y_size]+u[b[pos]]); - direction[eq+it_*y_size] = yy; - y[eq+it_*y_size] += slowc_l*yy; - } -} - -mxArray * -dynSparseMatrix::subtract_A_B(const mxArray *A_m, const mxArray *B_m) -{ - size_t n_A = mxGetN(A_m); - size_t m_A = mxGetM(A_m); - double *A_d = mxGetPr(A_m); - size_t n_B = mxGetN(B_m); - double *B_d = mxGetPr(B_m); - mxArray *C_m = mxCreateDoubleMatrix(m_A, n_B, mxREAL); - double *C_d = mxGetPr(C_m); - for (int j = 0; j < static_cast<int>(n_A); j++) - for (unsigned int i = 0; i < m_A; i++) - { - size_t index = j*m_A+i; - C_d[index] = A_d[index] - B_d[index]; - } - return C_m; -} - -mxArray * -dynSparseMatrix::Sparse_subtract_SA_SB(const mxArray *A_m, const mxArray *B_m) -{ - size_t n_A = mxGetN(A_m); - size_t m_A = mxGetM(A_m); - mwIndex *A_i = mxGetIr(A_m); - mwIndex *A_j = mxGetJc(A_m); - size_t total_nze_A = A_j[n_A]; - double *A_d = mxGetPr(A_m); - size_t n_B = mxGetN(B_m); - mwIndex *B_i = mxGetIr(B_m); - mwIndex *B_j = mxGetJc(B_m); - size_t total_nze_B = B_j[n_B]; - double *B_d = mxGetPr(B_m); - mxArray *C_m = mxCreateSparse(m_A, n_B, m_A*n_B, mxREAL); - mwIndex *C_i = mxGetIr(C_m); - mwIndex *C_j = mxGetJc(C_m); - double *C_d = mxGetPr(C_m); - unsigned int nze_B = 0, nze_C = 0, nze_A = 0; - unsigned int A_col = 0, B_col = 0, C_col = 0; - C_j[C_col] = 0; - while (nze_A < total_nze_A || nze_B < total_nze_B) - { - while (nze_A >= static_cast<unsigned int>(A_j[A_col+1]) && (nze_A < total_nze_A)) - A_col++; - size_t A_row = A_i[nze_A]; - while (nze_B >= static_cast<unsigned int>(B_j[B_col+1]) && (nze_B < total_nze_B)) - B_col++; - size_t B_row = B_i[nze_B]; - if (A_col == B_col) - { - if (A_row == B_row && (nze_B < total_nze_B && nze_A < total_nze_A)) - { - C_d[nze_C] = A_d[nze_A++] - B_d[nze_B++]; - C_i[nze_C] = A_row; - while (C_col < A_col) - C_j[++C_col] = nze_C; - C_j[A_col+1] = nze_C++; - C_col = A_col; - } - else if ((A_row < B_row && nze_A < total_nze_A) || nze_B == total_nze_B) - { - C_d[nze_C] = A_d[nze_A++]; - C_i[nze_C] = A_row; - while (C_col < A_col) - C_j[++C_col] = nze_C; - C_j[A_col+1] = nze_C++; - C_col = A_col; - } - else - { - C_d[nze_C] = -B_d[nze_B++]; - C_i[nze_C] = B_row; - while (C_col < B_col) - C_j[++C_col] = nze_C; - C_j[B_col+1] = nze_C++; - C_col = B_col; - } - } - else if ((A_col < B_col && nze_A < total_nze_A) || nze_B == total_nze_B) - { - C_d[nze_C] = A_d[nze_A++]; - C_i[nze_C] = A_row; - while (C_col < A_col) - C_j[++C_col] = nze_C; - C_j[A_col+1] = nze_C++; - C_col = A_col; - } - else - { - C_d[nze_C] = -B_d[nze_B++]; - C_i[nze_C] = B_row; - while (C_col < B_col) - C_j[++C_col] = nze_C; - C_j[B_col+1] = nze_C++; - C_col = B_col; - } - } - while (C_col < n_B) - C_j[++C_col] = nze_C; - mxSetNzmax(C_m, nze_C); - return C_m; -} - -mxArray * -dynSparseMatrix::mult_SAT_B(const mxArray *A_m, const mxArray *B_m) -{ - size_t n_A = mxGetN(A_m); - mwIndex *A_i = mxGetIr(A_m); - mwIndex *A_j = mxGetJc(A_m); - double *A_d = mxGetPr(A_m); - size_t n_B = mxGetN(B_m); - double *B_d = mxGetPr(B_m); - mxArray *C_m = mxCreateDoubleMatrix(n_A, n_B, mxREAL); - double *C_d = mxGetPr(C_m); - for (int j = 0; j < static_cast<int>(n_B); j++) - for (unsigned int i = 0; i < n_A; i++) - { - double sum = 0; - size_t nze_A = A_j[i]; - while (nze_A < static_cast<unsigned int>(A_j[i+1])) - { - size_t i_A = A_i[nze_A]; - sum += A_d[nze_A++] * B_d[i_A]; - } - C_d[j*n_A+i] = sum; - } - return C_m; -} - -mxArray * -dynSparseMatrix::Sparse_mult_SAT_B(const mxArray *A_m, const mxArray *B_m) -{ - size_t n_A = mxGetN(A_m); - mwIndex *A_i = mxGetIr(A_m); - mwIndex *A_j = mxGetJc(A_m); - double *A_d = mxGetPr(A_m); - size_t n_B = mxGetN(B_m); - size_t m_B = mxGetM(B_m); - double *B_d = mxGetPr(B_m); - mxArray *C_m = mxCreateSparse(n_A, n_B, n_A*n_B, mxREAL); - mwIndex *C_i = mxGetIr(C_m); - mwIndex *C_j = mxGetJc(C_m); - double *C_d = mxGetPr(C_m); - unsigned int nze_C = 0; - //unsigned int nze_A = 0; - unsigned int C_col = 0; - C_j[C_col] = 0; - //#pragma omp parallel for - for (unsigned int j = 0; j < n_B; j++) - for (unsigned int i = 0; i < n_A; i++) - { - double sum = 0; - size_t nze_A = A_j[i]; - while (nze_A < static_cast<unsigned int>(A_j[i+1])) - { - size_t i_A = A_i[nze_A]; - sum += A_d[nze_A++] * B_d[i_A]; - } - if (fabs(sum) > 1e-10) - { - C_d[nze_C] = sum; - C_i[nze_C] = i; - while (C_col < j) - C_j[++C_col] = nze_C; - nze_C++; - } - } - while (C_col < m_B) - C_j[++C_col] = nze_C; - mxSetNzmax(C_m, nze_C); - return C_m; -} - -mxArray * -dynSparseMatrix::Sparse_mult_SAT_SB(const mxArray *A_m, const mxArray *B_m) -{ - size_t n_A = mxGetN(A_m); - mwIndex *A_i = mxGetIr(A_m); - mwIndex *A_j = mxGetJc(A_m); - double *A_d = mxGetPr(A_m); - size_t n_B = mxGetN(B_m); - mwIndex *B_i = mxGetIr(B_m); - mwIndex *B_j = mxGetJc(B_m); - double *B_d = mxGetPr(B_m); - mxArray *C_m = mxCreateSparse(n_A, n_B, n_A*n_B, mxREAL); - mwIndex *C_i = mxGetIr(C_m); - mwIndex *C_j = mxGetJc(C_m); - double *C_d = mxGetPr(C_m); - size_t nze_B = 0, nze_C = 0, nze_A = 0; - unsigned int C_col = 0; - C_j[C_col] = 0; - for (unsigned int j = 0; j < n_B; j++) - for (unsigned int i = 0; i < n_A; i++) - { - double sum = 0; - nze_B = B_j[j]; - nze_A = A_j[i]; - while (nze_A < static_cast<unsigned int>(A_j[i+1]) && nze_B < static_cast<unsigned int>(B_j[j+1])) - { - size_t i_A = A_i[nze_A]; - size_t i_B = B_i[nze_B]; - if (i_A == i_B) - sum += A_d[nze_A++] * B_d[nze_B++]; - else if (i_A < i_B) - nze_A++; - else - nze_B++; - } - if (fabs(sum) > 1e-10) - { - C_d[nze_C] = sum; - C_i[nze_C] = i; - while (C_col < j) - C_j[++C_col] = nze_C; - nze_C++; - } - } - while (C_col < n_B) - C_j[++C_col] = nze_C; - mxSetNzmax(C_m, nze_C); - return C_m; -} - -mxArray * -dynSparseMatrix::Sparse_transpose(const mxArray *A_m) -{ - size_t n_A = mxGetN(A_m); - size_t m_A = mxGetM(A_m); - mwIndex *A_i = mxGetIr(A_m); - mwIndex *A_j = mxGetJc(A_m); - size_t total_nze_A = A_j[n_A]; - double *A_d = mxGetPr(A_m); - mxArray *C_m = mxCreateSparse(n_A, m_A, total_nze_A, mxREAL); - mwIndex *C_i = mxGetIr(C_m); - mwIndex *C_j = mxGetJc(C_m); - double *C_d = mxGetPr(C_m); - unsigned int nze_C = 0, nze_A = 0; - fill_n(C_j, m_A+1, 0); - map<pair<mwIndex, unsigned int>, double> B2; - for (unsigned int i = 0; i < n_A; i++) - while (nze_A < static_cast<unsigned int>(A_j[i+1])) - { - C_j[A_i[nze_A]+1]++; - B2[{ A_i[nze_A], i }] = A_d[nze_A]; - nze_A++; - } - for (unsigned int i = 0; i < m_A; i++) - C_j[i+1] += C_j[i]; - for (auto &[key, val] : B2) - { - C_d[nze_C] = val; - C_i[nze_C++] = key.second; - } - return C_m; -} - -void -dynSparseMatrix::compute_block_time(int Per_u_, bool evaluate, bool no_derivatives) -{ -#ifdef DEBUG - mexPrintf("compute_block_time\n"); -#endif - double *jacob {nullptr}, *jacob_exo {nullptr}, *jacob_exo_det {nullptr}; - if (evaluate) - { - jacob = mxGetPr(jacobian_block[block_num]); - if (!steady_state) - { - jacob_exo = mxGetPr(jacobian_exo_block[block_num]); - jacob_exo_det = mxGetPr(jacobian_det_exo_block[block_num]); - } - } - - try - { - evaluator.evaluateBlock(it_, y, ya, y_size, x, nb_row_x, params, steady_y, u, Per_u_, T, periods+y_kmin+y_kmax, TEF, TEFD, TEFDD, r, g1, jacob, jacob_exo, jacob_exo_det, evaluate, no_derivatives); - } - catch (FloatingPointException &e) - { - res1 = numeric_limits<double>::quiet_NaN(); - if (verbosity >= 2) - mexPrintf("%s\n %s\n", e.message.c_str(), e.location.c_str()); - } -} - -bool -dynSparseMatrix::compute_complete(bool no_derivatives, double &_res1, double &_res2, double &_max_res, int &_max_res_idx) -{ - bool result; - res1 = 0; - compute_block_time(0, false, no_derivatives); - if (!(isnan(res1) || isinf(res1))) - { - _res1 = 0; - _res2 = 0; - _max_res = 0; - for (int i = 0; i < size; i++) - { - double rr; - rr = r[i]; - if (max_res < fabs(rr)) - { - _max_res = fabs(rr); - _max_res_idx = i; - } - _res2 += rr*rr; - _res1 += fabs(rr); - } - result = true; - } - else - result = false; - return result; -} - -bool -dynSparseMatrix::compute_complete(double lambda, double *crit) -{ - double res1_ = 0, res2_ = 0, max_res_ = 0; - int max_res_idx_ = 0; - if (steady_state) - { - it_ = 0; - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - y[eq] = ya[eq] + lambda * direction[eq]; - } - Per_u_ = 0; - Per_y_ = 0; - if (compute_complete(true, res1, res2, max_res, max_res_idx)) - res2_ = res2; - else - return false; - } - else - { - for (int it = y_kmin; it < periods+y_kmin; it++) - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - y[eq+it*y_size] = ya[eq+it*y_size] + lambda * direction[eq+it*y_size]; - } - for (it_ = y_kmin; it_ < periods+y_kmin; it_++) - { - Per_u_ = (it_-y_kmin)*u_count_int; - Per_y_ = it_*y_size; - if (compute_complete(true, res1, res2, max_res, max_res_idx)) - { - res2_ += res2; - res1_ += res1; - if (max_res > max_res_) - { - max_res = max_res_; - max_res_idx = max_res_idx_; - } - } - else - return false; - } - it_ = periods+y_kmin-1; // Do not leave it_ in inconsistent state - } - if (verbosity >= 2) - mexPrintf(" lambda=%e, res2=%e\n", lambda, res2_); - *crit = res2_/2; - return true; -} - -bool -dynSparseMatrix::mnbrak(double *ax, double *bx, double *cx, double *fa, double *fb, double *fc) -{ - constexpr double GOLD = 1.618034; - constexpr double GLIMIT = 100.0; - constexpr double TINY = 1.0e-20; - - auto sign = [](double a, double b) { return b >= 0.0 ? fabs(a) : -fabs(a); }; - - if (verbosity >= 2) - mexPrintf("bracketing *ax=%f, *bx=%f\n", *ax, *bx); - if (!compute_complete(*ax, fa)) - return false; - if (!compute_complete(*bx, fb)) - return false; - if (*fb > *fa) - { - swap(*ax, *bx); - swap(*fa, *fb); - } - *cx = (*bx)+GOLD*(*bx-*ax); - if (!compute_complete(*cx, fc)) - return false; - while (*fb > *fc) - { - double r = (*bx-*ax)*(*fb-*fc); - double q = (*bx-*cx)*(*fb-*fa); - double u = (*bx)-((*bx-*cx)*q-(*bx-*ax)*r) - /(2.0*sign(fmax(fabs(q-r), TINY), q-r)); - double ulim = (*bx)+GLIMIT*(*cx-*bx); - double fu; - if ((*bx-u)*(u-*cx) > 0.0) - { - if (!compute_complete(u, &fu)) - return false; - if (fu < *fc) - { - *ax = (*bx); - *bx = u; - *fa = (*fb); - *fb = fu; - return true; - } - else if (fu > *fb) - { - *cx = u; - *fc = fu; - return true; - } - u = (*cx)+GOLD*(*cx-*bx); - if (!compute_complete(u, &fu)) - return false; - } - else if ((*cx-u)*(u-ulim) > 0.0) - { - if (!compute_complete(u, &fu)) - return false; - if (fu < *fc) - { - *bx = *cx; - *cx = u; - u = *cx+GOLD*(*cx-*bx); - *fb = *fc; - *fc = fu; - if (!compute_complete(u, &fu)) - return false; - } - } - else if ((u-ulim)*(ulim-*cx) >= 0.0) - { - u = ulim; - if (!compute_complete(u, &fu)) - return false; - } - else - { - u = (*cx)+GOLD*(*cx-*bx); - if (!compute_complete(u, &fu)) - return false; - } - *ax = *bx; - *bx = *cx; - *cx = u; - *fa = *fb; - *fb = *fc; - *fc = fu; - } - return true; -} - -bool -dynSparseMatrix::golden(double ax, double bx, double cx, double tol, double solve_tolf, double *xmin) -{ - const double R = 0.61803399; - const double C = (1.0-R); - if (verbosity >= 2) - mexPrintf("golden\n"); - int iter = 0, max_iter = 100; - double f1, f2, x1, x2; - double x0 = ax; - double x3 = cx; - if (fabs(cx-bx) > fabs(bx-ax)) - { - x1 = bx; - x2 = bx+C*(cx-bx); - } - else - { - x2 = bx; - x1 = bx-C*(bx-ax); - } - if (!compute_complete(x1, &f1)) - return false; - if (!compute_complete(x2, &f2)) - return false; - while (fabs(x3-x0) > tol*(fabs(x1)+fabs(x2)) && f1 > solve_tolf && f2 > solve_tolf - && iter < max_iter && abs(x1 - x2) > 1e-4) - { - if (f2 < f1) - { - x0 = x1; - x1 = x2; - x2 = R*x1+C*x3; - f1 = f2; - if (!compute_complete(x2, &f2)) - return false; - } - else - { - x3 = x2; - x2 = x1; - x1 = R*x2+C*x0; - f2 = f1; - if (!compute_complete(x1, &f1)) - return false; - } - iter++; - } - if (f1 < f2) - { - *xmin = x1; - return true; - } - else - { - *xmin = x2; - return true; - } -} - -void -dynSparseMatrix::Solve_Matlab_Relaxation(mxArray *A_m, mxArray *b_m, unsigned int Size, double slowc_l) -{ - 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 < 2*Size; var++) // Iterate over columns of A - { - if (var < 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 < Size) - { - if (eq < 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 < 2*Size) - { - if (eq < Size) - { - C1_i[C1_nze] = eq; - C1_d[C1_nze] = A_m_d[nze]; - C1_nze++; - } - else if (eq < 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 < (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 < (t+1) * Size) - { - C1_i[C1_nze] = eq - t*Size; - C1_d[C1_nze] = A_m_d[nze]; - C1_nze++; - } - else if (eq < (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 (unsigned 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_l * 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 (unsigned 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_l * yy; - } - } - - mxDestroyArray(B1); - mxDestroyArray(C1); - mxDestroyArray(A2); - mxDestroyArray(B2); - mxDestroyArray(A3); - mxDestroyArray(b1); - mxDestroyArray(b2); - mxDestroyArray(A_m); - mxDestroyArray(b_m); - mxDestroyArray(d1); -} - -void -dynSparseMatrix::End_Matlab_LU_UMFPack() -{ - if (Symbolic) - { - umfpack_dl_free_symbolic(&Symbolic); - Symbolic = nullptr; - } - if (Numeric) - { - umfpack_dl_free_numeric(&Numeric); - Numeric = nullptr; - } -} - -void -dynSparseMatrix::End_Solver() -{ - if (((stack_solve_algo == 0 || stack_solve_algo == 4) && !steady_state) - || (solve_algo == 6 && steady_state)) - End_Matlab_LU_UMFPack(); -} - -void -dynSparseMatrix::Printfull_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, const double *b, int n) -{ - double A[n*n]; - for (int i = 0; i < n*n; i++) - A[i] = 0; - int k = 0; - for (int i = 0; i < n; i++) - for (int j = Ap[i]; j < Ap[i+1]; j++) - A[Ai[j] * n + i] = Ax[k++]; - for (int i = 0; i < n; i++) - { - for (int j = 0; j < n; j++) - mexPrintf("%4.1f ", A[i*n+j]); - mexPrintf(" %6.3f\n", b[i]); - } -} - -void -dynSparseMatrix::Print_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, int n) -{ - int k = 0; - for (int i = 0; i < n; i++) - for (int j = Ap[i]; j < Ap[i+1]; j++) - mexPrintf("(%d, %d) %f\n", Ai[j]+1, i+1, Ax[k++]); -} - -void -dynSparseMatrix::Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_, const vector_table_conditional_local_type &vector_table_conditional_local) -{ - SuiteSparse_long sys = 0; - double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO], res[n]; - - umfpack_dl_defaults(Control); - SuiteSparse_long status = 0; - if (iter == 0) - { - if (Symbolic) - umfpack_dl_free_symbolic(&Symbolic); - status = umfpack_dl_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info); - if (status != UMFPACK_OK) - { - umfpack_dl_report_info(Control, Info); - umfpack_dl_report_status(Control, status); - throw FatalException{"umfpack_dl_symbolic failed"}; - } - } - if (Numeric) - umfpack_dl_free_numeric(&Numeric); - status = umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); - if (status != UMFPACK_OK) - { - umfpack_dl_report_info(Control, Info); - umfpack_dl_report_status(Control, status); - throw FatalException{"umfpack_dl_numeric failed"}; - } - status = umfpack_dl_solve(sys, Ap, Ai, Ax, res, b, Numeric, Control, Info); - if (status != UMFPACK_OK) - { - umfpack_dl_report_info(Control, Info); - umfpack_dl_report_status(Control, status); - throw FatalException{"umfpack_dl_solve failed"}; - } - - if (vector_table_conditional_local.size()) - { - if (is_two_boundaries) - for (int t = 0; t < n / Size; t++) - if (t == 0) - { - for (int i = 0; i < Size; i++) - { - bool fliped = vector_table_conditional_local[i].is_cond; - if (fliped) - { - int eq = index_vara[i+Size*(y_kmin)]; - int flip_exo = vector_table_conditional_local[i].var_exo; - double yy = -(res[i] + x[y_kmin + flip_exo*nb_row_x]); - direction[eq] = 0; - x[flip_exo*nb_row_x + y_kmin] += slowc_l * yy; - } - else - { - int eq = index_vara[i+Size*(y_kmin)]; - double yy = -(res[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc_l * yy; - } - } - } - else - { - for (int i = 0; i < Size; i++) - { - int eq = index_vara[i+Size*(t + y_kmin)]; - double yy = -(res[i + Size * t] + y[eq]); - direction[eq] = yy; - y[eq] += slowc_l * yy; - } - } - else - for (int i = 0; i < n; i++) - { - int eq = index_vara[i]; - double yy = -(res[i] + y[eq+it_*y_size]); - direction[eq] = yy; - y[eq+it_*y_size] += slowc_l * yy; - } - } - else - { - if (is_two_boundaries) - for (int i = 0; i < n; i++) - { - int eq = index_vara[i+Size*y_kmin]; - double yy = -(res[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc_l * yy; - } - else - for (int i = 0; i < n; i++) - { - int eq = index_vara[i]; - double yy = -(res[i] + y[eq+it_*y_size]); - direction[eq] = yy; - y[eq+it_*y_size] += slowc_l * yy; - } - } - - mxFree(Ap); - mxFree(Ai); - mxFree(Ax); - mxFree(b); -} - -void -dynSparseMatrix::Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_) -{ - SuiteSparse_long sys = 0; - double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO], res[n]; - - umfpack_dl_defaults(Control); - SuiteSparse_long status = 0; - if (iter == 0) - { - if (Symbolic) - umfpack_dl_free_symbolic(&Symbolic); - status = umfpack_dl_symbolic(n, n, Ap, Ai, Ax, &Symbolic, Control, Info); - if (status != UMFPACK_OK) - { - umfpack_dl_report_info(Control, Info); - umfpack_dl_report_status(Control, status); - throw FatalException{"umfpack_dl_symbolic failed"}; - } - } - if (Numeric) - umfpack_dl_free_numeric(&Numeric); - status = umfpack_dl_numeric(Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); - if (status != UMFPACK_OK) - { - umfpack_dl_report_info(Control, Info); - umfpack_dl_report_status(Control, status); - throw FatalException{"umfpack_dl_numeric failed"}; - } - status = umfpack_dl_solve(sys, Ap, Ai, Ax, res, b, Numeric, Control, Info); - if (status != UMFPACK_OK) - { - umfpack_dl_report_info(Control, Info); - umfpack_dl_report_status(Control, status); - throw FatalException{"umfpack_dl_solve failed"}; - } - - if (is_two_boundaries) - for (int i = 0; i < n; i++) - { - int eq = index_vara[i+Size*y_kmin]; - double yy = -(res[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc_l * yy; - } - else - for (int i = 0; i < n; i++) - { - int eq = index_vara[i]; - double yy = -(res[i] + y[eq+it_*y_size]); - direction[eq] = yy; - y[eq+it_*y_size] += slowc_l * yy; - } - mxFree(Ap); - mxFree(Ai); - mxFree(Ax); - mxFree(b); -} - -void -dynSparseMatrix::Solve_Matlab_GMRES(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m) -{ - size_t n = mxGetM(A_m); - const char *field_names[] = {"droptol", "type"}; - mwSize dims[1] = { 1 }; - mxArray *Setup = mxCreateStructArray(1, dims, std::extent_v<decltype(field_names)>, field_names); - mxSetFieldByNumber(Setup, 0, 0, mxCreateDoubleScalar(lu_inc_tol)); - mxSetFieldByNumber(Setup, 0, 1, mxCreateString("ilutp")); - mxArray *lhs0[2]; - mxArray *rhs0[] = { A_m, Setup }; - if (mexCallMATLAB(std::extent_v<decltype(lhs0)>, lhs0, std::extent_v<decltype(rhs0)>, rhs0, "ilu")) - throw FatalException("In GMRES, the incomplete LU decomposition (ilu) has failed"); - mxArray *L1 = lhs0[0]; - mxArray *U1 = lhs0[1]; - /*[za,flag1] = gmres(g1a,b,Blck_size,1e-6,Blck_size*periods,L1,U1);*/ - mxArray *rhs[] = { A_m, b_m, mxCreateDoubleScalar(Size), mxCreateDoubleScalar(1e-6), - mxCreateDoubleScalar(static_cast<double>(n)), L1, U1, x0_m }; - mxArray *lhs[2]; - mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "gmres"); - mxArray *z = lhs[0]; - mxArray *flag = lhs[1]; - double *flag1 = mxGetPr(flag); - mxDestroyArray(rhs0[1]); - mxDestroyArray(rhs[2]); - mxDestroyArray(rhs[3]); - mxDestroyArray(rhs[4]); - mxDestroyArray(rhs[5]); - mxDestroyArray(rhs[6]); - if (*flag1 > 0) - { - if (*flag1 == 1) - mexWarnMsgTxt(("Error in bytecode: No convergence inside GMRES, in block " - + to_string(block+1)).c_str()); - else if (*flag1 == 2) - mexWarnMsgTxt(("Error in bytecode: Preconditioner is ill-conditioned, in block " - + to_string(block+1)).c_str()); - else if (*flag1 == 3) - mexWarnMsgTxt(("Error in bytecode: GMRES stagnated (Two consecutive iterates were the same.), in block " - + to_string(block+1)).c_str()); - lu_inc_tol /= 10; - } - else - { - double *res = mxGetPr(z); - if (is_two_boundaries) - for (int i = 0; i < static_cast<int>(n); i++) - { - int eq = index_vara[i+Size*y_kmin]; - double yy = -(res[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc * yy; - } - else - for (int i = 0; i < static_cast<int>(n); i++) - { - int eq = index_vara[i]; - double yy = -(res[i] + y[eq+it_*y_size]); - direction[eq] = yy; - y[eq+it_*y_size] += slowc * yy; - } - } - mxDestroyArray(A_m); - mxDestroyArray(b_m); - mxDestroyArray(x0_m); - mxDestroyArray(z); - mxDestroyArray(flag); -} - -void -dynSparseMatrix::Solve_Matlab_BiCGStab(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m, int preconditioner) -{ - /* precond = 0 => Jacobi - precond = 1 => Incomplet LU decomposition*/ - size_t n = mxGetM(A_m); - mxArray *L1 = nullptr, *U1 = nullptr, *Diag = nullptr; - - if (preconditioner == 0) - { - mxArray *lhs0[1]; - mxArray *rhs0[] = { A_m, mxCreateDoubleScalar(0) }; - mexCallMATLAB(std::extent_v<decltype(lhs0)>, lhs0, std::extent_v<decltype(rhs0)>, rhs0, "spdiags"); - mxArray *tmp = lhs0[0]; - double *tmp_val = mxGetPr(tmp); - Diag = mxCreateSparse(n, n, n, mxREAL); - mwIndex *Diag_i = mxGetIr(Diag); - mwIndex *Diag_j = mxGetJc(Diag); - double *Diag_val = mxGetPr(Diag); - for (size_t i = 0; i < n; i++) - { - Diag_val[i] = tmp_val[i]; - Diag_j[i] = i; - Diag_i[i] = i; - } - Diag_j[n] = n; - } - else if (preconditioner == 1) - { - /*[L1, U1] = ilu(g1a=;*/ - const char *field_names[] = {"type", "droptol", "milu", "udiag", "thresh"}; - const int type = 0, droptol = 1, milu = 2, udiag = 3, thresh = 4; - mwSize dims[1] = { static_cast<mwSize>(1) }; - mxArray *Setup = mxCreateStructArray(1, dims, std::extent_v<decltype(field_names)>, field_names); - mxSetFieldByNumber(Setup, 0, type, mxCreateString("ilutp")); - mxSetFieldByNumber(Setup, 0, droptol, mxCreateDoubleScalar(lu_inc_tol)); - mxSetFieldByNumber(Setup, 0, milu, mxCreateString("off")); - mxSetFieldByNumber(Setup, 0, udiag, mxCreateDoubleScalar(0)); - mxSetFieldByNumber(Setup, 0, thresh, mxCreateDoubleScalar(1)); - mxArray *lhs0[2]; - mxArray *rhs0[] = { A_m, Setup }; - if (mexCallMATLAB(std::extent_v<decltype(lhs0)>, lhs0, std::extent_v<decltype(rhs0)>, rhs0, "ilu")) - throw FatalException{"In BiCGStab, the incomplete LU decomposition (ilu) has failed"}; - L1 = lhs0[0]; - U1 = lhs0[1]; - mxDestroyArray(Setup); - } - double flags = 2; - mxArray *z = nullptr; - if (steady_state) /*Octave BicStab algorihtm involves a 0 division in case of a preconditionner equal to the LU decomposition of A matrix*/ - { - mxArray *res = mult_SAT_B(Sparse_transpose(A_m), x0_m); - double *resid = mxGetPr(res); - double *b = mxGetPr(b_m); - for (int i = 0; i < static_cast<int>(n); i++) - resid[i] = b[i] - resid[i]; - mxArray *lhs[1]; - mxArray *rhs[] = { L1, res }; - mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "mldivide"); - mxArray *rhs2[] = { U1, lhs[0] }; - mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs2)>, rhs2, "mldivide"); - z = lhs[0]; - double *phat = mxGetPr(z); - double *x0 = mxGetPr(x0_m); - for (int i = 0; i < static_cast<int>(n); i++) - phat[i] = x0[i] + phat[i]; - - /*Check the solution*/ - res = mult_SAT_B(Sparse_transpose(A_m), z); - resid = mxGetPr(res); - double cum_abs = 0; - for (int i = 0; i < static_cast<int>(n); i++) - { - resid[i] = b[i] - resid[i]; - cum_abs += fabs(resid[i]); - } - if (cum_abs > 1e-7) - flags = 2; - else - flags = 0; - mxDestroyArray(res); - } - - if (flags == 2) - { - if (preconditioner == 0) - { - /*[za,flag1] = bicgstab(g1a,b,1e-6,Blck_size*periods,L1,U1);*/ - mxArray *rhs[] = { A_m, b_m, mxCreateDoubleScalar(1e-6), - mxCreateDoubleScalar(static_cast<double>(n)), Diag }; - mxArray *lhs[2]; - mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "bicgstab"); - z = lhs[0]; - mxArray *flag = lhs[1]; - double *flag1 = mxGetPr(flag); - flags = flag1[0]; - mxDestroyArray(flag); - mxDestroyArray(rhs[2]); - mxDestroyArray(rhs[3]); - mxDestroyArray(rhs[4]); - } - else if (preconditioner == 1) - { - /*[za,flag1] = bicgstab(g1a,b,1e-6,Blck_size*periods,L1,U1);*/ - mxArray *rhs[] = { A_m, b_m, mxCreateDoubleScalar(1e-6), - mxCreateDoubleScalar(static_cast<double>(n)), L1, U1, x0_m }; - mxArray *lhs[2]; - mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "bicgstab"); - z = lhs[0]; - mxArray *flag = lhs[1]; - double *flag1 = mxGetPr(flag); - flags = flag1[0]; - mxDestroyArray(flag); - mxDestroyArray(rhs[2]); - mxDestroyArray(rhs[3]); - mxDestroyArray(rhs[4]); - mxDestroyArray(rhs[5]); - } - } - - if (flags > 0) - { - if (flags == 1) - mexWarnMsgTxt(("Error in bytecode: No convergence inside BiCGStab, in block " - + to_string(block+1)).c_str()); - else if (flags == 2) - mexWarnMsgTxt(("Error in bytecode: Preconditioner is ill-conditioned, in block " - + to_string(block+1)).c_str()); - else if (flags == 3) - mexWarnMsgTxt(("Error in bytecode: BiCGStab stagnated (Two consecutive iterates were the same.), in block " - + to_string(block+1)).c_str()); - lu_inc_tol /= 10; - } - else - { - double *res = mxGetPr(z); - if (is_two_boundaries) - for (int i = 0; i < static_cast<int>(n); i++) - { - int eq = index_vara[i+Size*y_kmin]; - double yy = -(res[i] + y[eq]); - direction[eq] = yy; - y[eq] += slowc * yy; - } - else - for (int i = 0; i < static_cast<int>(n); i++) - { - int eq = index_vara[i]; - double yy = -(res[i] + y[eq+it_*y_size]); - direction[eq] = yy; - y[eq+it_*y_size] += slowc * yy; - } - } - mxDestroyArray(A_m); - mxDestroyArray(b_m); - mxDestroyArray(x0_m); - mxDestroyArray(z); -} - -void -dynSparseMatrix::Singular_display(int block, int Size) -{ - bool zero_solution; - Simple_Init(Size, IM_i, zero_solution); - mxArray *rhs[] = { mxCreateDoubleMatrix(Size, Size, mxREAL) }; - double *pind = mxGetPr(rhs[0]); - for (int j = 0; j < Size * Size; j++) - pind[j] = 0.0; - for (int ii = 0; ii < Size; ii++) - { - NonZeroElem *first; - int nb_eq = At_Col(ii, &first); - for (int j = 0; j < nb_eq; j++) - { - int k = first->u_index; - int jj = first->r_index; - pind[ii * Size + jj] = u[k]; - first = first->NZE_C_N; - } - } - mxArray *lhs[3]; - mexCallMATLAB(std::extent_v<decltype(lhs)>, lhs, std::extent_v<decltype(rhs)>, rhs, "svd"); - mxArray *SVD_u = lhs[0]; - mxArray *SVD_s = lhs[1]; - double *SVD_ps = mxGetPr(SVD_s); - double *SVD_pu = mxGetPr(SVD_u); - for (int i = 0; i < Size; i++) - if (abs(SVD_ps[i * (1 + Size)]) < 1e-12) - { - mexPrintf(" The following equations form a linear combination:\n "); - double max_u = 0; - for (int j = 0; j < Size; j++) - if (abs(SVD_pu[j + i * Size]) > abs(max_u)) - max_u = SVD_pu[j + i * Size]; - vector<int> equ_list; - for (int j = 0; j < Size; j++) - { - double rr = SVD_pu[j + i * Size] / max_u; - if (rr < -1e-10) - { - equ_list.push_back(j); - if (rr != -1) - mexPrintf(" - %3.2f*Dequ_%d_dy", abs(rr), j+1); - else - mexPrintf(" - Dequ_%d_dy", j+1); - } - else if (rr > 1e-10) - { - equ_list.push_back(j); - if (j > 0) - if (rr != 1) - mexPrintf(" + %3.2f*Dequ_%d_dy", rr, j+1); - else - mexPrintf(" + Dequ_%d_dy", j+1); - else if (rr != 1) - mexPrintf(" %3.2f*Dequ_%d_dy", rr, j+1); - else - mexPrintf(" Dequ_%d_dy", j+1); - } - } - mexPrintf(" = 0\n"); - } - mxDestroyArray(lhs[0]); - mxDestroyArray(lhs[1]); - mxDestroyArray(lhs[2]); - if (block > 1) - throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system in block " - + to_string(block+1)}; - else - throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system"}; -} - -bool -dynSparseMatrix::Solve_ByteCode_Sparse_GaussianElimination(int Size, int blck, int it_) -{ - int pivj = 0, pivk = 0; - NonZeroElem **bc = static_cast<NonZeroElem **>(mxMalloc(Size*sizeof(*bc))); - test_mxMalloc(bc, __LINE__, __FILE__, __func__, Size*sizeof(*bc)); - double *piv_v = static_cast<double *>(mxMalloc(Size*sizeof(double))); - test_mxMalloc(piv_v, __LINE__, __FILE__, __func__, Size*sizeof(double)); - int *pivj_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivj_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); - int *pivk_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivk_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); - int *NR = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(NR, __LINE__, __FILE__, __func__, Size*sizeof(int)); - - for (int i = 0; i < Size; i++) - { - /*finding the max-pivot*/ - double piv = 0, piv_abs = 0; - NonZeroElem *first; - int nb_eq = At_Col(i, &first); - int l = 0; - int N_max = 0; - bool one = false; - for (int j = 0; j < nb_eq; j++) - { - if (!line_done[first->r_index]) - { - int k = first->u_index; - int jj = first->r_index; - int NRow_jj = NRow(jj); - - piv_v[l] = u[k]; - double piv_fabs = fabs(u[k]); - pivj_v[l] = jj; - pivk_v[l] = k; - NR[l] = NRow_jj; - if (NRow_jj == 1 && !one) - { - one = true; - piv_abs = piv_fabs; - N_max = NRow_jj; - } - if (!one) - { - if (piv_fabs > piv_abs) - piv_abs = piv_fabs; - if (NRow_jj > N_max) - N_max = NRow_jj; - } - else if (NRow_jj == 1) - { - if (piv_fabs > piv_abs) - piv_abs = piv_fabs; - if (NRow_jj > N_max) - N_max = NRow_jj; - } - l++; - } - first = first->NZE_C_N; - } - if (piv_abs < eps) - { - mxFree(piv_v); - mxFree(pivj_v); - mxFree(pivk_v); - mxFree(NR); - mxFree(bc); - if (steady_state) - { - if (verbosity >= 1) - { - if (blck > 1) - mexPrintf("Error: singular system in Simulate_NG in block %d\n", blck+1); - else - mexPrintf("Error: singular system in Simulate_NG"); - } - return true; - } - else - { - if (blck > 1) - throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system in block " - + to_string(blck+1)}; - else - throw FatalException{"In Solve_ByteCode_Sparse_GaussianElimination, singular system"}; - } - } - double markovitz = 0, markovitz_max = -9e70; - if (!one) - for (int j = 0; j < l; j++) - { - if (N_max > 0 && NR[j] > 0) - { - if (fabs(piv_v[j]) > 0) - { - if (markowitz_c > 0) - markovitz = exp(log(fabs(piv_v[j])/piv_abs) - -markowitz_c*log(static_cast<double>(NR[j]) - /static_cast<double>(N_max))); - else - markovitz = fabs(piv_v[j])/piv_abs; - } - else - markovitz = 0; - } - else - markovitz = fabs(piv_v[j])/piv_abs; - if (markovitz > markovitz_max) - { - piv = piv_v[j]; - pivj = pivj_v[j]; //Line number - pivk = pivk_v[j]; //positi - markovitz_max = markovitz; - } - } - else - for (int j = 0; j < l; j++) - { - if (N_max > 0 && NR[j] > 0) - { - if (fabs(piv_v[j]) > 0) - { - if (markowitz_c > 0) - markovitz = exp(log(fabs(piv_v[j])/piv_abs) - -markowitz_c*log(static_cast<double>(NR[j]) - /static_cast<double>(N_max))); - else - markovitz = fabs(piv_v[j])/piv_abs; - } - else - markovitz = 0; - } - else - markovitz = fabs(piv_v[j])/piv_abs; - if (NR[j] == 1) - { - piv = piv_v[j]; - pivj = pivj_v[j]; //Line number - pivk = pivk_v[j]; //positi - markovitz_max = markovitz; - } - } - pivot[i] = pivj; - pivotk[i] = pivk; - pivotv[i] = piv; - line_done[pivj] = true; - - /*divide all the non zeros elements of the line pivj by the max_pivot*/ - int nb_var = At_Row(pivj, &first); - for (int j = 0; j < nb_var; j++) - { - u[first->u_index] /= piv; - first = first->NZE_R_N; - } - u[b[pivj]] /= piv; - /*subtract the elements on the non treated lines*/ - nb_eq = At_Col(i, &first); - NonZeroElem *first_piva; - int nb_var_piva = At_Row(pivj, &first_piva); - int nb_eq_todo = 0; - for (int j = 0; j < nb_eq && first; j++) - { - if (!line_done[first->r_index]) - bc[nb_eq_todo++] = first; - first = first->NZE_C_N; - } - for (int j = 0; j < nb_eq_todo; j++) - { - first = bc[j]; - int row = first->r_index; - double first_elem = u[first->u_index]; - - int nb_var_piv = nb_var_piva; - NonZeroElem *first_piv = first_piva; - NonZeroElem *first_sub; - int nb_var_sub = At_Row(row, &first_sub); - int l_sub = 0, l_piv = 0; - int sub_c_index = first_sub->c_index, piv_c_index = first_piv->c_index; - while (l_sub < nb_var_sub || l_piv < nb_var_piv) - if (l_sub < nb_var_sub && (sub_c_index < piv_c_index || l_piv >= nb_var_piv)) - { - first_sub = first_sub->NZE_R_N; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size; - l_sub++; - } - else if (sub_c_index > piv_c_index || l_sub >= nb_var_sub) - { - int tmp_u_count = Get_u(); - Insert(row, first_piv->c_index, tmp_u_count, 0); - u[tmp_u_count] = -u[first_piv->u_index]*first_elem; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size; - l_piv++; - } - else - { - if (i == sub_c_index) - { - NonZeroElem *firsta = first; - NonZeroElem *first_suba = first_sub->NZE_R_N; - Delete(first_sub->r_index, first_sub->c_index); - first = firsta->NZE_C_N; - first_sub = first_suba; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size; - l_sub++; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size; - l_piv++; - } - else - { - u[first_sub->u_index] -= u[first_piv->u_index]*first_elem; - first_sub = first_sub->NZE_R_N; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size; - l_sub++; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size; - l_piv++; - } - } - u[b[row]] -= u[b[pivj]]*first_elem; - } - } - double slowc_lbx = slowc; - for (int i = 0; i < y_size; i++) - ya[i+it_*y_size] = y[i+it_*y_size]; - - slowc_save = slowc; - simple_bksub(it_, Size, slowc_lbx); - End_GE(); - mxFree(piv_v); - mxFree(pivj_v); - mxFree(pivk_v); - mxFree(NR); - mxFree(bc); - return false; -} - -void -dynSparseMatrix::Solve_ByteCode_Symbolic_Sparse_GaussianElimination(int Size, bool symbolic, int Block_number) -{ - /*Triangularisation at each period of a block using a simple gaussian Elimination*/ - int *save_op = nullptr, *save_opa = nullptr, *save_opaa = nullptr; - long int nop = 0, nopa = 0; - bool record = false; - - int pivj = 0, pivk = 0; - int tbreak = 0, last_period = periods; - - double *piv_v = static_cast<double *>(mxMalloc(Size*sizeof(double))); - test_mxMalloc(piv_v, __LINE__, __FILE__, __func__, Size*sizeof(double)); - int *pivj_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivj_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); - int *pivk_v = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(pivk_v, __LINE__, __FILE__, __func__, Size*sizeof(int)); - int *NR = static_cast<int *>(mxMalloc(Size*sizeof(int))); - test_mxMalloc(NR, __LINE__, __FILE__, __func__, Size*sizeof(int)); - NonZeroElem **bc = static_cast<NonZeroElem **>(mxMalloc(Size*sizeof(NonZeroElem *))); - test_mxMalloc(bc, __LINE__, __FILE__, __func__, Size*sizeof(NonZeroElem *)); - - for (int t = 0; t < periods; t++) - { -#ifdef MATLAB_MEX_FILE - if (utIsInterruptPending()) - throw UserException{}; -#endif - - if (record && symbolic) - { - save_op = static_cast<int *>(mxMalloc(nop*sizeof(int))); - test_mxMalloc(save_op, __LINE__, __FILE__, __func__, nop*sizeof(int)); - nopa = nop; - } - nop = 0; - Clear_u(); - int ti = t*Size; - for (int i = ti; i < Size+ti; i++) - { - /*finding the max-pivot*/ - double piv = 0, piv_abs = 0; - NonZeroElem *first; - int nb_eq = At_Col(i, 0, &first); - if ((symbolic && t <= start_compare) || !symbolic) - { - int l = 0, N_max = 0; - bool one = false; - piv_abs = 0; - for (int j = 0; j < nb_eq; j++) - { - if (!line_done[first->r_index]) - { - int k = first->u_index; - int jj = first->r_index; - int NRow_jj = NRow(jj); - piv_v[l] = u[k]; - double piv_fabs = fabs(u[k]); - pivj_v[l] = jj; - pivk_v[l] = k; - NR[l] = NRow_jj; - if (NRow_jj == 1 && !one) - { - one = true; - piv_abs = piv_fabs; - N_max = NRow_jj; - } - if (!one) - { - if (piv_fabs > piv_abs) - piv_abs = piv_fabs; - if (NRow_jj > N_max) - N_max = NRow_jj; - } - else if (NRow_jj == 1) - { - if (piv_fabs > piv_abs) - piv_abs = piv_fabs; - if (NRow_jj > N_max) - N_max = NRow_jj; - } - l++; - } - first = first->NZE_C_N; - } - double markovitz = 0, markovitz_max = -9e70; - int NR_max = 0; - if (!one) - for (int j = 0; j < l; j++) - { - if (N_max > 0 && NR[j] > 0) - { - if (fabs(piv_v[j]) > 0) - { - if (markowitz_c > 0) - markovitz = exp(log(fabs(piv_v[j])/piv_abs) - -markowitz_c*log(static_cast<double>(NR[j]) - /static_cast<double>(N_max))); - else - markovitz = fabs(piv_v[j])/piv_abs; - } - else - markovitz = 0; - } - else - markovitz = fabs(piv_v[j])/piv_abs; - if (markovitz > markovitz_max) - { - piv = piv_v[j]; - pivj = pivj_v[j]; //Line number - pivk = pivk_v[j]; //positi - markovitz_max = markovitz; - NR_max = NR[j]; - } - } - else - for (int j = 0; j < l; j++) - { - if (N_max > 0 && NR[j] > 0) - { - if (fabs(piv_v[j]) > 0) - { - if (markowitz_c > 0) - markovitz = exp(log(fabs(piv_v[j])/piv_abs) - -markowitz_c*log(static_cast<double>(NR[j]) - /static_cast<double>(N_max))); - else - markovitz = fabs(piv_v[j])/piv_abs; - } - else - markovitz = 0; - } - else - markovitz = fabs(piv_v[j])/piv_abs; - if (NR[j] == 1) - { - piv = piv_v[j]; - pivj = pivj_v[j]; //Line number - pivk = pivk_v[j]; //positi - markovitz_max = markovitz; - NR_max = NR[j]; - } - } - if (fabs(piv) < eps && verbosity >= 1) - mexPrintf("==> Error NR_max=%d, N_max=%d and piv=%f, piv_abs=%f, markovitz_max=%f\n", NR_max, N_max, piv, piv_abs, markovitz_max); - if (NR_max == 0 && verbosity >= 1) - mexPrintf("==> Error NR_max=0 and piv=%f, markovitz_max=%f\n", piv, markovitz_max); - pivot[i] = pivj; - pivot_save[i] = pivj; - pivotk[i] = pivk; - pivotv[i] = piv; - } - else - { - pivj = pivot[i-Size]+Size; - pivot[i] = pivj; - At_Pos(pivj, i, &first); - pivk = first->u_index; - piv = u[pivk]; - piv_abs = fabs(piv); - } - line_done[pivj] = true; - - if (record && symbolic) - { - if (nop+1 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - t_save_op_s *save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[nop]); - save_op_s->operat = IFLD; - save_op_s->first = pivk; - save_op_s->lag = 0; - nop += 2; - if (piv_abs < eps) - { - if (Block_number > 1) - throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system in block " - + to_string(Block_number+1)}; - else - throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system"}; - } - /*divide all the non zeros elements of the line pivj by the max_pivot*/ - int nb_var = At_Row(pivj, &first); - for (int j = 0; j < nb_var; j++) - { - u[first->u_index] /= piv; - if (nop+j*2+1 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[nop+j*2]); - save_op_s->operat = IFDIV; - save_op_s->first = first->u_index; - save_op_s->lag = first->lag_index; - first = first->NZE_R_N; - } - nop += nb_var*2; - u[b[pivj]] /= piv; - if (nop+1 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - save_op_s = reinterpret_cast<t_save_op_s *>(&save_op[nop]); - save_op_s->operat = IFDIV; - save_op_s->first = b[pivj]; - save_op_s->lag = 0; - nop += 2; - // Subtract the elements on the non treated lines - nb_eq = At_Col(i, &first); - NonZeroElem *first_piva; - int nb_var_piva = At_Row(pivj, &first_piva); - - int nb_eq_todo = 0; - for (int j = 0; j < nb_eq && first; j++) - { - if (!line_done[first->r_index]) - bc[nb_eq_todo++] = first; - first = first->NZE_C_N; - } - for (int j = 0; j < nb_eq_todo; j++) - { - t_save_op_s *save_op_s_l; - NonZeroElem *first = bc[j]; - int row = first->r_index; - double first_elem = u[first->u_index]; - if (nop+1 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); - save_op_s_l->operat = IFLD; - save_op_s_l->first = first->u_index; - save_op_s_l->lag = abs(first->lag_index); - nop += 2; - - int nb_var_piv = nb_var_piva; - NonZeroElem *first_piv = first_piva; - NonZeroElem *first_sub; - int nb_var_sub = At_Row(row, &first_sub); - int l_sub = 0; - int l_piv = 0; - int sub_c_index = first_sub->c_index; - int piv_c_index = first_piv->c_index; - int tmp_lag = first_sub->lag_index; - while (l_sub < nb_var_sub /*=NRow(row)*/ || l_piv < nb_var_piv) - { - if (l_sub < nb_var_sub && (sub_c_index < piv_c_index || l_piv >= nb_var_piv)) - { - /* There is no nonzero element at row pivot for this - column ⇒ Nothing to do for the current element got to - next column */ - first_sub = first_sub->NZE_R_N; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size*periods; - l_sub++; - } - else if (sub_c_index > piv_c_index || l_sub >= nb_var_sub) - { - // There is an nonzero element at row pivot but not at the current row=> insert a negative element in the current row - int tmp_u_count = Get_u(); - int lag = first_piv->c_index/Size-row/Size; - Insert(row, first_piv->c_index, tmp_u_count, lag); - u[tmp_u_count] = -u[first_piv->u_index]*first_elem; - if (nop+2 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); - save_op_s_l->operat = IFLESS; - save_op_s_l->first = tmp_u_count; - save_op_s_l->second = first_piv->u_index; - save_op_s_l->lag = max(first_piv->lag_index, abs(tmp_lag)); - nop += 3; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size*periods; - l_piv++; - } - else /*first_sub->c_index==first_piv->c_index*/ - { - if (i == sub_c_index) - { - NonZeroElem *firsta = first; - NonZeroElem *first_suba = first_sub->NZE_R_N; - Delete(first_sub->r_index, first_sub->c_index); - first = firsta->NZE_C_N; - first_sub = first_suba; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size*periods; - l_sub++; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size*periods; - l_piv++; - } - else - { - u[first_sub->u_index] -= u[first_piv->u_index]*first_elem; - if (nop+3 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); - save_op_s_l->operat = IFSUB; - save_op_s_l->first = first_sub->u_index; - save_op_s_l->second = first_piv->u_index; - save_op_s_l->lag = max(abs(tmp_lag), first_piv->lag_index); - nop += 3; - first_sub = first_sub->NZE_R_N; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size*periods; - l_sub++; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size*periods; - l_piv++; - } - } - } - u[b[row]] -= u[b[pivj]]*first_elem; - - if (nop+3 >= nopa) - { - nopa = static_cast<long>(mem_increasing_factor*static_cast<double>(nopa)); - save_op = static_cast<int *>(mxRealloc(save_op, nopa*sizeof(int))); - } - save_op_s_l = reinterpret_cast<t_save_op_s *>(&save_op[nop]); - save_op_s_l->operat = IFSUB; - save_op_s_l->first = b[row]; - save_op_s_l->second = b[pivj]; - save_op_s_l->lag = abs(tmp_lag); - nop += 3; - } - } - else if (symbolic) - { - nop += 2; - if (piv_abs < eps) - { - if (Block_number > 1) - throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system in block " - + to_string(Block_number+1)}; - else - throw FatalException{"In Solve_ByteCode_Symbolic_Sparse_GaussianElimination, singular system"}; - } - // Divide all the non zeros elements of the line pivj by the max_pivot - int nb_var = At_Row(pivj, &first); - for (int j = 0; j < nb_var; j++) - { - u[first->u_index] /= piv; - first = first->NZE_R_N; - } - nop += nb_var*2; - u[b[pivj]] /= piv; - nop += 2; - // Subtract the elements on the non treated lines - nb_eq = At_Col(i, &first); - NonZeroElem *first_piva; - int nb_var_piva = At_Row(pivj, &first_piva); - - int nb_eq_todo = 0; - for (int j = 0; j < nb_eq && first; j++) - { - if (!line_done[first->r_index]) - bc[nb_eq_todo++] = first; - first = first->NZE_C_N; - } - for (int j = 0; j < nb_eq_todo; j++) - { - NonZeroElem *first = bc[j]; - int row = first->r_index; - double first_elem = u[first->u_index]; - nop += 2; - int nb_var_piv = nb_var_piva; - NonZeroElem *first_piv = first_piva; - NonZeroElem *first_sub; - int nb_var_sub = At_Row(row, &first_sub); - int l_sub = 0; - int l_piv = 0; - int sub_c_index = first_sub->c_index; - int piv_c_index = first_piv->c_index; - while (l_sub < nb_var_sub /*= NRow(row)*/ || l_piv < nb_var_piv) - { - if (l_sub < nb_var_sub && (sub_c_index < piv_c_index || l_piv >= nb_var_piv)) - { - /* There is no nonzero element at row pivot for this - column ⇒ Nothing to do for the current element got to - next column */ - first_sub = first_sub->NZE_R_N; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size*periods; - l_sub++; - } - else if (sub_c_index > piv_c_index || l_sub >= nb_var_sub) - { - /* There is an nonzero element at row pivot but not - at the current row ⇒ insert a negative element in the - current row */ - int tmp_u_count = Get_u(); - int lag = first_piv->c_index/Size-row/Size; - Insert(row, first_piv->c_index, tmp_u_count, lag); - u[tmp_u_count] = -u[first_piv->u_index]*first_elem; - nop += 3; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size*periods; - l_piv++; - } - else /*first_sub->c_index==first_piv->c_index*/ - { - if (i == sub_c_index) - { - NonZeroElem *firsta = first; - NonZeroElem *first_suba = first_sub->NZE_R_N; - Delete(first_sub->r_index, first_sub->c_index); - first = firsta->NZE_C_N; - first_sub = first_suba; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size*periods; - l_sub++; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size*periods; - l_piv++; - } - else - { - u[first_sub->u_index] -= u[first_piv->u_index]*first_elem; - nop += 3; - first_sub = first_sub->NZE_R_N; - if (first_sub) - sub_c_index = first_sub->c_index; - else - sub_c_index = Size*periods; - l_sub++; - first_piv = first_piv->NZE_R_N; - if (first_piv) - piv_c_index = first_piv->c_index; - else - piv_c_index = Size*periods; - l_piv++; - } - } - } - u[b[row]] -= u[b[pivj]]*first_elem; - nop += 3; - } - } - } - if (symbolic) - { - if (t > static_cast<int>(periods*0.35)) - { - symbolic = false; - mxFree(save_opaa); - mxFree(save_opa); - mxFree(save_op); - } - else if (record && nop == nop1) - { - if (t > static_cast<int>(periods*0.35)) - { - symbolic = false; - if (save_opaa) - { - mxFree(save_opaa); - save_opaa = nullptr; - } - if (save_opa) - { - mxFree(save_opa); - save_opa = nullptr; - } - if (save_op) - { - mxFree(save_op); - save_op = nullptr; - } - } - else if (save_opa && save_opaa) - { - if (compare(save_op, save_opa, save_opaa, t, periods, nop, Size)) - { - tbreak = t; - tbreak_g = tbreak; - break; - } - } - if (save_opa) - { - if (save_opaa) - { - mxFree(save_opaa); - save_opaa = nullptr; - } - save_opaa = save_opa; - } - save_opa = save_op; - } - else - { - if (nop == nop1) - record = true; - else - { - record = false; - if (save_opa) - { - mxFree(save_opa); - save_opa = nullptr; - } - if (save_opaa) - { - mxFree(save_opaa); - save_opaa = nullptr; - } - } - } - nop1 = nop; - } - } - mxFree(bc); - mxFree(piv_v); - mxFree(pivj_v); - mxFree(pivk_v); - mxFree(NR); - if (symbolic) - { - if (save_op) - mxFree(save_op); - if (save_opa) - mxFree(save_opa); - if (save_opaa) - mxFree(save_opaa); - } - - // The backward substitution - double slowc_lbx = slowc; - for (int i = 0; i < y_size*(periods+y_kmin); i++) - ya[i] = y[i]; - slowc_save = slowc; - bksub(tbreak, last_period, Size, slowc_lbx); - End_GE(); -} - -void -dynSparseMatrix::Check_and_Correct_Previous_Iteration(int y_size, int size) -{ - if (isnan(res1) || isinf(res1) || (res2 > g0 && iter > 0)) - { - while (isnan(res1) || isinf(res1)) - { - prev_slowc_save = slowc_save; - slowc_save /= 1.1; - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; - } - compute_complete(true, res1, res2, max_res, max_res_idx); - } - - while (res2 > g0 && slowc_save > 1e-1) - { - prev_slowc_save = slowc_save; - slowc_save /= 1.5; - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; - } - compute_complete(true, res1, res2, max_res, max_res_idx); - } - if (verbosity >= 2) - mexPrintf("Error: Simulation diverging, trying to correct it using slowc=%f\n", slowc_save); - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; - } - compute_complete(false, res1, res2, max_res, max_res_idx); - } - else - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - y[eq+it_*y_size] = ya[eq+it_*y_size] + slowc_save * direction[eq+it_*y_size]; - } - slowc_save = slowc; -} - -bool -dynSparseMatrix::Simulate_One_Boundary(int block_num, int y_size, int size) -{ - mxArray *b_m = nullptr, *A_m = nullptr, *x0_m = nullptr; - SuiteSparse_long *Ap = nullptr, *Ai = nullptr; - double *Ax = nullptr, *b = nullptr; - int preconditioner = 1; - - try_at_iteration = 0; - Clear_u(); - bool singular_system = false; - u_count_alloc_save = u_count_alloc; - - if (isnan(res1) || isinf(res1)) - { -#ifdef DEBUG - for (int j = 0; j < y_size; j++) - { - bool select = false; - for (int i = 0; i < size; i++) - if (j == index_vara[i]) - { - select = true; - break; - } - if (select) - mexPrintf("-> variable %s (%d) at time %d = %f direction = %f\n", get_variable(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); - else - mexPrintf(" variable %s (%d) at time %d = %f direction = %f\n", get_variable(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); - } -#endif - if (steady_state) - { - if (verbosity >= 1) - { - if (iter == 0) - mexPrintf(" the initial values of endogenous variables are too far from the solution.\nChange them!\n"); - else - mexPrintf(" dynare cannot improve the simulation in block %d at time %d (variable %d)\n", block_num+1, it_+1, index_vara[max_res_idx]+1); - mexEvalString("drawnow;"); - } - } - else - { - if (iter == 0) - throw FatalException{"In Simulate_One_Boundary, The initial values of endogenous variables are too far from the solution. Change them!"}; - else - throw FatalException{"In Simulate_One_Boundary, Dynare cannot improve the simulation in block " - + to_string(block_num+1) + " at time " + to_string(it_+1) - + " (variable " + to_string(index_vara[max_res_idx]+1)}; - } - } - - if (verbosity >= 1) - { - if (steady_state) - { - switch (solve_algo) - { - case 5: - mexPrintf("MODEL STEADY STATE: (method=Sparse Gaussian Elimination)\n"); - break; - case 6: - mexPrintf("MODEL STEADY STATE: (method=Sparse LU)\n"); - break; - case 7: - mexPrintf(preconditioner_print_out("MODEL STEADY STATE: (method=GMRES)\n", preconditioner, true).c_str()); - break; - case 8: - mexPrintf(preconditioner_print_out("MODEL STEADY STATE: (method=BiCGStab)\n", preconditioner, true).c_str()); - break; - } - } - - mexPrintf("------------------------------------\n"); - mexPrintf(" Iteration no. %d\n", iter+1); - mexPrintf(" Inf-norm error = %.3e\n", static_cast<double>(max_res)); - mexPrintf(" 2-norm error = %.3e\n", static_cast<double>(sqrt(res2))); - mexPrintf(" 1-norm error = %.3e\n", static_cast<double>(res1)); - mexPrintf("------------------------------------\n"); - } - bool zero_solution; - - if ((solve_algo == 5 && steady_state) || (stack_solve_algo == 5 && !steady_state)) - Simple_Init(size, IM_i, zero_solution); - else - { - x0_m = mxCreateDoubleMatrix(size, 1, mxREAL); - if (!x0_m) - throw FatalException{"In Simulate_One_Boundary, can't allocate x0_m vector"}; - if (!((solve_algo == 6 && steady_state) - || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 - || stack_solve_algo == 6) && !steady_state))) - { - b_m = mxCreateDoubleMatrix(size, 1, mxREAL); - if (!b_m) - throw FatalException{"In Simulate_One_Boundary, can't allocate b_m vector"}; - A_m = mxCreateSparse(size, size, min(static_cast<int>(IM_i.size()*2), size * size), mxREAL); - if (!A_m) - throw FatalException{"In Simulate_One_Boundary, can't allocate A_m matrix"}; - Init_Matlab_Sparse_Simple(size, IM_i, A_m, b_m, zero_solution, x0_m); - } - else - { - Init_UMFPACK_Sparse_Simple(size, IM_i, &Ap, &Ai, &Ax, &b, zero_solution, x0_m); - if (Ap_save[size] != Ap[size]) - { - mxFree(Ai_save); - mxFree(Ax_save); - Ai_save = static_cast<SuiteSparse_long *>(mxMalloc(Ap[size] * sizeof(SuiteSparse_long))); - test_mxMalloc(Ai_save, __LINE__, __FILE__, __func__, Ap[size] * sizeof(SuiteSparse_long)); - Ax_save = static_cast<double *>(mxMalloc(Ap[size] * sizeof(double))); - test_mxMalloc(Ax_save, __LINE__, __FILE__, __func__, Ap[size] * sizeof(double)); - } - copy_n(Ap, size + 1, Ap_save); - copy_n(Ai, Ap[size], Ai_save); - copy_n(Ax, Ap[size], Ax_save); - copy_n(b, size, b_save); - } - } - if (zero_solution) - for (int i = 0; i < size; i++) - { - int eq = index_vara[i]; - double yy = -(y[eq+it_*y_size]); - direction[eq] = yy; - y[eq+it_*y_size] += slowc * yy; - } - else - { - if ((solve_algo == 5 && steady_state) || (stack_solve_algo == 5 && !steady_state)) - singular_system = Solve_ByteCode_Sparse_GaussianElimination(size, block_num, it_); - else if ((solve_algo == 7 && steady_state) || (stack_solve_algo == 2 && !steady_state)) - Solve_Matlab_GMRES(A_m, b_m, size, slowc, block_num, false, it_, x0_m); - else if ((solve_algo == 8 && steady_state) || (stack_solve_algo == 3 && !steady_state)) - Solve_Matlab_BiCGStab(A_m, b_m, size, slowc, block_num, false, it_, x0_m, preconditioner); - else if ((solve_algo == 6 && steady_state) || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 || stack_solve_algo == 6) && !steady_state)) - { - Solve_LU_UMFPack(Ap, Ai, Ax, b, size, size, slowc, false, it_); - mxDestroyArray(x0_m); - } - } - return singular_system; -} - -bool -dynSparseMatrix::solve_linear(int block_num, int y_size, int size, int iter) -{ - bool cvg = false; - compute_complete(false, res1, res2, max_res, max_res_idx); - cvg = (max_res < solve_tolf); - if (!cvg || isnan(res1) || isinf(res1)) - { - if (iter) - Check_and_Correct_Previous_Iteration(y_size, size); - bool singular_system = Simulate_One_Boundary(block_num, y_size, size); - if (singular_system && verbosity >= 1) - Singular_display(block_num, size); - } - return cvg; -} - -void -dynSparseMatrix::solve_non_linear(int block_num, int y_size, int size) -{ - max_res_idx = 0; - bool cvg = false; - iter = 0; - glambda2 = g0 = very_big; - while (!cvg && iter < maxit_) - { - cvg = solve_linear(block_num, y_size, size, iter); - g0 = res2; - iter++; - } - if (!cvg) - { - if (steady_state) - throw FatalException{"In Solve Forward/Backward Complete, convergence not achieved in block " - + to_string(block_num+1) + ", after " + to_string(iter) - + " iterations"}; - else - throw FatalException{"In Solve Forward/Backward Complete, convergence not achieved in block " - + to_string(block_num+1) + ", at time " + to_string(it_) - + ", after " + to_string(iter) + " iterations"}; - } -} - -void -dynSparseMatrix::Simulate_Newton_One_Boundary(bool forward) -{ - g1 = static_cast<double *>(mxMalloc(size*size*sizeof(double))); - test_mxMalloc(g1, __LINE__, __FILE__, __func__, size*size*sizeof(double)); - r = static_cast<double *>(mxMalloc(size*sizeof(double))); - test_mxMalloc(r, __LINE__, __FILE__, __func__, size*sizeof(double)); - iter = 0; - if ((solve_algo == 6 && steady_state) - || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 || stack_solve_algo == 6) && !steady_state)) - { - Ap_save = static_cast<SuiteSparse_long *>(mxMalloc((size + 1) * sizeof(SuiteSparse_long))); - test_mxMalloc(Ap_save, __LINE__, __FILE__, __func__, (size + 1) * sizeof(SuiteSparse_long)); - Ap_save[size] = 0; - Ai_save = static_cast<SuiteSparse_long *>(mxMalloc(1 * sizeof(SuiteSparse_long))); - test_mxMalloc(Ai_save, __LINE__, __FILE__, __func__, 1 * sizeof(SuiteSparse_long)); - Ax_save = static_cast<double *>(mxMalloc(1 * sizeof(double))); - test_mxMalloc(Ax_save, __LINE__, __FILE__, __func__, 1 * sizeof(double)); - b_save = static_cast<double *>(mxMalloc((size) * sizeof(SuiteSparse_long))); - test_mxMalloc(b_save, __LINE__, __FILE__, __func__, (size) * sizeof(SuiteSparse_long)); - } - if (steady_state) - { - it_ = 0; - if (!is_linear) - solve_non_linear(block_num, y_size, size); - else - solve_linear(block_num, y_size, size, 0); - } - else if (forward) - { - if (!is_linear) - for (it_ = y_kmin; it_ < periods+y_kmin; it_++) - solve_non_linear(block_num, y_size, size); - else - for (it_ = y_kmin; it_ < periods+y_kmin; it_++) - solve_linear(block_num, y_size, size, 0); - } - else - { - if (!is_linear) - for (it_ = periods+y_kmin-1; it_ >= y_kmin; it_--) - solve_non_linear(block_num, y_size, size); - else - for (it_ = periods+y_kmin-1; it_ >= y_kmin; it_--) - solve_linear(block_num, y_size, size, 0); - } - if ((solve_algo == 6 && steady_state) - || ((stack_solve_algo == 0 || stack_solve_algo == 1 || stack_solve_algo == 4 || stack_solve_algo == 6) && !steady_state)) - { - mxFree(Ap_save); - mxFree(Ai_save); - mxFree(Ax_save); - mxFree(b_save); - } - mxFree(g1); - mxFree(r); -} - -string -dynSparseMatrix::preconditioner_print_out(string s, int preconditioner, bool ss) -{ - int n = s.length(); - string tmp = ", preconditioner="; - switch (preconditioner) - { - case 0: - if (ss) - tmp.append("Jacobi on static jacobian"); - else - tmp.append("Jacobi on dynamic jacobian"); - break; - case 1: - if (ss) - tmp.append("incomplete lutp on static jacobian"); - else - tmp.append("incomplete lu0 on dynamic jacobian"); - break; - case 2: - tmp.append("incomplete lutp on dynamic jacobian"); - break; - case 3: - tmp.append("lu on static jacobian"); - break; - } - s.insert(n - 2, tmp); - return s; -} - -void -dynSparseMatrix::Simulate_Newton_Two_Boundaries(int blck, int y_size, int y_kmin, int y_kmax,int Size, int periods, bool cvg, int minimal_solving_periods, int stack_solve_algo, const vector_table_conditional_local_type &vector_table_conditional_local) -{ - double top = 0.5; - double bottom = 0.1; - int preconditioner = 2; - if (start_compare == 0) - start_compare = y_kmin; - u_count_alloc_save = u_count_alloc; - auto t1 { chrono::high_resolution_clock::now() }; - nop1 = 0; - mxArray *b_m = nullptr, *A_m = nullptr, *x0_m = nullptr; - double *Ax = nullptr, *b; - SuiteSparse_long *Ap = nullptr, *Ai = nullptr; - - if (isnan(res1) || isinf(res1) || (res2 > 12*g0 && iter > 0)) - { - if (iter == 0 || fabs(slowc_save) < 1e-8) - { - if (verbosity >= 2) - mexPrintf("res1 = %f, res2 = %f g0 = %f iter = %d\n", res1, res2, g0, iter); - for (int j = 0; j < y_size; j++) - { - bool select = false; - for (int i = 0; i < Size; i++) - if (j == index_vara[i]) - { - select = true; - break; - } - if (verbosity >= 2) - { - if (select) - mexPrintf("-> variable %s (%d) at time %d = %f direction = %f\n", symbol_table.getName(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); - else - mexPrintf(" variable %s (%d) at time %d = %f direction = %f\n", symbol_table.getName(SymbolType::endogenous, j).c_str(), j+1, it_, y[j+it_*y_size], direction[j+it_*y_size]); - } - } - if (iter == 0) - throw FatalException{"In Simulate_Newton_Two_Boundaries, the initial values of endogenous variables are too far from the solution. Change them!"}; - else - throw FatalException{"In Simulate_Newton_Two_Boundaries, dynare cannot improve the simulation in block " - + to_string(blck+1) + " at time " + to_string(it_+1) - + " (variable " + to_string(index_vara[max_res_idx]+1) - + " = " + to_string(max_res) + ")"}; - } - if (!(isnan(res1) || isinf(res1)) && !(isnan(g0) || isinf(g0)) - && (stack_solve_algo == 4 || stack_solve_algo == 5)) - { - if (try_at_iteration == 0) - { - prev_slowc_save = slowc_save; - slowc_save = max(-gp0 / (2 * (res2 - g0 - gp0)), bottom); - } - else - { - double t1 = res2 - gp0 * slowc_save - g0; - double t2 = glambda2 - gp0 * prev_slowc_save - g0; - double a = (1/(slowc_save * slowc_save) * t1 - - 1/(prev_slowc_save * prev_slowc_save) * t2) - / (slowc_save - prev_slowc_save); - double b = (-prev_slowc_save/(slowc_save * slowc_save) * t1 - + slowc_save/(prev_slowc_save * prev_slowc_save) * t2) - / (slowc_save - prev_slowc_save); - prev_slowc_save = slowc_save; - slowc_save = max(min(-b + sqrt(b*b - 3 * a * gp0) / (3 * a), - top * slowc_save), bottom * slowc_save); - } - glambda2 = res2; - try_at_iteration++; - if (slowc_save <= bottom) - { - for (int i = 0; i < y_size*(periods+y_kmin); i++) - y[i] = ya[i]+direction[i]; - g0 = res2; - gp0 = -res2; - try_at_iteration = 0; - iter--; - return; - } - } - else - { - prev_slowc_save = slowc_save; - slowc_save /= 1.05; - } - if (verbosity >= 2) - { - if (isnan(res1) || isinf(res1)) - mexPrintf("The model cannot be evaluated, trying to correct it using slowc=%f\n", slowc_save); - else - mexPrintf("Simulation diverging, trying to correct it using slowc=%f\n", slowc_save); - } - for (int i = 0; i < y_size*(periods+y_kmin); i++) - y[i] = ya[i]+slowc_save*direction[i]; - iter--; - return; - } - u_count += u_count_init; - if (stack_solve_algo == 5) - { - if (alt_symbolic && alt_symbolic_count < alt_symbolic_count_max) - { - if (verbosity >= 2) - mexPrintf("Pivoting method will be applied only to the first periods.\n"); - alt_symbolic = false; - symbolic = true; - markowitz_c = markowitz_c_s; - alt_symbolic_count++; - } - if (res1/res1a-1 > -0.3 && symbolic && iter > 0) - { - if (restart > 2) - { - if (verbosity >= 2) - mexPrintf("Divergence or slowdown occurred during simulation.\nIn the next iteration, pivoting method will be applied to all periods.\n"); - symbolic = false; - alt_symbolic = true; - markowitz_c_s = markowitz_c; - markowitz_c = 0; - } - else - { - if (verbosity >= 2) - mexPrintf("Divergence or slowdown occurred during simulation.\nIn the next iteration, pivoting method will be applied for a longer period.\n"); - start_compare = min(tbreak_g, periods); - restart++; - } - } - else - { - start_compare = max(y_kmin, minimal_solving_periods); - restart = 0; - } - } - res1a = res1; - if (verbosity >= 1) - { - if (iter == 0) - { - switch (stack_solve_algo) - { - 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; - case 3: - mexPrintf(preconditioner_print_out("MODEL SIMULATION: (method=BiCGStab)\n", preconditioner, false).c_str()); - break; - case 4: - mexPrintf("MODEL SIMULATION: (method=Sparse LU & optimal path length)\n"); - break; - case 5: - mexPrintf("MODEL SIMULATION: (method=Sparse Gaussian Elimination)\n"); - break; - } - } - mexPrintf("------------------------------------\n"); - mexPrintf(" Iteration no. %d\n", iter+1); - mexPrintf(" Inf-norm error = %.3e\n", static_cast<double>(max_res)); - mexPrintf(" 2-norm error = %.3e\n", static_cast<double>(sqrt(res2))); - mexPrintf(" 1-norm error = %.3e\n", static_cast<double>(res1)); - mexPrintf("------------------------------------\n"); - mexEvalString("drawnow;"); - } - if (cvg) - return; - else - { - if (stack_solve_algo == 5) - Init_GE(periods, y_kmin, y_kmax, Size, IM_i); - else - { - x0_m = mxCreateDoubleMatrix(periods*Size, 1, mxREAL); - if (!x0_m) - throw FatalException{"In Simulate_Newton_Two_Boundaries, can't allocate x0_m vector"}; - if (stack_solve_algo == 0 || stack_solve_algo == 4) - Init_UMFPACK_Sparse(periods, y_kmin, y_kmax, Size, IM_i, &Ap, &Ai, &Ax, &b, x0_m, vector_table_conditional_local, blck); - else - { - b_m = mxCreateDoubleMatrix(periods*Size, 1, mxREAL); - if (!b_m) - throw FatalException{"In Simulate_Newton_Two_Boundaries, can't allocate b_m vector"}; - if (stack_solve_algo != 0 && stack_solve_algo != 4) - { - A_m = mxCreateSparse(periods*Size, periods*Size, IM_i.size()* periods*2, mxREAL); - if (!A_m) - throw FatalException{"In Simulate_Newton_Two_Boundaries, can't allocate A_m matrix"}; - } - Init_Matlab_Sparse(periods, y_kmin, y_kmax, Size, IM_i, A_m, b_m, x0_m); - } - } - if (stack_solve_algo == 0 || stack_solve_algo == 4) - { - Solve_LU_UMFPack(Ap, Ai, Ax, b, Size * periods, Size, slowc, true, 0, vector_table_conditional_local); - mxDestroyArray(x0_m); - } - else if (stack_solve_algo == 1 || stack_solve_algo == 6) - { - Solve_Matlab_Relaxation(A_m, b_m, Size, slowc); - mxDestroyArray(x0_m); - } - else if (stack_solve_algo == 2) - Solve_Matlab_GMRES(A_m, b_m, Size, slowc, blck, true, 0, x0_m); - else if (stack_solve_algo == 3) - Solve_Matlab_BiCGStab(A_m, b_m, Size, slowc, blck, true, 0, x0_m, 1); - else if (stack_solve_algo == 5) - Solve_ByteCode_Symbolic_Sparse_GaussianElimination(Size, symbolic, blck); - } - using FloatSeconds = chrono::duration<double, chrono::seconds::period>; - auto t2 { chrono::high_resolution_clock::now() }; - if (verbosity >= 1) - { - mexPrintf("(** %.2f seconds **)\n", FloatSeconds{t2 - t1}.count()); - mexEvalString("drawnow;"); - } - if (!steady_state && stack_solve_algo == 4) - { - double ax = -0.1, bx = 1.1, cx = 0.5, fa, fb, fc, xmin; - - if (!mnbrak(&ax, &bx, &cx, &fa, &fb, &fc)) - return; - if (!golden(ax, bx, cx, 1e-1, solve_tolf, &xmin)) - return; - slowc = xmin; - if (verbosity >= 1) - { - auto t3 { chrono::high_resolution_clock::now() }; - mexPrintf("(** %.2f seconds **)\n", FloatSeconds{t3 - t2}.count()); - mexEvalString("drawnow;"); - } - } - if (tbreak_g == 0) - tbreak_g = periods; -} - -void -dynSparseMatrix::fixe_u(double **u, int u_count_int, int max_lag_plus_max_lead_plus_1) -{ - u_count = u_count_int * periods; - u_count_alloc = 2*u_count; -#ifdef DEBUG - mexPrintf("fixe_u : alloc(%d double)\n", u_count_alloc); -#endif - *u = static_cast<double *>(mxMalloc(u_count_alloc*sizeof(double))); - test_mxMalloc(*u, __LINE__, __FILE__, __func__, u_count_alloc*sizeof(double)); -#ifdef DEBUG - mexPrintf("*u=%d\n", *u); -#endif - fill_n(*u, u_count_alloc, 0); - u_count_init = max_lag_plus_max_lead_plus_1; -} diff --git a/mex/sources/bytecode/SparseMatrix.hh b/mex/sources/bytecode/SparseMatrix.hh deleted file mode 100644 index 8aa4d067ba..0000000000 --- a/mex/sources/bytecode/SparseMatrix.hh +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright © 2007-2023 Dynare Team - * - * This file is part of Dynare. - * - * Dynare is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Dynare is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Dynare. If not, see <https://www.gnu.org/licenses/>. - */ - -#ifndef _SPARSEMATRIX_HH -#define _SPARSEMATRIX_HH - -#include <utility> -#include <vector> -#include <map> -#include <tuple> -#include <stack> -#include <fstream> -#include <string> - -#include "dynumfpack.h" -#include "dynmex.h" - -#include "Mem_Mngr.hh" -#include "Evaluate.hh" - -using namespace std; - -struct t_save_op_s -{ - short int lag, operat; - int first, second; -}; - -struct s_plan -{ - string var, exo; - int var_num, exo_num; - vector<pair<int, double>> per_value; - vector<double> value; -}; - -struct table_conditional_local_type -{ - bool is_cond; - int var_exo, var_endo; - double constrained_value; -}; -using vector_table_conditional_local_type = vector<table_conditional_local_type>; -using table_conditional_global_type = map<int, vector_table_conditional_local_type>; - -constexpr int IFLD = 0, IFDIV = 1, IFLESS = 2, IFSUB = 3, IFLDZ = 4, IFMUL = 5, IFSTP = 6, IFADD = 7; -constexpr double eps = 1e-15, very_big = 1e24; -constexpr int alt_symbolic_count_max = 1; -constexpr double mem_increasing_factor = 1.1; - -class dynSparseMatrix -{ -public: - dynSparseMatrix(Evaluate &evaluator_arg, int y_size_arg, int y_kmin_arg, int y_kmax_arg, bool steady_state_arg, bool block_decomposed_arg, int periods_arg, int minimal_solving_periods_arg, const BasicSymbolTable &symbol_table_arg, int verbosity_arg); - void Simulate_Newton_Two_Boundaries(int blck, int y_size, int y_kmin, int y_kmax, int Size, int periods, bool cvg, int minimal_solving_periods, int stack_solve_algo, const vector_table_conditional_local_type &vector_table_conditional_local); - void Simulate_Newton_One_Boundary(bool forward); - void fixe_u(double **u, int u_count_int, int max_lag_plus_max_lead_plus_1); - void Read_SparseMatrix(const string &file_name, int Size, int periods, int y_kmin, int y_kmax, bool two_boundaries, int stack_solve_algo, int solve_algo); - void Close_SaveCode(); - void Singular_display(int block, int Size); - void End_Solver(); - double g0, gp0, glambda2; - int try_at_iteration; - static int find_exo_num(const vector<s_plan> &sconstrained_extended_path, int value); - static int find_int_date(const vector<pair<int, double>> &per_value, int value); - -private: - void Init_GE(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM); - void Init_Matlab_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, mxArray *A_m, mxArray *b_m, const mxArray *x0_m) const; - void Init_UMFPACK_Sparse(int periods, int y_kmin, int y_kmax, int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, const mxArray *x0_m, const vector_table_conditional_local_type &vector_table_conditional_local, int block_num) const; - void Init_Matlab_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, const mxArray *A_m, const mxArray *b_m, bool &zero_solution, const mxArray *x0_m) const; - void Init_UMFPACK_Sparse_Simple(int Size, const map<tuple<int, int, int>, int> &IM, SuiteSparse_long **Ap, SuiteSparse_long **Ai, double **Ax, double **b, bool &zero_solution, const mxArray *x0_m) const; - void Simple_Init(int Size, const map<tuple<int, int, int>, int> &IM, bool &zero_solution); - void End_GE(); - bool mnbrak(double *ax, double *bx, double *cx, double *fa, double *fb, double *fc); - bool golden(double ax, double bx, double cx, double tol, double solve_tolf, double *xmin); - void Solve_ByteCode_Symbolic_Sparse_GaussianElimination(int Size, bool symbolic, int Block_number); - bool Solve_ByteCode_Sparse_GaussianElimination(int Size, int blck, int it_); - void Solve_Matlab_Relaxation(mxArray *A_m, mxArray *b_m, unsigned int Size, double slowc_l); - static void Print_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, int n); - static void Printfull_UMFPack(const SuiteSparse_long *Ap, const SuiteSparse_long *Ai, const double *Ax, const double *b, int n); - static void PrintM(int n, const double *Ax, const mwIndex *Ap, const mwIndex *Ai); - void Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_, const vector_table_conditional_local_type &vector_table_conditional_local); - void Solve_LU_UMFPack(SuiteSparse_long *Ap, SuiteSparse_long *Ai, double *Ax, double *b, int n, int Size, double slowc_l, bool is_two_boundaries, int it_); - - void End_Matlab_LU_UMFPack(); - void Solve_Matlab_GMRES(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m); - void Solve_Matlab_BiCGStab(mxArray *A_m, mxArray *b_m, int Size, double slowc, int block, bool is_two_boundaries, int it_, mxArray *x0_m, int precond); - void Check_and_Correct_Previous_Iteration(int y_size, int size); - bool Simulate_One_Boundary(int blck, int y_size, int size); - bool solve_linear(int block_num, int y_size, int size, int iter); - void solve_non_linear(int block_num, int y_size, int size); - string preconditioner_print_out(string s, int preconditioner, bool ss); - bool compare(int *save_op, int *save_opa, int *save_opaa, int beg_t, int periods, long nop4, int Size); - void Insert(int r, int c, int u_index, int lag_index); - void Delete(int r, int c); - int At_Row(int r, NonZeroElem **first) const; - int At_Pos(int r, int c, NonZeroElem **first) const; - int At_Col(int c, NonZeroElem **first) const; - int At_Col(int c, int lag, NonZeroElem **first) const; - int NRow(int r) const; - int NCol(int c) const; - int Union_Row(int row1, int row2) const; - int Get_u(); - void Delete_u(int pos); - void Clear_u(); - void *Symbolic {nullptr}, *Numeric {nullptr}; - int complete(int beg_t, int Size, int periods, int *b); - void bksub(int tbreak, int last_period, int Size, double slowc_l); - void simple_bksub(int it_, int Size, double slowc_l); - // Computes Aᵀ where A is are sparse. The result is sparse. - static mxArray *Sparse_transpose(const mxArray *A_m); - // Computes Aᵀ·B where A and B are sparse. The result is sparse. - static mxArray *Sparse_mult_SAT_SB(const mxArray *A_m, const mxArray *B_m); - // Computes Aᵀ·B where A is sparse and B is dense. The result is sparse. - static mxArray *Sparse_mult_SAT_B(const mxArray *A_m, const mxArray *B_m); - // Computes Aᵀ·B where A is sparse and B is dense. The result is dense. - static mxArray *mult_SAT_B(const mxArray *A_m, const mxArray *B_m); - // Computes A−B where A and B are sparse. The result is sparse. - static mxArray *Sparse_subtract_SA_SB(const mxArray *A_m, const mxArray *B_m); - // Computes A−B where A and B are dense. The result is dense. - static mxArray *subtract_A_B(const mxArray *A_m, const mxArray *B_m); -protected: - const BasicSymbolTable &symbol_table; - const bool steady_state; // Whether this is a static or dynamic model - - // Whether to use the block-decomposed version of the bytecode file - bool block_decomposed; - - Evaluate &evaluator; - - fstream SaveCode; - - Mem_Mngr mem_mngr; - vector<int> u_liste; - int *NbNZRow, *NbNZCol; - NonZeroElem **FNZE_R, **FNZE_C; - int u_count_init; - - int *pivot, *pivotk, *pivot_save; - double *pivotv, *pivotva; - int *b; - bool *line_done; - bool symbolic, alt_symbolic; - int alt_symbolic_count; - double markowitz_c_s; - double res1a; - long int nop1; - map<tuple<int, int, int>, int> IM_i; - int u_count_alloc, u_count_alloc_save; - double slowc, slowc_save, prev_slowc_save, markowitz_c; - int *index_equa; // Actually unused - int u_count, tbreak_g; - int iter; - int start_compare; - int restart; - double lu_inc_tol; - - SuiteSparse_long *Ap_save, *Ai_save; - double *Ax_save, *b_save; - - int stack_solve_algo, solve_algo; - int minimal_solving_periods; - int Per_u_, Per_y_; - int maxit_; - double *direction; - double solve_tolf; - // 1-norm error, square of 2-norm error, ∞-norm error - double res1, res2, max_res; - int max_res_idx; - int *index_vara; - - double *y, *ya; - int y_size; - double *T; - int nb_row_x; - int y_kmin, y_kmax, periods; - double *x, *params; - double *u; - double *steady_y; - double *g1, *r, *res; - vector<mxArray *> jacobian_block, jacobian_exo_block, jacobian_det_exo_block; - mxArray *GlobalTemporaryTerms; - int it_; - map<int, double> TEF; - map<pair<int, int>, double> TEFD; - map<tuple<int, int, int>, double> TEFDD; - - // Information about the current block - int block_num; // Index of the current block - int size; // Size of the current block - BlockSimulationType type; - bool is_linear; - int u_count_int; - vector<Block_contain_type> Block_Contain; - - int verbosity; // Corresponds to options_.verbosity - - void compute_block_time(int Per_u_, bool evaluate, bool no_derivatives); - bool compute_complete(bool no_derivatives, double &res1, double &res2, double &max_res, int &max_res_idx); - - bool compute_complete(double lambda, double *crit); -}; - -#endif // _SPARSEMATRIX_HH -- GitLab