diff --git a/mex/sources/perfect_foresight_problem/DynamicModelCaller.cc b/mex/sources/perfect_foresight_problem/DynamicModelCaller.cc index 73d7a46425d973221b02ca62ab0951fea2156a37..4e7e819fdbddc744d9f4b1f0f198dc058f8f8c31 100644 --- a/mex/sources/perfect_foresight_problem/DynamicModelCaller.cc +++ b/mex/sources/perfect_foresight_problem/DynamicModelCaller.cc @@ -75,8 +75,8 @@ DynamicModelDllCaller::unload_dll() #endif } -DynamicModelDllCaller::DynamicModelDllCaller(size_t ntt, mwIndex nx, mwIndex ny, size_t ndynvars, const double *x_arg, size_t nb_row_x_arg, const double *params_arg, const double *steady_state_arg, bool compute_jacobian_arg) : - DynamicModelCaller{compute_jacobian_arg}, +DynamicModelDllCaller::DynamicModelDllCaller(size_t ntt, mwIndex nx, mwIndex ny, size_t ndynvars, const double *x_arg, size_t nb_row_x_arg, const double *params_arg, const double *steady_state_arg, bool linear_arg, bool compute_jacobian_arg) : + DynamicModelCaller{linear_arg, compute_jacobian_arg}, nb_row_x{nb_row_x_arg}, x{x_arg}, params{params_arg}, steady_state{steady_state_arg} { tt = std::make_unique<double[]>(ntt); @@ -94,11 +94,14 @@ DynamicModelDllCaller::eval(int it, double *resid) { g1_tt_fct(y_p.get(), x, nb_row_x, params, steady_state, it, tt.get()); g1_fct(y_p.get(), x, nb_row_x, params, steady_state, it, tt.get(), jacobian_p.get()); + + if (linear) + compute_jacobian = false; // If model is linear, no need to recompute Jacobian later } } -DynamicModelMatlabCaller::DynamicModelMatlabCaller(std::string basename_arg, size_t ntt, size_t ndynvars, const mxArray *x_mx_arg, const mxArray *params_mx_arg, const mxArray *steady_state_mx_arg, bool compute_jacobian_arg) : - DynamicModelCaller{compute_jacobian_arg}, +DynamicModelMatlabCaller::DynamicModelMatlabCaller(std::string basename_arg, size_t ntt, size_t ndynvars, const mxArray *x_mx_arg, const mxArray *params_mx_arg, const mxArray *steady_state_mx_arg, bool linear_arg, bool compute_jacobian_arg) : + DynamicModelCaller{linear_arg, compute_jacobian_arg}, basename{std::move(basename_arg)}, T_mx{mxCreateDoubleMatrix(ntt, 1, mxREAL)}, y_mx{mxCreateDoubleMatrix(ndynvars, 1, mxREAL)}, @@ -178,6 +181,9 @@ DynamicModelMatlabCaller::eval(int it, double *resid) jacobian_mx = cmplxToReal(plhs[0]); else jacobian_mx = plhs[0]; + + if (linear) + compute_jacobian = false; // If model is linear, no need to recompute Jacobian later } } diff --git a/mex/sources/perfect_foresight_problem/DynamicModelCaller.hh b/mex/sources/perfect_foresight_problem/DynamicModelCaller.hh index 4d10bb1ad8eddd3d6c58f40fe9c5ce66ebd1f4c2..4dd1d02c84c5a2b6792fae15592b4fbd4cf05ce2 100644 --- a/mex/sources/perfect_foresight_problem/DynamicModelCaller.hh +++ b/mex/sources/perfect_foresight_problem/DynamicModelCaller.hh @@ -33,12 +33,13 @@ class DynamicModelCaller { public: - const bool compute_jacobian; + const bool linear; + bool compute_jacobian; // Not constant, because will be changed from true to false for linear models after first evaluation // Used to store error messages (as exceptions cannot cross the OpenMP boundary) static std::string error_msg; - DynamicModelCaller(bool compute_jacobian_arg) : compute_jacobian{compute_jacobian_arg} {}; + DynamicModelCaller(bool linear_arg, bool compute_jacobian_arg) : linear{linear_arg}, compute_jacobian{compute_jacobian_arg} {}; virtual ~DynamicModelCaller() = default; virtual double &y(size_t i) const = 0; virtual double jacobian(size_t i) const = 0; @@ -62,7 +63,7 @@ private: std::unique_ptr<double[]> tt, y_p, jacobian_p; public: - DynamicModelDllCaller(size_t ntt, mwIndex nx, mwIndex ny, size_t ndynvars, const double *x_arg, size_t nb_row_x_arg, const double *params_arg, const double *steady_state_arg, bool compute_jacobian_arg); + DynamicModelDllCaller(size_t ntt, mwIndex nx, mwIndex ny, size_t ndynvars, const double *x_arg, size_t nb_row_x_arg, const double *params_arg, const double *steady_state_arg, bool linear_arg, bool compute_jacobian_arg); virtual ~DynamicModelDllCaller() = default; double &y(size_t i) const override { return y_p[i]; }; double jacobian(size_t i) const override { return jacobian_p[i]; }; @@ -82,7 +83,7 @@ private: Destroys the original matrix. */ static mxArray *cmplxToReal(mxArray *m); public: - DynamicModelMatlabCaller(std::string basename_arg, size_t ntt, size_t ndynvars, const mxArray *x_mx_arg, const mxArray *params_mx_arg, const mxArray *steady_state_mx_arg, bool compute_jacobian_arg); + DynamicModelMatlabCaller(std::string basename_arg, size_t ntt, size_t ndynvars, const mxArray *x_mx_arg, const mxArray *params_mx_arg, const mxArray *steady_state_mx_arg, bool linear_arg, bool compute_jacobian_arg); ~DynamicModelMatlabCaller() override; double &y(size_t i) const override { return mxGetPr(y_mx)[i]; }; double jacobian(size_t i) const override { return jacobian_mx ? mxGetPr(jacobian_mx)[i] : std::numeric_limits<double>::quiet_NaN(); }; diff --git a/mex/sources/perfect_foresight_problem/perfect_foresight_problem.cc b/mex/sources/perfect_foresight_problem/perfect_foresight_problem.cc index 107dc3caaf1d31719e2d803af98d5b45342edf46..c813b1697aa54f1236e2d9ad0a398c03f5c0fe28 100644 --- a/mex/sources/perfect_foresight_problem/perfect_foresight_problem.cc +++ b/mex/sources/perfect_foresight_problem/perfect_foresight_problem.cc @@ -86,6 +86,11 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("options_.use_dll should be a logical scalar"); bool use_dll = static_cast<bool>(mxGetScalar(use_dll_mx)); + const mxArray *linear_mx = mxGetField(options_mx, 0, "linear"); + if (!(linear_mx && mxIsLogicalScalar(linear_mx))) + mexErrMsgTxt("options_.linear should be a logical scalar"); + bool linear = static_cast<bool>(mxGetScalar(linear_mx)); + const mxArray *threads_mx = mxGetField(options_mx, 0, "threads"); if (!threads_mx) mexErrMsgTxt("Can't find field options_.threads"); @@ -211,9 +216,9 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) // Allocate (thread-private) model evaluator (which allocates space for temporaries) std::unique_ptr<DynamicModelCaller> m; if (use_dll) - m = std::make_unique<DynamicModelDllCaller>(ntt, nx, ny, ndynvars, exo_path, nb_row_x, params, steady_state, compute_jacobian); + m = std::make_unique<DynamicModelDllCaller>(ntt, nx, ny, ndynvars, exo_path, nb_row_x, params, steady_state, linear, compute_jacobian); else - m = std::make_unique<DynamicModelMatlabCaller>(basename, ntt, ndynvars, exo_path_mx, params_mx, steady_state_mx, compute_jacobian); + m = std::make_unique<DynamicModelMatlabCaller>(basename, ntt, ndynvars, exo_path_mx, params_mx, steady_state_mx, linear, compute_jacobian); // Main computing loop #pragma omp for diff --git a/tests/deterministic_simulations/multiple_lead_lags/AR2_forward.mod b/tests/deterministic_simulations/multiple_lead_lags/AR2_forward.mod index 8e6b3f083934754bee9133e6514603e37bc07c04..d79dbbddc8ec73280d23b8562957af76b72e86ab 100644 --- a/tests/deterministic_simulations/multiple_lead_lags/AR2_forward.mod +++ b/tests/deterministic_simulations/multiple_lead_lags/AR2_forward.mod @@ -6,7 +6,7 @@ rho_1=0.2; rho_2=0.1; // Equilibrium conditions -model; +model(linear); y_backward=rho_1*y_backward(-1)+rho_2*y_backward(-2); dummy_var=0.9*dummy_var(+1); end;