diff --git a/src/CodeInterpreter.hh b/src/CodeInterpreter.hh index 2f933be52ba70d886700f14e4ef4b37744e5900f..207ae356f165788c233e0fb03f4d928c396555c4 100644 --- a/src/CodeInterpreter.hh +++ b/src/CodeInterpreter.hh @@ -152,7 +152,10 @@ enum class SymbolType statementDeclaredVariable = 14, //!< Local variable assigned within a Statement (see subsample statement for example) logTrend = 15, //!< Log-trend variable unusedEndogenous = 16, - endogenousVAR = 17 //!< Variables declared in a var_model statement + endogenousVAR = 17, //!< Variables declared in a var_model statement + endogenousEpilogue = 18, //!< Endogenous Variables used in the epilogue block + exogenousEpilogue = 19, //!< Variables used in the epilogue block + parameterEpilogue = 20 //!< Variables used in the epilogue block }; enum ExpressionType diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh index 7fc05721e52a1417690bf366f4044bc6f7b5cb0a..be6c5d1a6e3674e9e12defa3be8aa79742a18264 100644 --- a/src/ComputingTasks.hh +++ b/src/ComputingTasks.hh @@ -27,7 +27,7 @@ #include "Statement.hh" #include "StaticModel.hh" #include "DynamicModel.hh" -#include "SteadyStateModel.hh" +#include "ModelEquationBlock.hh" class SteadyStatement : public Statement { diff --git a/src/DynareBison.yy b/src/DynareBison.yy index 6093bc7a768816e351ab31b65df8497e21ae5cb3..90685fa94b9f39c865a0931b0ff8150c3ac65b07 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -148,7 +148,7 @@ class ParsingDriver; %token SBVAR TREND_VAR DEFLATOR GROWTH_FACTOR MS_IRF MS_VARIANCE_DECOMPOSITION GROWTH %token MS_ESTIMATION MS_SIMULATION MS_COMPUTE_MDD MS_COMPUTE_PROBABILITIES MS_FORECAST %token SVAR_IDENTIFICATION EQUATION EXCLUSION LAG UPPER_CHOLESKY LOWER_CHOLESKY MONTHLY QUARTERLY -%token MARKOV_SWITCHING CHAIN DURATION NUMBER_OF_REGIMES NUMBER_OF_LAGS +%token MARKOV_SWITCHING CHAIN DURATION NUMBER_OF_REGIMES NUMBER_OF_LAGS EPILOGUE %token SVAR SVAR_GLOBAL_IDENTIFICATION_CHECK COEFF COEFFICIENTS VARIANCES CONSTANTS EQUATIONS %token EXTERNAL_FUNCTION EXT_FUNC_NAME EXT_FUNC_NARGS FIRST_DERIV_PROVIDED SECOND_DERIV_PROVIDED %token SELECTED_VARIABLES_ONLY COVA_COMPUTE SIMULATION_FILE_TAG FILE_TAG @@ -221,6 +221,7 @@ statement : parameters | estimated_params_init | set_time | data + | epilogue | var_model | pac_model | trend_component_model @@ -348,6 +349,7 @@ log_trend_var_list : log_trend_var_list symbol ; var : VAR var_list ';' + | VAR '(' EPILOGUE ')' epilogue_var_list ';' | VAR '(' DEFLATOR EQUAL { driver.begin_trend(); } hand_side ')' nonstationary_var_list ';' { driver.end_nonstationary_var(false, $6); } | VAR '(' LOG_DEFLATOR EQUAL { driver.begin_trend(); } hand_side ')' nonstationary_var_list ';' @@ -537,13 +539,17 @@ nonstationary_var_list : nonstationary_var_list symbol { driver.declare_nonstationary_var($1, $2, $3); } ; -varexo : VAREXO varexo_list ';'; +varexo : VAREXO varexo_list ';' + | VAREXO '(' EPILOGUE ')' epilogue_varexo_list ';' + ; varexo_det : VAREXO_DET varexo_det_list ';'; predetermined_variables : PREDETERMINED_VARIABLES predetermined_variables_list ';'; parameters : PARAMETERS parameter_list ';'; + | PARAMETERS '(' EPILOGUE ')' epilogue_parameter_list ';'; + ; model_local_variable : MODEL_LOCAL_VARIABLE model_local_variable_list ';'; @@ -598,6 +604,32 @@ var_list : var_list symbol { driver.declare_endogenous($1, $2, $3); } ; +epilogue_var_list : epilogue_var_list symbol + { driver.declare_epilogue_endogenous($2); } + | epilogue_var_list COMMA symbol + { driver.declare_epilogue_endogenous($3); } + | symbol + { driver.declare_epilogue_endogenous($1); } + | epilogue_var_list symbol named_var + { driver.declare_epilogue_endogenous($2, "", $3); } + | epilogue_var_list COMMA symbol named_var + { driver.declare_epilogue_endogenous($3, "", $4); } + | symbol named_var + { driver.declare_epilogue_endogenous($1, "", $2); } + | epilogue_var_list symbol TEX_NAME + { driver.declare_epilogue_endogenous($2, $3); } + | epilogue_var_list COMMA symbol TEX_NAME + { driver.declare_epilogue_endogenous($3, $4); } + | symbol TEX_NAME + { driver.declare_epilogue_endogenous($1, $2); } + | epilogue_var_list symbol TEX_NAME named_var + { driver.declare_epilogue_endogenous($2, $3, $4); } + | epilogue_var_list COMMA symbol TEX_NAME named_var + { driver.declare_epilogue_endogenous($3, $4, $5); } + | symbol TEX_NAME named_var + { driver.declare_epilogue_endogenous($1, $2, $3); } + ; + varexo_list : varexo_list symbol { driver.declare_exogenous($2); } | varexo_list COMMA symbol @@ -650,6 +682,32 @@ varexo_det_list : varexo_det_list symbol { driver.declare_exogenous_det($1, $2, $3); } ; +epilogue_varexo_list : epilogue_varexo_list symbol + { driver.declare_epilogue_exogenous($2); } + | epilogue_varexo_list COMMA symbol + { driver.declare_epilogue_exogenous($3); } + | symbol + { driver.declare_epilogue_exogenous($1); } + | epilogue_varexo_list symbol named_var + { driver.declare_epilogue_exogenous($2, "", $3); } + | epilogue_varexo_list COMMA symbol named_var + { driver.declare_epilogue_exogenous($3, "", $4); } + | symbol named_var + { driver.declare_epilogue_exogenous($1, "", $2); } + | epilogue_varexo_list symbol TEX_NAME + { driver.declare_epilogue_exogenous($2, $3); } + | epilogue_varexo_list COMMA symbol TEX_NAME + { driver.declare_epilogue_exogenous($3, $4); } + | symbol TEX_NAME + { driver.declare_epilogue_exogenous($1, $2); } + | epilogue_varexo_list symbol TEX_NAME named_var + { driver.declare_epilogue_exogenous($2, $3, $4); } + | epilogue_varexo_list COMMA symbol TEX_NAME named_var + { driver.declare_epilogue_exogenous($3, $4, $5); } + | symbol TEX_NAME named_var + { driver.declare_epilogue_exogenous($1, $2, $3); } + ; + parameter_list : parameter_list symbol { driver.declare_parameter($2); } | parameter_list COMMA symbol @@ -676,6 +734,32 @@ parameter_list : parameter_list symbol { driver.declare_parameter($1, $2, $3); } ; +epilogue_parameter_list : epilogue_parameter_list symbol + { driver.declare_parameter($2); } + | epilogue_parameter_list COMMA symbol + { driver.declare_parameter($3); } + | symbol + { driver.declare_parameter($1); } + | epilogue_parameter_list symbol named_var + { driver.declare_parameter($2, "", $3); } + | epilogue_parameter_list COMMA symbol named_var + { driver.declare_parameter($3, "", $4); } + | symbol named_var + { driver.declare_parameter($1, "", $2); } + | epilogue_parameter_list symbol TEX_NAME + { driver.declare_parameter($2, $3); } + | epilogue_parameter_list COMMA symbol TEX_NAME + { driver.declare_parameter($3, $4); } + | symbol TEX_NAME + { driver.declare_parameter($1, $2); } + | epilogue_parameter_list symbol TEX_NAME named_var + { driver.declare_parameter($2, $3, $4); } + | epilogue_parameter_list COMMA symbol TEX_NAME named_var + { driver.declare_parameter($3, $4, $5); } + | symbol TEX_NAME named_var + { driver.declare_parameter($1, $2, $3); } + ; + predetermined_variables_list : predetermined_variables_list symbol { driver.add_predetermined_variable($2); } | predetermined_variables_list COMMA symbol @@ -864,6 +948,18 @@ histval_file : HISTVAL_FILE '(' FILENAME EQUAL filename ')' ';' { driver.histval_file($5); } ; +epilogue : EPILOGUE ';' { driver.begin_epilogue(); } + epilogue_equation_list END ';' { driver.end_epilogue(); } + ; + +epilogue_equation_list : epilogue_equation_list epilogue_equation + | epilogue_equation + ; + +epilogue_equation : symbol EQUAL expression ';' + { driver.add_epilogue_equal($1, $3); } + ; + model_options : BLOCK { driver.block(); } | o_cutoff | o_mfs diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll index 817a83fa415e0ab468728b61416fa34d3051c9ec..9869e1bb83ff2c787c91a37703ab4e3d5b50dcd9 100644 --- a/src/DynareFlex.ll +++ b/src/DynareFlex.ll @@ -204,6 +204,7 @@ DATE -?[0-9]+([YyAa]|[Mm]([1-9]|1[0-2])|[Qq][1-4]|[Ww]([1-9]{1}|[1-4][0-9]|5[0-2 <INITIAL>shock_groups {BEGIN DYNARE_BLOCK; return token::SHOCK_GROUPS;} <INITIAL>mshocks {BEGIN DYNARE_BLOCK; return token::MSHOCKS;} <INITIAL>estimated_params {BEGIN DYNARE_BLOCK; return token::ESTIMATED_PARAMS;} +<INITIAL>epilogue {BEGIN DYNARE_BLOCK; return token::EPILOGUE;} /* priors is an alias for estimated_params */ <INITIAL>priors {BEGIN DYNARE_BLOCK;return token::ESTIMATED_PARAMS;} <INITIAL>estimated_params_init {BEGIN DYNARE_BLOCK; return token::ESTIMATED_PARAMS_INIT;} @@ -629,6 +630,7 @@ DATE -?[0-9]+([YyAa]|[Mm]([1-9]|1[0-2])|[Qq][1-4]|[Ww]([1-9]{1}|[1-4][0-9]|5[0-2 <DYNARE_STATEMENT>save_draws {return token::SAVE_DRAWS; } <DYNARE_STATEMENT>deflator {return token::DEFLATOR;} <DYNARE_STATEMENT>log_deflator {return token::LOG_DEFLATOR;} +<DYNARE_STATEMENT>epilogue {return token::EPILOGUE;} <DYNARE_STATEMENT>growth_factor {return token::GROWTH_FACTOR;} <DYNARE_STATEMENT>log_growth_factor {return token::LOG_GROWTH_FACTOR;} <DYNARE_STATEMENT>growth {return token::GROWTH;} diff --git a/src/ExprNode.cc b/src/ExprNode.cc index 10c4737376c1dea56e197ff5c268c6c02c583697..80ca2741b22c2283d41870b5be8b97de927f1247 100644 --- a/src/ExprNode.cc +++ b/src/ExprNode.cc @@ -748,6 +748,9 @@ VariableNode::prepareForDerivation() break; case SymbolType::externalFunction: case SymbolType::endogenousVAR: + case SymbolType::endogenousEpilogue: + case SymbolType::exogenousEpilogue: + case SymbolType::parameterEpilogue: cerr << "VariableNode::prepareForDerivation: impossible case" << endl; exit(EXIT_FAILURE); } @@ -781,7 +784,10 @@ VariableNode::computeDerivative(int deriv_id) exit(EXIT_FAILURE); case SymbolType::externalFunction: case SymbolType::endogenousVAR: - cerr << "Impossible case!" << endl; + case SymbolType::endogenousEpilogue: + case SymbolType::exogenousEpilogue: + case SymbolType::parameterEpilogue: + cerr << "VariableNode::computeDerivative: Impossible case!" << endl; exit(EXIT_FAILURE); } // Suppress GCC warning @@ -857,6 +863,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, switch (type) { case SymbolType::parameter: + case SymbolType::parameterEpilogue: if (output_type == oMatlabOutsideModel) output << "M_.params" << "(" << tsid + 1 << ")"; else @@ -927,6 +934,13 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, if (lag != 0) output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type); break; + case oEpilogueFile: + output << datatree.symbol_table.getName(symb_id) + << LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__"; + if (lag != 0) + output << lag; + output << RIGHT_ARRAY_SUBSCRIPT(output_type); + break; default: cerr << "VariableNode::writeOutput: should not reach this point" << endl; exit(EXIT_FAILURE); @@ -980,6 +994,13 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, if (lag != 0) output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type); break; + case oEpilogueFile: + output << datatree.symbol_table.getName(symb_id) + << LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__"; + if (lag != 0) + output << lag; + output << RIGHT_ARRAY_SUBSCRIPT(output_type); + break; default: cerr << "VariableNode::writeOutput: should not reach this point" << endl; exit(EXIT_FAILURE); @@ -1033,19 +1054,33 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, if (lag != 0) output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type); break; + case oEpilogueFile: + output << datatree.symbol_table.getName(symb_id) + << LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__"; + if (lag != 0) + output << lag; + output << RIGHT_ARRAY_SUBSCRIPT(output_type); + break; default: cerr << "VariableNode::writeOutput: should not reach this point" << endl; exit(EXIT_FAILURE); } break; - + case SymbolType::endogenousEpilogue: + case SymbolType::exogenousEpilogue: + output << datatree.symbol_table.getName(symb_id) + << LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__"; + if (lag != 0) + output << lag; + output << RIGHT_ARRAY_SUBSCRIPT(output_type); + break; case SymbolType::externalFunction: case SymbolType::trend: case SymbolType::logTrend: case SymbolType::statementDeclaredVariable: case SymbolType::unusedEndogenous: case SymbolType::endogenousVAR: - cerr << "Impossible case" << endl; + cerr << "VariableNode::writeOutput: Impossible case" << endl; exit(EXIT_FAILURE); } } @@ -1264,7 +1299,10 @@ VariableNode::getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recur exit(EXIT_FAILURE); case SymbolType::externalFunction: case SymbolType::endogenousVAR: - cerr << "Impossible case!" << endl; + case SymbolType::endogenousEpilogue: + case SymbolType::exogenousEpilogue: + case SymbolType::parameterEpilogue: + cerr << "VariableNode::getChainRuleDerivative: Impossible case" << endl; exit(EXIT_FAILURE); } // Suppress GCC warning @@ -1302,6 +1340,9 @@ VariableNode::computeXrefs(EquationInfo &ei) const case SymbolType::unusedEndogenous: case SymbolType::externalFunction: case SymbolType::endogenousVAR: + case SymbolType::endogenousEpilogue: + case SymbolType::exogenousEpilogue: + case SymbolType::parameterEpilogue: break; } } @@ -6705,6 +6746,7 @@ AbstractExternalFunctionNode::getIndxInTefTerms(int the_symb_id, const deriv_nod auto it = tef_terms.find({ the_symb_id, arguments }); if (it != tef_terms.end()) return it->second; + cout << endl << endl << tef_terms.size() << "." <<the_symb_id << endl << endl; throw UnknownFunctionNameAndArgs(); } diff --git a/src/ExprNode.hh b/src/ExprNode.hh index d77f9a6fc380e17223c97c4c3eb7e1289d3aea75..a519d88afbd8451a0ab5d38a405d6736c36e3791 100644 --- a/src/ExprNode.hh +++ b/src/ExprNode.hh @@ -87,7 +87,8 @@ enum ExprNodeOutputType oJuliaDynamicSteadyStateOperator, //!< Julia code, dynamic model, inside a steady state operator oSteadyStateFile, //!< Matlab code, in the generated steady state file oJuliaSteadyStateFile, //!< Julia code, in the generated steady state file - oMatlabDseries //!< Matlab code for dseries + oMatlabDseries, //!< Matlab code for dseries + oEpilogueFile //!< Matlab code, in the generated epilogue file }; #define IS_MATLAB(output_type) ((output_type) == oMatlabStaticModel \ @@ -98,7 +99,8 @@ enum ExprNodeOutputType || (output_type) == oMatlabDynamicSteadyStateOperator \ || (output_type) == oMatlabDynamicSparseSteadyStateOperator \ || (output_type) == oSteadyStateFile \ - || (output_type) == oMatlabDseries) + || (output_type) == oMatlabDseries \ + || (output_type) == oEpilogueFile) #define IS_JULIA(output_type) ((output_type) == oJuliaStaticModel \ || (output_type) == oJuliaDynamicModel \ diff --git a/src/Makefile.am b/src/Makefile.am index 4fea410466b4da34fcf953568b5006d44183f6cd..1756b9212f179f58fe26c7670887fcf148c11486 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,8 +48,8 @@ dynare_m_SOURCES = \ CodeInterpreter.hh \ ExternalFunctionsTable.cc \ ExternalFunctionsTable.hh \ - SteadyStateModel.hh \ - SteadyStateModel.cc \ + ModelEquationBlock.hh \ + ModelEquationBlock.cc \ WarningConsolidation.hh \ WarningConsolidation.cc \ ExtendedPreprocessorTypes.hh \ diff --git a/src/ModFile.cc b/src/ModFile.cc index e7183d5d1fa7109471d04e549135d1d0cd66ba26..7c97f03262ab11e683d1f63ad28b333301920c7a 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -44,6 +44,8 @@ ModFile::ModFile(WarningConsolidation &warnings_arg) trend_component_model_table, var_model_table), orig_ramsey_dynamic_model(symbol_table, num_constants, external_functions_table, trend_component_model_table, var_model_table), + epilogue(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), static_model(symbol_table, num_constants, external_functions_table, trend_component_model_table, var_model_table), steady_state_model(symbol_table, num_constants, external_functions_table, @@ -127,6 +129,9 @@ ModFile::checkPass(bool nostrict, bool stochastic) // Check the steady state block steady_state_model.checkPass(mod_file_struct, warnings); + // Check epilogue block + epilogue.checkPass(warnings); + if (mod_file_struct.write_latex_steady_state_model_present && !mod_file_struct.steady_state_model_present) { @@ -767,6 +772,8 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri for (auto & statement : statements) statement->computingPass(); + + epilogue.computingPass(true, true, false, 0, global_eval_context, true, false, false, false, true); } void @@ -1074,6 +1081,9 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo // Create steady state file steady_state_model.writeSteadyStateFile(basename, mod_file_struct.ramsey_model_present, false); + + // Create epilogue file + epilogue.writeEpilogueFile(basename); } if (!nopreprocessoroutput) diff --git a/src/ModFile.hh b/src/ModFile.hh index 6b6d9c82083ffb352bf769b35538fbae992a7647..4e696e6164ad9e4947f6b1ce4a19f813d136f2dc 100644 --- a/src/ModFile.hh +++ b/src/ModFile.hh @@ -32,7 +32,7 @@ using namespace std; #include "NumericalInitialization.hh" #include "StaticModel.hh" #include "DynamicModel.hh" -#include "SteadyStateModel.hh" +#include "ModelEquationBlock.hh" #include "Statement.hh" #include "ExternalFunctionsTable.hh" #include "ConfigFile.hh" @@ -68,6 +68,8 @@ public: DynamicModel ramsey_FOC_equations_dynamic_model; //! A copy of the original model, used to test model linearity under ramsey problem DynamicModel orig_ramsey_dynamic_model; + //! Epilogue model, as declared in the "epilogue" block + Epilogue epilogue; //! Static model, as derived from the "model" block when leads and lags have been removed StaticModel static_model; //! Static model, as declared in the "steady_state_model" block if present diff --git a/src/SteadyStateModel.cc b/src/ModelEquationBlock.cc similarity index 70% rename from src/SteadyStateModel.cc rename to src/ModelEquationBlock.cc index 4b97d953f73a8f645016193447524cb324fe0910..5edeab5e16ff925c2f0b3e8050fef26a3f701c2b 100644 --- a/src/SteadyStateModel.cc +++ b/src/ModelEquationBlock.cc @@ -20,7 +20,7 @@ #include <cassert> #include <algorithm> -#include "SteadyStateModel.hh" +#include "ModelEquationBlock.hh" SteadyStateModel::SteadyStateModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, @@ -269,3 +269,109 @@ SteadyStateModel::writeJsonSteadyStateFile(ostream &output, bool transformComput output << "]}"; } + +Epilogue::Epilogue(SymbolTable &symbol_table_arg, + NumericalConstants &num_constants_arg, + ExternalFunctionsTable &external_functions_table_arg, + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg) : + DynamicModel(symbol_table_arg, num_constants_arg, external_functions_table_arg, + trend_component_model_table_arg, var_model_table_arg) +{ +} + +void +Epilogue::addDefinition(int symb_id, expr_t expr) +{ + AddVariable(symb_id); // Create the variable node to be used in write method + def_table.emplace_back(symb_id, expr); + endogs.emplace(symb_id); + expr->collectVariables(SymbolType::endogenous, exogs); + expr->collectVariables(SymbolType::exogenous, exogs); + expr->collectVariables(SymbolType::endogenousEpilogue, exogs); + expr->collectVariables(SymbolType::exogenousEpilogue, exogs); + for (auto it : endogs) + exogs.erase(it); +} + +void +Epilogue::checkPass(WarningConsolidation &warnings) const +{ + if (def_table.size() == 0) + return; + + vector<int> so_far_defined; + for (const auto & it : def_table) + { + if (find(so_far_defined.begin(), so_far_defined.end(), it.first) != so_far_defined.end()) + { + cerr << "WARNING: in the 'epilogue' block, variable '" << symbol_table.getName(it.first) + << "' is declared twice" << endl; + exit(EXIT_FAILURE); + } + so_far_defined.push_back(it.first); + } +} + +void +Epilogue::writeEpilogueFile(const string &basename) const +{ + if (def_table.size() == 0) + return; + + string filename = packageDir(basename) + "/epilogue.m"; + ofstream output; + output.open(filename, ios::out | ios::binary); + if (!output.is_open()) + { + cerr << "ERROR: Can't open file " << filename << " for writing" << endl; + exit(EXIT_FAILURE); + } + + ExprNodeOutputType output_type = oEpilogueFile; + output << "function ds = epilogue(params, ds)" << endl + << "% function ds = epilogue(params, ds)" << endl + << "% Epilogue file generated by Dynare preprocessor" << endl << endl + << "epilogue_ds_first_date__ = ds.firstdate;" << endl + << "epilogue_loop_begin_idx__ = lastdate(ds) - ds.lastobservedperiod;" << endl + << "epilogue_loop_end_idx__ = lastdate(ds) - firstdate(ds) + 1;" << endl << endl; + + output << "% endogenous" << endl; + for (auto symb_id : endogs) + output << symbol_table.getName(symb_id) << " = ds." << symbol_table.getName(symb_id) << ".data;" << endl; + output << endl + << "% exogenous" << endl; + for (auto symb_id : exogs) + output << symbol_table.getName(symb_id) << " = ds." << symbol_table.getName(symb_id) << ".data;" << endl; + output << endl + << "for epilogue_it__ = epilogue_loop_begin_idx__::epilogue_loop_end_idx__" << endl; + + deriv_node_temp_terms_t tef_terms; + temporary_terms_t temporary_terms; + temporary_terms_idxs_t temporary_terms_idxs; + for (const auto & it : def_table) + if (it.second->containsExternalFunction()) + { + output << " "; + it.second->writeExternalFunctionOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms); + } + output << endl; + for (const auto & it : def_table) + { + auto node = variable_node_map.find({ it.first, 0 }); + assert(node != variable_node_map.end()); + + output << " "; + dynamic_cast<ExprNode *>(node->second)->writeOutput(output, output_type); + output << " = "; + it.second->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms); + output << ";" << endl; + } + output << "end" << endl << endl; + for (auto symb_id : endogs) + output << "ds." << symbol_table.getName(symb_id) << " = dseries(" << symbol_table.getName(symb_id) + << ", epilogue_ds_first_date__);" << endl; + output << endl + << "end" << endl; + output.close(); +} diff --git a/src/SteadyStateModel.hh b/src/ModelEquationBlock.hh similarity index 75% rename from src/SteadyStateModel.hh rename to src/ModelEquationBlock.hh index bf436766ef609ff26efab36151b0af4a936d119a..5ad8ed0dad3bd39310184ca294f02c56fa4a1794 100644 --- a/src/SteadyStateModel.hh +++ b/src/ModelEquationBlock.hh @@ -23,6 +23,7 @@ #include "DataTree.hh" #include "Statement.hh" #include "StaticModel.hh" +#include "DynamicModel.hh" #include "WarningConsolidation.hh" class SteadyStateModel : public DataTree @@ -61,4 +62,31 @@ public: void writeJsonSteadyStateFile(ostream &output, bool transformComputingPass) const; }; +class Epilogue : public DynamicModel +{ +private: + //! Associates a set of symbol IDs (the variable(s) assigned in a given statement) to an expression (their assigned value) + vector<pair<int, expr_t>> def_table; + + //! List of variables found in block + set<int> endogs; + set<int> exogs; +public: + Epilogue(SymbolTable &symbol_table_arg, + NumericalConstants &num_constants_arg, + ExternalFunctionsTable &external_functions_table_arg, + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg); + + //! Add an expression of the form "var = expr;" + void addDefinition(int symb_id, expr_t expr); + + //! Checks that no variable is declared twice + void checkPass(WarningConsolidation &warnings) const; + + //! Write the steady state file + void writeEpilogueFile(const string &basename) const; +}; + + #endif diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index fe4e8184f36b3ca9b14ca9cd6e7ab1aa5853bab8..bcb9143059490c41c8cee5fa6e157f8e9bef2dba 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -201,6 +201,14 @@ ParsingDriver::declare_endogenous(const string &name, const string &tex_name, co declare_symbol(name, SymbolType::endogenous, tex_name, partition_value); } +void +ParsingDriver::declare_epilogue_endogenous(const string &name, + const string &tex_name, + const vector<pair<string, string>> &partition_value) +{ + declare_symbol(name, SymbolType::endogenousEpilogue, tex_name, partition_value); +} + void ParsingDriver::declare_var_endogenous(const string &name) { @@ -230,12 +238,28 @@ ParsingDriver::declare_exogenous_det(const string &name, const string &tex_name, declare_symbol(name, SymbolType::exogenousDet, tex_name, partition_value); } +void +ParsingDriver::declare_epilogue_exogenous(const string &name, + const string &tex_name, + const vector<pair<string, string>> &partition_value) +{ + declare_symbol(name, SymbolType::exogenousEpilogue, tex_name, partition_value); +} + void ParsingDriver::declare_parameter(const string &name, const string &tex_name, const vector<pair<string, string>> &partition_value) { declare_symbol(name, SymbolType::parameter, tex_name, partition_value); } +void +ParsingDriver::declare_epilogue_parameter(const string &name, + const string &tex_name, + const vector<pair<string, string>> &partition_value) +{ + declare_symbol(name, SymbolType::parameterEpilogue, tex_name, partition_value); +} + void ParsingDriver::declare_statement_local_variable(const string &name) { @@ -414,6 +438,9 @@ ParsingDriver::add_model_variable(int symb_id, int lag) expr_t ParsingDriver::add_expression_variable(const string &name) { + if (parsing_epilogue && !mod_file->symbol_table.exists(name)) + error("Variable " + name + " used in the epilogue block but was not declared."); + // If symbol doesn't exist, then declare it as a mod file local variable if (!mod_file->symbol_table.exists(name)) mod_file->symbol_table.addSymbol(name, SymbolType::modFileLocalVariable); @@ -817,6 +844,35 @@ ParsingDriver::end_homotopy() homotopy_values.clear(); } +void +ParsingDriver::begin_epilogue() +{ + parsing_epilogue = true; + set_current_data_tree(&mod_file->epilogue); +} + +void +ParsingDriver::end_epilogue() +{ + parsing_epilogue = false; + reset_data_tree(); +} + +void +ParsingDriver::add_epilogue_equal(const string &varname, expr_t expr) +{ + int id; + try + { + id = mod_file->symbol_table.getID(varname); + } + catch (SymbolTable::UnknownSymbolNameException &e) + { + error("Variable " + varname + " used in the epilogue block but was not declared."); + } + mod_file->epilogue.addDefinition(id, expr); +} + void ParsingDriver::begin_model() { @@ -2887,7 +2943,7 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b expr_t nid; if (mod_file->symbol_table.exists(function_name)) if (mod_file->symbol_table.getType(function_name) != SymbolType::externalFunction) - if (!in_model_block) + if (!in_model_block && !parsing_epilogue) { if (stack_external_function_args.top().size() > 0) error(string("Symbol ") + function_name + string(" cannot take arguments.")); @@ -2915,7 +2971,7 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b if (!mod_file->external_functions_table.exists(symb_id)) error("Using a derivative of an external function (" + function_name + ") in the model block is currently not allowed."); - if (in_model_block) + if (in_model_block || parsing_epilogue) if (mod_file->external_functions_table.getNargs(symb_id) == eExtFunNotSet) error("Before using " + function_name +"() in the model block, you must first declare it via the external_function() statement"); @@ -2925,6 +2981,9 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b } else { //First time encountering this external function i.e., not previously declared or encountered + if (parsing_epilogue) + error("Variable " + function_name + " used in the epilogue block but was not declared."); + if (in_model_block) { // Continue processing, noting that it was not declared diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh index b53af1ab9ede3b7a949737add58da5ca2787af2c..77a6020946a8347d9461678d6958474f16aeff5e 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -259,8 +259,12 @@ private: //! Used by VAR restrictions void clear_VAR_storage(); + //! True when parsing the epilogue block + bool parsing_epilogue; + public: - ParsingDriver(WarningConsolidation &warnings_arg, bool nostrict_arg) : warnings(warnings_arg), nostrict(nostrict_arg) { }; + ParsingDriver(WarningConsolidation &warnings_arg, bool nostrict_arg) : + warnings(warnings_arg), nostrict(nostrict_arg), parsing_epilogue(false) { }; //! Starts parsing, and constructs the MOD file representation unique_ptr<ModFile> parse(istream &in, bool debug); @@ -335,12 +339,18 @@ public: void initval_file(const string &filename); //! Declares an endogenous variable void declare_endogenous(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); + //! Declares an endogenous variable in the epilogue block + void declare_epilogue_endogenous(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); //! Declares an exogenous variable void declare_exogenous(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); + //! Declares an exogenous variable in the epilogue block + void declare_epilogue_exogenous(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); //! Declares an exogenous deterministic variable void declare_exogenous_det(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); //! Declares a parameter void declare_parameter(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); + //! Declare a parameter in the epilogue block + void declare_epilogue_parameter(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {}); //! Declares a VAR variable and adds to symbol_list void declare_var_endogenous(const string &name); //! Declares a model local variable @@ -402,6 +412,12 @@ public: void end_histval(bool all_values_required); //! Writes end of an homotopy_setup block void end_homotopy(); + //! Begin epilogue block + void begin_epilogue(); + //! Endepilogue block + void end_epilogue(); + //! Add equation in epilogue block + void add_epilogue_equal(const string &varname, expr_t expr); //! Begin a model block void begin_model(); //! End a model block, printing errors that were encountered in parsing