Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 4.6
  • 5.x
  • 6.x
  • aux_vars_fix
  • julia
  • llvm-15
  • master
  • python-codegen
  • rework_pac
  • uop
  • julia-6.2.0
  • julia-6.3.0
  • julia-6.4.0
  • julia-7.0.0
14 results

Target

Select target project
  • normann/preprocessor
  • Dynare/preprocessor
  • FerhatMihoubi/preprocessor
  • MichelJuillard/preprocessor
  • sebastien/preprocessor
  • lnsongxf/preprocessor
  • albop/preprocessor
  • DoraK/preprocessor
  • amg/preprocessor
  • wmutschl/preprocessor
  • JohannesPfeifer/preprocessor
11 results
Select Git revision
  • 4.6
  • 5.x
  • aux_vars_fix
  • dynare_lite
  • julia
  • master
  • pylib
  • rework_pac
  • uop
  • wasm
  • created_preprocessor_repo
  • julia-6.2.0
12 results
Show changes
Showing
with 4217 additions and 3120 deletions
......@@ -17,17 +17,16 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <cassert>
#include <cmath>
#include <cstdlib>
#include "NumericalConstants.hh"
int
NumericalConstants::AddNonNegativeConstant(const string& iConst)
{
if (auto iter = numConstantsIndex.find(iConst);
iter != numConstantsIndex.end())
if (auto iter = numConstantsIndex.find(iConst); iter != numConstantsIndex.end())
return iter->second;
auto id = static_cast<int>(mNumericalConstants.size());
......
/*
* Copyright © 2003-2022 Dynare Team
* Copyright © 2003-2023 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,12 +17,12 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _NUMERICALCONSTANTS_HH
#define _NUMERICALCONSTANTS_HH
#ifndef NUMERICAL_CONSTANTS_HH
#define NUMERICAL_CONSTANTS_HH
#include <map>
#include <string>
#include <vector>
#include <map>
using namespace std;
......@@ -36,13 +36,14 @@ private:
vector<double> double_vals;
//! Map matching constants to their id
map<string, int> numConstantsIndex;
public:
//! Adds a non-negative constant (possibly Inf or NaN) and returns its ID
int AddNonNegativeConstant(const string& iConst);
//! Get a constant in string form
string get(int ID) const;
[[nodiscard]] string get(int ID) const;
//! Get a constant in double form
double getDouble(int ID) const;
[[nodiscard]] double getDouble(int ID) const;
};
#endif
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,36 +17,36 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <utility>
#include "NumericalInitialization.hh"
InitParamStatement::InitParamStatement(int symb_id_arg,
const expr_t param_value_arg,
InitParamStatement::InitParamStatement(int symb_id_arg, const expr_t param_value_arg,
const SymbolTable& symbol_table_arg) :
symb_id{symb_id_arg},
param_value{param_value_arg},
symbol_table{symbol_table_arg}
symb_id {symb_id_arg}, param_value {param_value_arg}, symbol_table {symbol_table_arg}
{
}
void
InitParamStatement::checkPass(ModFileStructure &mod_file_struct, [[maybe_unused]] WarningConsolidation &warnings)
InitParamStatement::checkPass(ModFileStructure& mod_file_struct,
[[maybe_unused]] WarningConsolidation& warnings)
{
if (symbol_table.getName(symb_id) == "dsge_prior_weight")
mod_file_struct.dsge_prior_weight_initialized = true;
// Needed for the workaround discussed in dynare#1173
if (symbol_table.getName(symb_id) == "optimal_policy_discount_factor")
param_value->collectVariables(SymbolType::parameter, mod_file_struct.parameters_in_planner_discount);
param_value->collectVariables(SymbolType::parameter,
mod_file_struct.parameters_in_planner_discount);
}
void
InitParamStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basename, bool minimal_workspace) const
InitParamStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
bool minimal_workspace) const
{
int id = symbol_table.getTypeSpecificID(symb_id) + 1;
output << "M_.params(" << id << ") = ";
......@@ -59,7 +59,9 @@ InitParamStatement::writeOutput(ostream &output, [[maybe_unused]] const string &
void
InitParamStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "param_init", "name": ")" << symbol_table.getName(symb_id) << R"(", )" << R"("value": ")";
output << R"({"statementName": "param_init", "name": ")" << symbol_table.getName(symb_id)
<< R"(", )"
<< R"("value": ")";
param_value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -163,14 +165,14 @@ InitOrEndValStatement::writeInitValues(ostream &output) const
void
InitOrEndValStatement::writeJsonInitValues(ostream& output) const
{
for (bool printed_something{false};
auto &[symb_id, value] : init_values)
for (bool printed_something {false}; auto& [symb_id, value] : init_values)
{
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
continue;
if (exchange(printed_something, true))
output << ", ";
output << R"({"name": ")" << symbol_table.getName(symb_id) << R"(", )" << R"("value": ")";
output << R"({"name": ")" << symbol_table.getName(symb_id) << R"(", )"
<< R"("value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -220,9 +222,7 @@ void
InitValStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
output << "%" << endl
<< "% INITVAL instructions" << endl
<< "%" << endl;
output << "%" << endl << "% INITVAL instructions" << endl << "%" << endl;
// Writing initval block to set initial values for variables
output << "options_.initval_file = false;" << endl;
......@@ -248,8 +248,7 @@ InitValStatement::writeOutputPostInit(ostream &output) const
<< "end" << endl;
}
EndValStatement::EndValStatement(init_values_t init_values_arg,
const SymbolTable &symbol_table_arg,
EndValStatement::EndValStatement(init_values_t init_values_arg, const SymbolTable& symbol_table_arg,
bool all_values_required_arg) :
InitOrEndValStatement {move(init_values_arg), symbol_table_arg, all_values_required_arg}
{
......@@ -288,9 +287,7 @@ void
EndValStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
output << "%" << endl
<< "% ENDVAL instructions" << endl
<< "%" << endl;
output << "%" << endl << "% ENDVAL instructions" << endl << "%" << endl;
// Writing endval block to set terminal values for variables
output << "oo_.initial_steady_state = oo_.steady_state;" << endl
<< "oo_.initial_exo_steady_state = oo_.exo_steady_state;" << endl;
......@@ -306,10 +303,10 @@ EndValStatement::writeJsonOutput(ostream &output) const
output << "]}";
}
EndValLearntInStatement::EndValLearntInStatement(int learnt_in_period_arg,
EndValLearntInStatement::EndValLearntInStatement(variant<int, string> learnt_in_period_arg,
learnt_end_values_t learnt_end_values_arg,
const SymbolTable& symbol_table_arg) :
learnt_in_period{learnt_in_period_arg},
learnt_in_period {move(learnt_in_period_arg)},
learnt_end_values {move(learnt_end_values_arg)},
symbol_table {symbol_table_arg}
{
......@@ -346,9 +343,10 @@ EndValLearntInStatement::writeOutput(ostream &output, [[maybe_unused]] const str
{
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
continue;
output << "struct('learnt_in'," << learnt_in_period
<< ",'exo_id'," << symbol_table.getTypeSpecificID(symb_id)+1
<< ",'type','" << typeToString(type) << "'"
output << "struct('learnt_in',";
visit([&](const auto& p) { output << p; }, learnt_in_period);
output << ",'exo_id'," << symbol_table.getTypeSpecificID(symb_id) + 1 << ",'type','"
<< typeToString(type) << "'"
<< ",'value',";
value->writeOutput(output);
output << ");" << endl;
......@@ -359,10 +357,19 @@ EndValLearntInStatement::writeOutput(ostream &output, [[maybe_unused]] const str
void
EndValLearntInStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "endval", "learnt_in": )"
<< learnt_in_period << R"(, "vals": [)";
for (bool printed_something{false};
auto &[type, symb_id, value] : learnt_end_values)
output << R"({"statementName": "endval", "learnt_in": )";
visit(
[&]<class T>(const T& p) {
if constexpr (is_same_v<T, int>)
output << p;
else if constexpr (is_same_v<T, string>)
output << '"' << p << '"';
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
},
learnt_in_period);
output << R"(, "vals": [)";
for (bool printed_something {false}; auto& [type, symb_id, value] : learnt_end_values)
{
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
continue;
......@@ -430,15 +437,18 @@ HistValStatement::writeOutput(ostream &output, [[maybe_unused]] const string &ba
output << "%" << endl
<< "% HISTVAL instructions" << endl
<< "%" << endl
<< "M_.histval_dseries = dseries(zeros(M_.orig_maximum_lag_with_diffs_expanded, M_.orig_endo_nbr"
<< "M_.histval_dseries = dseries(zeros(M_.orig_maximum_lag_with_diffs_expanded, "
"M_.orig_endo_nbr"
<< (symbol_table.AuxVarsSize() > 0 ? "+sum([M_.aux_vars.type]==6)" : "")
<< (symbol_table.exo_nbr() > 0 ? "+M_.exo_nbr" : "")
<< (symbol_table.exo_det_nbr() > 0 ? "+M_.exo_det_nbr" : "")
<< "), dates(sprintf('%dY', -M_.orig_maximum_lag_with_diffs_expanded+1)), [ M_.endo_names(1:M_.orig_endo_nbr); "
<< (symbol_table.AuxVarsSize() > 0 ? "M_.endo_names([M_.aux_vars(find([M_.aux_vars.type]==6)).endo_index]); " : "")
<< "), dates(sprintf('%dY', -M_.orig_maximum_lag_with_diffs_expanded+1)), [ "
"M_.endo_names(1:M_.orig_endo_nbr); "
<< (symbol_table.AuxVarsSize() > 0
? "M_.endo_names([M_.aux_vars(find([M_.aux_vars.type]==6)).endo_index]); "
: "")
<< (symbol_table.exo_nbr() > 0 ? "M_.exo_names; " : "")
<< (symbol_table.exo_det_nbr() > 0 ? "M_.exo_det_names; " : "")
<< "]);" << endl;
<< (symbol_table.exo_det_nbr() > 0 ? "M_.exo_det_names; " : "") << "]);" << endl;
for (const auto& [key, value] : hist_values)
{
......@@ -446,29 +456,38 @@ HistValStatement::writeOutput(ostream &output, [[maybe_unused]] const string &ba
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
continue;
output << "M_.histval_dseries{'" << symbol_table.getName(symb_id) << "'}(dates('" << lag << "Y'))=";
output << "M_.histval_dseries{'" << symbol_table.getName(symb_id) << "'}(dates('" << lag
<< "Y'))=";
value->writeOutput(output);
output << ";" << endl;
}
output << "if exist(['+' M_.fname '/dynamic_set_auxiliary_series.m'])" << endl
<< " eval(['M_.histval_dseries = ' M_.fname '.dynamic_set_auxiliary_series(M_.histval_dseries, M_.params);']);" << endl
<< " eval(['M_.histval_dseries = ' M_.fname "
"'.dynamic_set_auxiliary_series(M_.histval_dseries, M_.params);']);"
<< endl
<< "end" << endl
<< "M_.endo_histval = M_.histval_dseries{M_.endo_names{:}}(dates(sprintf('%dY', 1-M_.maximum_lag)):dates('0Y')).data';" << endl
<< "M_.endo_histval(isnan(M_.endo_histval)) = 0;" << endl; // Ensure that lead aux variables do not have a NaN
<< "M_.endo_histval = M_.histval_dseries{M_.endo_names{:}}(dates(sprintf('%dY', "
"1-M_.maximum_lag)):dates('0Y')).data';"
<< endl
<< "M_.endo_histval(isnan(M_.endo_histval)) = 0;"
<< endl; // Ensure that lead aux variables do not have a NaN
if (symbol_table.exo_nbr() > 0)
output << "M_.exo_histval = M_.histval_dseries{M_.exo_names{:}}(dates(sprintf('%dY', 1-M_.maximum_lag)):dates('0Y')).data';" << endl;
output << "M_.exo_histval = M_.histval_dseries{M_.exo_names{:}}(dates(sprintf('%dY', "
"1-M_.maximum_lag)):dates('0Y')).data';"
<< endl;
if (symbol_table.exo_det_nbr() > 0)
output << "M_.exo_det_histval = M_.histval_dseries{M_.exo_det_names{:}}(dates(sprintf('%dY', 1-M_.maximum_lag)):dates('0Y')).data';" << endl;
output << "M_.exo_det_histval = M_.histval_dseries{M_.exo_det_names{:}}(dates(sprintf('%dY', "
"1-M_.maximum_lag)):dates('0Y')).data';"
<< endl;
}
void
HistValStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "histval", "vals": [)";
for (bool printed_something{false};
const auto &[key, value] : hist_values)
for (bool printed_something {false}; const auto& [key, value] : hist_values)
{
auto& [symb_id, lag] = key;
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
......@@ -476,8 +495,7 @@ HistValStatement::writeJsonOutput(ostream &output) const
if (exchange(printed_something, true))
output << ", ";
output << R"({ "name": ")" << symbol_table.getName(symb_id) << R"(")"
<< R"(, "lag": )" << lag
<< R"(, "value": ")";
<< R"(, "lag": )" << lag << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -498,7 +516,9 @@ InitvalFileStatement::writeOutput(ostream &output, [[maybe_unused]] const string
<< "%" << endl
<< "options_.initval_file = true;" << endl;
options_list.writeOutput(output, "options_initvalf");
output << "[oo_.initval_series, options_.periods] = histvalf_initvalf('INITVALF', M_, options_initvalf);" << endl;
output << "[oo_.initval_series, options_.periods] = histvalf_initvalf('INITVALF', M_, "
"options_initvalf);"
<< endl;
}
void
......@@ -527,7 +547,9 @@ HistvalFileStatement::writeOutput(ostream &output, [[maybe_unused]] const string
<< "%" << endl
<< "options_.histval_file = true;" << endl;
options_list.writeOutput(output, "options_histvalf");
output << "[M_.endo_histval, M_.exo_histval, M_.exo_det_histval] = histvalf(M_, options_histvalf);" << endl;
output
<< "[M_.endo_histval, M_.exo_histval, M_.exo_det_histval] = histvalf(M_, options_histvalf);"
<< endl;
}
void
......@@ -558,7 +580,8 @@ HomotopySetupStatement::writeOutput(ostream &output, [[maybe_unused]] const stri
output << "%" << endl
<< "% HOMOTOPY_SETUP instructions" << endl
<< "%" << endl
<< "options_.homotopy_from_initval_to_endval = " << boolalpha << from_initval_to_endval << ';' << endl
<< "options_.homotopy_from_initval_to_endval = " << boolalpha << from_initval_to_endval
<< ';' << endl
<< "options_.homotopy_values = zeros(0, 4);" << endl;
for (auto [symb_id, expression1, expression2] : homotopy_values)
......@@ -566,7 +589,8 @@ HomotopySetupStatement::writeOutput(ostream &output, [[maybe_unused]] const stri
const SymbolType type = symbol_table.getType(symb_id);
const int tsid = symbol_table.getTypeSpecificID(symb_id) + 1;
output << "options_.homotopy_values = vertcat(options_.homotopy_values, [ " << static_cast<int>(type) << ", " << tsid << ", ";
output << "options_.homotopy_values = vertcat(options_.homotopy_values, [ "
<< static_cast<int>(type) << ", " << tsid << ", ";
if (expression1)
expression1->writeOutput(output);
else
......@@ -608,7 +632,8 @@ SaveParamsAndSteadyStateStatement::SaveParamsAndSteadyStateStatement(string file
}
void
SaveParamsAndSteadyStateStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basename,
SaveParamsAndSteadyStateStatement::writeOutput(ostream& output,
[[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
output << "save_params_and_steady_state('" << filename << "');" << endl;
......@@ -622,8 +647,8 @@ SaveParamsAndSteadyStateStatement::writeJsonOutput(ostream &output) const
<< "}";
}
LoadParamsAndSteadyStateStatement::LoadParamsAndSteadyStateStatement(const filesystem::path &filename,
const SymbolTable &symbol_table_arg,
LoadParamsAndSteadyStateStatement::LoadParamsAndSteadyStateStatement(
const filesystem::path& filename, const SymbolTable& symbol_table_arg,
WarningConsolidation& warnings) :
symbol_table {symbol_table_arg}
{
......@@ -651,14 +676,16 @@ LoadParamsAndSteadyStateStatement::LoadParamsAndSteadyStateStatement(const files
}
catch (SymbolTable::UnknownSymbolNameException& e)
{
warnings << "WARNING: Unknown symbol " << symb_name << " in " << filename.string() << endl;
warnings << "WARNING: Unknown symbol " << symb_name << " in " << filename.string()
<< endl;
}
}
f.close();
}
void
LoadParamsAndSteadyStateStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basename,
LoadParamsAndSteadyStateStatement::writeOutput(ostream& output,
[[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
for (const auto& [id, value] : content)
......@@ -678,7 +705,8 @@ LoadParamsAndSteadyStateStatement::writeOutput(ostream &output, [[maybe_unused]]
output << "oo_.exo_det_steady_state";
break;
default:
cerr << "ERROR: Unsupported variable type for " << symbol_table.getName(id) << " in load_params_and_steady_state" << endl;
cerr << "ERROR: Unsupported variable type for " << symbol_table.getName(id)
<< " in load_params_and_steady_state" << endl;
exit(EXIT_FAILURE);
}
......@@ -692,8 +720,7 @@ LoadParamsAndSteadyStateStatement::writeJsonOutput(ostream &output) const
{
output << R"({"statementName": "load_params_and_steady_state",)"
<< R"("values": [)";
for (bool printed_something{false};
const auto &[id, value] : content)
for (bool printed_something {false}; const auto& [id, value] : content)
{
if (exchange(printed_something, true))
output << ", ";
......
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,17 +17,18 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _NUMERICALINITIALIZATION_HH
#define _NUMERICALINITIALIZATION_HH
#ifndef NUMERICAL_INITIALIZATION_HH
#define NUMERICAL_INITIALIZATION_HH
#include <filesystem>
#include <map>
#include <string>
#include <variant>
#include <vector>
#include <map>
#include <filesystem>
#include "SymbolTable.hh"
#include "ExprNode.hh"
#include "Statement.hh"
#include "SymbolTable.hh"
using namespace std;
......@@ -37,6 +38,7 @@ private:
const int symb_id;
const expr_t param_value;
const SymbolTable& symbol_table;
public:
InitParamStatement(int symb_id_arg, const expr_t param_value_arg,
const SymbolTable& symbol_table_arg);
......@@ -55,18 +57,20 @@ public:
an initialization can depend on a previously initialized variable inside the block
*/
using init_values_t = vector<pair<int, expr_t>>;
protected:
const init_values_t init_values;
const SymbolTable& symbol_table;
const bool all_values_required;
public:
InitOrEndValStatement(init_values_t init_values_arg,
const SymbolTable &symbol_table_arg,
InitOrEndValStatement(init_values_t init_values_arg, const SymbolTable& symbol_table_arg,
bool all_values_required_arg);
//! Return set of unused variables by type
set<int> getUninitializedVariables(SymbolType type);
//! Fill eval context with variables values
void fillEvalContext(eval_context_t& eval_context) const;
protected:
void writeInitValues(ostream& output) const;
void writeJsonInitValues(ostream& output) const;
......@@ -75,8 +79,7 @@ protected:
class InitValStatement : public InitOrEndValStatement
{
public:
InitValStatement(init_values_t init_values_arg,
const SymbolTable &symbol_table_arg,
InitValStatement(init_values_t init_values_arg, const SymbolTable& symbol_table_arg,
bool all_values_required_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -88,8 +91,7 @@ public:
class EndValStatement : public InitOrEndValStatement
{
public:
EndValStatement(init_values_t init_values_arg,
const SymbolTable &symbol_table_arg,
EndValStatement(init_values_t init_values_arg, const SymbolTable& symbol_table_arg,
bool all_values_required_arg);
//! Workaround for trac ticket #35
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -100,7 +102,7 @@ public:
class EndValLearntInStatement : public Statement
{
public:
const int learnt_in_period;
const variant<int, string> learnt_in_period;
enum class LearntEndValType
{
level,
......@@ -110,11 +112,13 @@ public:
// The tuple is (type, symb_id, value)
using learnt_end_values_t = vector<tuple<LearntEndValType, int, expr_t>>;
const learnt_end_values_t learnt_end_values;
private:
const SymbolTable& symbol_table;
static string typeToString(LearntEndValType type);
public:
EndValLearntInStatement(int learnt_in_period_arg,
EndValLearntInStatement(variant<int, string> learnt_in_period_arg,
learnt_end_values_t learnt_end_values_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -131,13 +135,14 @@ public:
Maps pairs (symbol_id, lag) to expr_t
*/
using hist_values_t = map<pair<int, int>, expr_t>;
private:
const hist_values_t hist_values;
const SymbolTable& symbol_table;
const bool all_values_required;
public:
HistValStatement(hist_values_t hist_values_arg,
const SymbolTable &symbol_table_arg,
HistValStatement(hist_values_t hist_values_arg, const SymbolTable& symbol_table_arg,
bool all_values_required_arg);
//! Workaround for trac ticket #157
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -149,6 +154,7 @@ class InitvalFileStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit InitvalFileStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -159,6 +165,7 @@ class HistvalFileStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit HistvalFileStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -171,10 +178,12 @@ public:
//! Stores the declarations of homotopy_setup
/*! Order matter so we use a vector. First expr_t can be NULL if no initial value given. */
using homotopy_values_t = vector<tuple<int, expr_t, expr_t>>;
private:
const bool from_initval_to_endval; // Whether the from_initval_to_endval option was passed
const homotopy_values_t homotopy_values;
const SymbolTable& symbol_table;
public:
HomotopySetupStatement(bool from_initval_to_endval_arg, homotopy_values_t homotopy_values_arg,
const SymbolTable& symbol_table_arg);
......@@ -186,6 +195,7 @@ class SaveParamsAndSteadyStateStatement : public Statement
{
private:
const string filename;
public:
explicit SaveParamsAndSteadyStateStatement(string filename_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -199,6 +209,7 @@ private:
//! Content of the file
/*! Maps symbol ID to numeric value (stored as string) */
map<int, string> content;
public:
LoadParamsAndSteadyStateStatement(const filesystem::path& filename,
const SymbolTable& symbol_table_arg,
......
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,16 +17,19 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <fstream>
#include <iostream>
#include <cassert>
#include <sstream>
#include <cmath>
#include <fstream>
#include <iostream>
#include <numeric>
#include <ranges>
#include <sstream>
#include "ExprNode.hh"
#include "ParsingDriver.hh"
#include "Statement.hh"
#include "ExprNode.hh"
/* NB: the following also imports our specialization of operator<< for location class,
used below in error() and undeclared_model_variable_error() */
#include "WarningConsolidation.hh"
bool
......@@ -51,7 +54,9 @@ void
ParsingDriver::check_symbol_existence(const string& name)
{
if (!mod_file->symbol_table.exists(name))
error("Unknown symbol: " + name + ".\nIf referenced from the 'initval', 'endval', 'histval', or 'shocks' block, you can pass the 'nostrict' option to dynare to have this line ignored.");
error("Unknown symbol: " + name
+ ".\nIf referenced from the 'initval', 'endval', 'histval', or 'shocks' block, you can "
"pass the 'nostrict' option to dynare to have this line ignored.");
}
void
......@@ -69,6 +74,7 @@ ParsingDriver::set_current_data_tree(DataTree *data_tree_arg)
data_tree = data_tree_arg;
model_tree = dynamic_cast<ModelTree*>(data_tree_arg);
dynamic_model = dynamic_cast<DynamicModel*>(data_tree_arg);
heterogeneous_model = dynamic_cast<HeterogeneousModel*>(data_tree_arg);
}
void
......@@ -109,7 +115,7 @@ ParsingDriver::parse(istream &in, bool debug)
void
ParsingDriver::error(const Dynare::parser::location_type& l, const string& m)
{
create_error_string(l, m, cerr);
cerr << "ERROR: " << l << ": " << m << endl;
exit(EXIT_FAILURE);
}
......@@ -119,52 +125,12 @@ ParsingDriver::error(const string &m)
error(location, m);
}
void
ParsingDriver::create_error_string(const Dynare::parser::location_type &l, const string &m, ostream &stream)
{
stream << "ERROR: " << *l.begin.filename << ": line " << l.begin.line;
if (l.begin.line == l.end.line)
if (l.begin.column == l.end.column - 1)
stream << ", col " << l.begin.column;
else
stream << ", cols " << l.begin.column << "-" << l.end.column - 1;
else
stream << ", col " << l.begin.column << " -"
<< " line " << l.end.line << ", col " << l.end.column - 1;
stream << ": " << m << endl;
}
void
ParsingDriver::create_error_string(const Dynare::parser::location_type &l, const string &m, const string &var)
{
ostringstream stream;
create_error_string(l, m, stream);
model_errors.emplace_back(var, stream.str());
}
void
ParsingDriver::model_error(const string &m, const string &var)
{
create_error_string(location, m, var);
}
void
ParsingDriver::undeclared_model_variable_error(const string& m, const string& var)
{
ostringstream stream;
if (!nostrict)
{
stream << "ERROR: " << *location.begin.filename << ": line " << location.begin.line;
if (location.begin.line == location.end.line)
if (location.begin.column == location.end.column - 1)
stream << ", col " << location.begin.column;
else
stream << ", cols " << location.begin.column << "-" << location.end.column - 1;
else
stream << ", col " << location.begin.column << " -"
<< " line " << location.end.line << ", col " << location.end.column - 1;
stream << ": ";
}
stream << "ERROR: " << location << ": ";
stream << m;
if (nostrict)
stream << " automatically declared exogenous.";
......@@ -178,12 +144,15 @@ ParsingDriver::warning(const string &m)
}
int
ParsingDriver::declare_symbol(const string &name, SymbolType type, const string &tex_name, const vector<pair<string, string>> &partition_value)
ParsingDriver::declare_symbol(const string& name, SymbolType type, const string& tex_name,
const vector<pair<string, string>>& partition_value,
const optional<int>& heterogeneity_dimension)
{
int symb_id;
try
{
symb_id = mod_file->symbol_table.addSymbol(name, type, tex_name, partition_value);
symb_id = mod_file->symbol_table.addSymbol(name, type, tex_name, partition_value,
heterogeneity_dimension);
}
catch (SymbolTable::AlreadyDeclaredException& e)
{
......@@ -199,53 +168,97 @@ ParsingDriver::declare_symbol(const string &name, SymbolType type, const string
}
int
ParsingDriver::declare_endogenous(const string &name, const string &tex_name, const vector<pair<string, string>> &partition_value)
ParsingDriver::declare_endogenous(const string& name, const string& tex_name,
const vector<pair<string, string>>& partition_value)
{
return declare_symbol(name, SymbolType::endogenous, tex_name, partition_value);
return declare_symbol(name, SymbolType::endogenous, tex_name, partition_value, {});
}
void
ParsingDriver::var(const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
bool log_option)
const optional<string>& heterogeneity_dimension, bool log_option)
{
for (auto& [name, tex_name, partition] : symbol_list)
{
int symb_id = declare_endogenous(name, tex_name, partition);
int symb_id {[&] {
if (heterogeneity_dimension)
try
{
return declare_symbol(name, SymbolType::heterogeneousEndogenous, tex_name, partition,
mod_file->heterogeneity_table.getID(*heterogeneity_dimension));
}
catch (HeterogeneityTable::UnknownDimensionNameException&)
{
error("Unknown heterogeneity dimension: " + *heterogeneity_dimension);
}
else
return declare_endogenous(name, tex_name, partition);
}()};
if (log_option)
mod_file->symbol_table.markWithLogTransform(symb_id);
}
}
int
ParsingDriver::declare_exogenous(const string &name, const string &tex_name, const vector<pair<string, string>> &partition_value)
ParsingDriver::declare_exogenous(const string& name, const string& tex_name,
const vector<pair<string, string>>& partition_value)
{
return declare_symbol(name, SymbolType::exogenous, tex_name, partition_value);
return declare_symbol(name, SymbolType::exogenous, tex_name, partition_value, {});
}
void
ParsingDriver::varexo(const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list)
ParsingDriver::varexo(
const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
const optional<string>& heterogeneity_dimension)
{
for (auto& [name, tex_name, partition] : symbol_list)
if (heterogeneity_dimension)
try
{
declare_symbol(name, SymbolType::heterogeneousExogenous, tex_name, partition,
mod_file->heterogeneity_table.getID(*heterogeneity_dimension));
}
catch (HeterogeneityTable::UnknownDimensionNameException&)
{
error("Unknown heterogeneity dimension: " + *heterogeneity_dimension);
}
else
declare_exogenous(name, tex_name, partition);
}
void
ParsingDriver::varexo_det(const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list)
ParsingDriver::varexo_det(
const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list)
{
for (auto& [name, tex_name, partition] : symbol_list)
declare_symbol(name, SymbolType::exogenousDet, tex_name, partition);
declare_symbol(name, SymbolType::exogenousDet, tex_name, partition, {});
}
int
ParsingDriver::declare_parameter(const string &name, const string &tex_name, const vector<pair<string, string>> &partition_value)
ParsingDriver::declare_parameter(const string& name, const string& tex_name,
const vector<pair<string, string>>& partition_value)
{
return declare_symbol(name, SymbolType::parameter, tex_name, partition_value);
return declare_symbol(name, SymbolType::parameter, tex_name, partition_value, {});
}
void
ParsingDriver::parameters(const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list)
ParsingDriver::parameters(
const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
const optional<string>& heterogeneity_dimension)
{
for (auto& [name, tex_name, partition] : symbol_list)
if (heterogeneity_dimension)
try
{
declare_symbol(name, SymbolType::heterogeneousParameter, tex_name, partition,
mod_file->heterogeneity_table.getID(*heterogeneity_dimension));
}
catch (HeterogeneityTable::UnknownDimensionNameException&)
{
error("Unknown heterogeneity dimension: " + *heterogeneity_dimension);
}
else
declare_parameter(name, tex_name, partition);
}
......@@ -255,7 +268,7 @@ ParsingDriver::declare_statement_local_variable(const string &name)
if (mod_file->symbol_table.exists(name))
error("Symbol " + name + " cannot be assigned within a statement "
+ "while being assigned elsewhere in the modfile");
declare_symbol(name, SymbolType::statementDeclaredVariable, "", {});
declare_symbol(name, SymbolType::statementDeclaredVariable, "", {}, {});
}
void
......@@ -271,7 +284,8 @@ ParsingDriver::set_planner_discount_latex_name(string tex_name)
}
void
ParsingDriver::end_trend_var(bool log_trend, expr_t growth_factor, const vector<pair<string, string>> &symbol_list)
ParsingDriver::end_trend_var(bool log_trend, expr_t growth_factor,
const vector<pair<string, string>>& symbol_list)
{
/* Run detrending engine if trend variables are present, even if unused in
a var(deflator=…) statement (see #113). */
......@@ -280,7 +294,8 @@ ParsingDriver::end_trend_var(bool log_trend, expr_t growth_factor, const vector<
vector<int> declared_trend_vars;
for (auto& [name, tex_name] : symbol_list)
{
int symb_id = declare_symbol(name, log_trend ? SymbolType::logTrend : SymbolType::trend, tex_name, {});
int symb_id = declare_symbol(name, log_trend ? SymbolType::logTrend : SymbolType::trend,
tex_name, {}, {});
declared_trend_vars.push_back(symb_id);
}
......@@ -328,7 +343,7 @@ ParsingDriver::add_inf_constant()
expr_t
ParsingDriver::add_model_variable(const string& name)
{
if (name.find(".") != string::npos)
if (name.find('.') != string::npos)
error(name + " treated as a variable, but it contains a '.'");
check_symbol_existence_in_model_block(name);
......@@ -337,7 +352,9 @@ ParsingDriver::add_model_variable(const string &name)
{
symb_id = mod_file->symbol_table.getID(name);
if (mod_file->symbol_table.getType(symb_id) == SymbolType::excludedVariable)
error("Variable '" + name + "' can no longer be used since it has been excluded by a previous 'model_remove' or 'var_remove' statement");
error("Variable '" + name
+ "' can no longer be used since it has been excluded by a previous 'model_remove' "
"or 'var_remove' statement");
}
catch (SymbolTable::UnknownSymbolNameException& e)
{
......@@ -361,8 +378,7 @@ ParsingDriver::declare_or_change_type(SymbolType new_type, const string &name)
// remove error messages
undeclared_model_vars.erase(name);
erase_if(undeclared_model_variable_errors,
[&name](auto &v) { return v.first == name; });
erase_if(undeclared_model_variable_errors, [&name](auto& v) { return v.first == name; });
}
catch (SymbolTable::UnknownSymbolNameException& e)
{
......@@ -382,7 +398,6 @@ ParsingDriver::declare_or_change_type(SymbolType new_type, const string &name)
}
}
return add_model_variable(symb_id, 0);
}
expr_t
......@@ -397,14 +412,13 @@ ParsingDriver::add_model_variable(int symb_id, int lag)
if (type == SymbolType::externalFunction)
error("Symbol " + mod_file->symbol_table.getName(symb_id)
+" is a function name external to Dynare. It cannot be used like a variable without input argument inside model.");
+ " is a function name external to Dynare. It cannot be used like a variable without "
"input argument inside model.");
// See dynare#1765
if (type == SymbolType::exogenousDet && lag != 0)
error("Exogenous deterministic variable " + mod_file->symbol_table.getName(symb_id) + " cannot be given a lead or a lag.");
if (type == SymbolType::modelLocalVariable && lag != 0)
error("Model local variable " + mod_file->symbol_table.getName(symb_id) + " cannot be given a lead or a lag.");
error("Exogenous deterministic variable " + mod_file->symbol_table.getName(symb_id)
+ " cannot be given a lead or a lag.");
if (data_tree == planner_objective.get())
{
......@@ -412,30 +426,35 @@ ParsingDriver::add_model_variable(int symb_id, int lag)
error("Leads and lags on variables are forbidden in 'planner_objective'.");
if (type == SymbolType::modelLocalVariable)
error("Model local variable " + mod_file->symbol_table.getName(symb_id) + " cannot be used in 'planner_objective'.");
error("Model local variable " + mod_file->symbol_table.getName(symb_id)
+ " cannot be used in 'planner_objective'.");
}
if (data_tree == occbin_constraints_tree.get())
{
if (lag != 0)
error("Leads and lags on variables are forbidden in 'occbin_constraints'. Note that you can achieve the same effect by introducing an auxiliary variable in the model.");
error("Leads and lags on variables are forbidden in 'occbin_constraints'. Note that you "
"can achieve the same effect by introducing an auxiliary variable in the model.");
if (type == SymbolType::modelLocalVariable)
error("Model local variable " + mod_file->symbol_table.getName(symb_id) + " cannot be used in 'occbin_constraints'.");
error("Model local variable " + mod_file->symbol_table.getName(symb_id)
+ " cannot be used in 'occbin_constraints'.");
if (type == SymbolType::exogenous || type == SymbolType::exogenousDet)
error("Exogenous variable " + mod_file->symbol_table.getName(symb_id) + " cannot be used in 'occbin_constraints'.");
error("Exogenous variable " + mod_file->symbol_table.getName(symb_id)
+ " cannot be used in 'occbin_constraints'.");
}
// It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
// NB: we use data_tree here, to avoid a crash in the occbin_constraints case
// It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous
// and parameters can be swapped NB: we use data_tree here, to avoid a crash in the
// occbin_constraints case
return data_tree->AddVariable(symb_id, lag);
}
expr_t
ParsingDriver::add_expression_variable(const string& name)
{
if (name.find(".") != string::npos)
if (name.find('.') != string::npos)
error(name + " treated as a variable, but it contains a '.'");
if (parsing_epilogue && !mod_file->symbol_table.exists(name))
......@@ -447,21 +466,26 @@ ParsingDriver::add_expression_variable(const string &name)
// This check must come after the previous one!
if (mod_file->symbol_table.getType(name) == SymbolType::modelLocalVariable)
error("Variable " + name + " not allowed outside model declaration. Its scope is only inside model.");
error("Variable " + name
+ " not allowed outside model declaration. Its scope is only inside model.");
if (mod_file->symbol_table.getType(name) == SymbolType::trend
|| mod_file->symbol_table.getType(name) == SymbolType::logTrend)
error("Variable " + name + " not allowed outside model declaration, because it is a trend variable.");
error("Variable " + name
+ " not allowed outside model declaration, because it is a trend variable.");
if (mod_file->symbol_table.getType(name) == SymbolType::externalFunction)
error("Symbol '" + name + "' is the name of a MATLAB/Octave function, and cannot be used as a variable.");
error("Symbol '" + name
+ "' is the name of a MATLAB/Octave function, and cannot be used as a variable.");
int symb_id = mod_file->symbol_table.getID(name);
return data_tree->AddVariable(symb_id);
}
void
ParsingDriver::end_nonstationary_var(bool log_deflator, expr_t deflator, const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list, bool log_option)
ParsingDriver::end_nonstationary_var(
bool log_deflator, expr_t deflator,
const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list, bool log_option)
{
mod_file->nonstationary_variables = true;
......@@ -487,7 +511,8 @@ ParsingDriver::end_nonstationary_var(bool log_deflator, expr_t deflator, const v
deflator->collectVariables(SymbolType::endogenous, r);
for (int it : r)
if (dynamic_model->isNonstationary(it))
error("The deflator contains a non-stationary endogenous variable. This is not allowed. Please use only stationary endogenous and/or {log_}trend_vars.");
error("The deflator contains a non-stationary endogenous variable. This is not allowed. "
"Please use only stationary endogenous and/or {log_}trend_vars.");
declared_nonstationary_vars.clear();
reset_data_tree();
......@@ -538,7 +563,8 @@ ParsingDriver::initval_file()
}
void
ParsingDriver::end_val(EndValLearntInStatement::LearntEndValType type, const string &name, expr_t rhs)
ParsingDriver::end_val(EndValLearntInStatement::LearntEndValType type, const string& name,
expr_t rhs)
{
if (nostrict && !mod_file->symbol_table.exists(name))
{
......@@ -582,8 +608,7 @@ ParsingDriver::homotopy_val(const string &name, expr_t val1, expr_t val2)
int symb_id = mod_file->symbol_table.getID(name);
SymbolType type = mod_file->symbol_table.getType(symb_id);
if (type != SymbolType::parameter
&& type != SymbolType::exogenous
if (type != SymbolType::parameter && type != SymbolType::exogenous
&& type != SymbolType::exogenousDet)
error("homotopy_val: " + name + " should be a parameter or exogenous variable");
......@@ -593,9 +618,8 @@ ParsingDriver::homotopy_val(const string &name, expr_t val1, expr_t val2)
void
ParsingDriver::end_generate_irfs()
{
mod_file->addStatement(make_unique<GenerateIRFsStatement>(move(options_list),
move(generate_irf_names),
move(generate_irf_elements)));
mod_file->addStatement(make_unique<GenerateIRFsStatement>(
move(options_list), move(generate_irf_names), move(generate_irf_elements)));
generate_irf_elements.clear();
generate_irf_names.clear();
......@@ -607,8 +631,8 @@ ParsingDriver::add_generate_irfs_element(string name)
{
for (const auto& it : generate_irf_names)
if (it == name)
error("Names in the generate_irfs block must be unique but you entered '"
+ name + "' more than once.");
error("Names in the generate_irfs block must be unique but you entered '" + name
+ "' more than once.");
generate_irf_names.push_back(move(name));
generate_irf_elements.push_back(generate_irf_exos);
......@@ -749,9 +773,11 @@ ParsingDriver::end_endval(bool all_values_required)
end_values_new.emplace_back(symb_id, value);
break;
case EndValLearntInStatement::LearntEndValType::add:
error("endval: '" + mod_file->symbol_table.getName(symb_id) + " += ...' line not allowed unless 'learnt_in' option with value >1 is passed");
error("endval: '" + mod_file->symbol_table.getName(symb_id)
+ " += ...' line not allowed unless 'learnt_in' option with value >1 is passed");
case EndValLearntInStatement::LearntEndValType::multiply:
error("endval: '" + mod_file->symbol_table.getName(symb_id) + " *= ...' line not allowed unless 'learnt_in' option with value >1 is passed");
error("endval: '" + mod_file->symbol_table.getName(symb_id)
+ " *= ...' line not allowed unless 'learnt_in' option with value >1 is passed");
}
mod_file->addStatement(make_unique<EndValStatement>(move(end_values_new), mod_file->symbol_table,
......@@ -760,21 +786,26 @@ ParsingDriver::end_endval(bool all_values_required)
}
void
ParsingDriver::end_endval_learnt_in(const string &learnt_in_period)
ParsingDriver::end_endval_learnt_in(variant<int, string> learnt_in_period)
{
int learnt_in_period_int = stoi(learnt_in_period);
if (holds_alternative<int>(learnt_in_period))
{
int learnt_in_period_int = get<int>(learnt_in_period);
if (learnt_in_period_int < 1)
error("endval: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option");
error("endval: value '" + to_string(learnt_in_period_int)
+ "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
{
end_endval(false);
return;
}
}
for (auto [type, symb_id, value] : end_values)
if (mod_file->symbol_table.getType(symb_id) != SymbolType::exogenous)
error("endval(learnt_in=...): " + mod_file->symbol_table.getName(symb_id) + " is not an exogenous variable");
mod_file->addStatement(make_unique<EndValLearntInStatement>(learnt_in_period_int, move(end_values),
mod_file->symbol_table));
error("endval(learnt_in=...): " + mod_file->symbol_table.getName(symb_id)
+ " is not an exogenous variable");
mod_file->addStatement(make_unique<EndValLearntInStatement>(
move(learnt_in_period), move(end_values), mod_file->symbol_table));
end_values.clear();
}
......@@ -789,7 +820,8 @@ ParsingDriver::end_histval(bool all_values_required)
void
ParsingDriver::end_homotopy(bool from_initval_to_endval)
{
mod_file->addStatement(make_unique<HomotopySetupStatement>(from_initval_to_endval, move(homotopy_values), mod_file->symbol_table));
mod_file->addStatement(make_unique<HomotopySetupStatement>(
from_initval_to_endval, move(homotopy_values), mod_file->symbol_table));
homotopy_values.clear();
}
......@@ -810,7 +842,7 @@ ParsingDriver::end_epilogue()
void
ParsingDriver::add_epilogue_variable(const string& name)
{
declare_symbol(name, SymbolType::epilogue, "", {});
declare_symbol(name, SymbolType::epilogue, "", {}, {});
}
void
......@@ -826,16 +858,25 @@ ParsingDriver::begin_model()
}
void
ParsingDriver::end_model()
ParsingDriver::begin_heterogeneous_model(const string& heterogeneity_dimension)
{
bool exit_after_write = false;
if (model_errors.size() > 0)
for (auto &it : model_errors)
int het_dim_id {[&] {
try
{
if (it.first.empty())
exit_after_write = true;
cerr << it.second;
return mod_file->heterogeneity_table.getID(heterogeneity_dimension);
}
catch (HeterogeneityTable::UnknownDimensionNameException&)
{
error("Unknown heterogeneity dimension: " + heterogeneity_dimension);
}
}()};
set_current_data_tree(&mod_file->heterogeneous_models.at(het_dim_id));
}
void
ParsingDriver::end_model()
{
bool exit_after_write = false;
if (undeclared_model_variable_errors.size() > 0)
for (auto& it : undeclared_model_variable_errors)
......@@ -866,7 +907,30 @@ ParsingDriver::end_shocks(bool overwrite)
if (!learnt_shocks_add.empty())
error("shocks: 'add' keyword not allowed unless 'learnt_in' option with value >1 is passed");
if (!learnt_shocks_multiply.empty())
error("shocks: 'multiply' keyword not allowed unless 'learnt_in' option with value >1 is passed");
error(
"shocks: 'multiply' keyword not allowed unless 'learnt_in' option with value >1 is passed");
var_shocks.clear();
std_shocks.clear();
covar_shocks.clear();
corr_shocks.clear();
}
void
ParsingDriver::end_heterogeneous_shocks(const string& heterogeneity_dimension, bool overwrite)
{
int het_dim_id {[&] {
try
{
return mod_file->heterogeneity_table.getID(heterogeneity_dimension);
}
catch (HeterogeneityTable::UnknownDimensionNameException&)
{
error("Unknown heterogeneity dimension: " + heterogeneity_dimension);
}
}()};
mod_file->addStatement(make_unique<HeterogeneousShocksStatement>(
het_dim_id, overwrite, move(var_shocks), move(std_shocks), move(covar_shocks),
move(corr_shocks), mod_file->symbol_table, mod_file->heterogeneity_table));
var_shocks.clear();
std_shocks.clear();
covar_shocks.clear();
......@@ -877,8 +941,7 @@ void
ParsingDriver::end_mshocks(bool overwrite, bool relative_to_initval)
{
mod_file->addStatement(make_unique<MShocksStatement>(overwrite, relative_to_initval,
move(det_shocks),
mod_file->symbol_table));
move(det_shocks), mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("mshocks: 'add' keyword not allowed");
......@@ -889,8 +952,13 @@ ParsingDriver::end_mshocks(bool overwrite, bool relative_to_initval)
void
ParsingDriver::end_shocks_surprise(bool overwrite)
{
mod_file->addStatement(make_unique<ShocksSurpriseStatement>(overwrite, move(det_shocks),
mod_file->symbol_table));
if (ranges::any_of(views::values(det_shocks), [](auto& v) {
return ranges::any_of(views::keys(v),
[](auto& p) { return !holds_alternative<pair<int, int>>(p); });
}))
error("shocks(surprise): dates are not allowed in the 'periods' keyword");
mod_file->addStatement(
make_unique<ShocksSurpriseStatement>(overwrite, move(det_shocks), mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("shocks(surprise): 'add' keyword not allowed");
......@@ -899,11 +967,14 @@ ParsingDriver::end_shocks_surprise(bool overwrite)
}
void
ParsingDriver::end_shocks_learnt_in(const string &learnt_in_period, bool overwrite)
ParsingDriver::end_shocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite)
{
int learnt_in_period_int = stoi(learnt_in_period);
if (holds_alternative<int>(learnt_in_period))
{
int learnt_in_period_int = get<int>(learnt_in_period);
if (learnt_in_period_int < 1)
error("shocks: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option");
error("shocks: value '" + to_string(learnt_in_period_int)
+ "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
{
end_shocks(overwrite);
......@@ -911,74 +982,95 @@ ParsingDriver::end_shocks_learnt_in(const string &learnt_in_period, bool overwri
}
for (auto& storage : {det_shocks, learnt_shocks_add, learnt_shocks_multiply})
for (auto& [symb_id, vals] : storage)
for (auto [period1, period2, expr] : vals)
if (period1 < learnt_in_period_int)
error("shocks: for variable " + mod_file->symbol_table.getName(symb_id) + ", shock period (" + to_string(period1) + ") is earlier than the period in which the shock is learnt (" + learnt_in_period + ")");
for (const auto& [period_range, expr] : vals)
if (holds_alternative<pair<int, int>>(period_range))
if (int period1 = get<pair<int, int>>(period_range).first;
period1 < learnt_in_period_int)
error("shocks: for variable " + mod_file->symbol_table.getName(symb_id)
+ ", shock period (" + to_string(period1)
+ ") is earlier than the period in which the shock is learnt ("
+ to_string(learnt_in_period_int) + ")");
}
// Aggregate the three types of shocks
ShocksLearntInStatement::learnt_shocks_t learnt_shocks;
for (const auto& [id, v] : det_shocks)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::level, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::level, period_range, value);
learnt_shocks[id] = v2;
}
for (const auto& [id, v] : learnt_shocks_add)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::add, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::add, period_range, value);
learnt_shocks[id] = v2;
}
for (const auto& [id, v] : learnt_shocks_multiply)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::multiply, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::multiply, period_range, value);
learnt_shocks[id] = v2;
}
mod_file->addStatement(make_unique<ShocksLearntInStatement>(learnt_in_period_int, overwrite,
move(learnt_shocks),
mod_file->symbol_table));
mod_file->addStatement(make_unique<ShocksLearntInStatement>(
move(learnt_in_period), overwrite, move(learnt_shocks), mod_file->symbol_table));
det_shocks.clear();
learnt_shocks_add.clear();
learnt_shocks_multiply.clear();
}
void
ParsingDriver::end_mshocks_learnt_in(const string &learnt_in_period, bool overwrite, bool relative_to_initval)
ParsingDriver::end_mshocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite,
bool relative_to_initval)
{
if (holds_alternative<int>(learnt_in_period))
{
int learnt_in_period_int = stoi(learnt_in_period);
int learnt_in_period_int = get<int>(learnt_in_period);
if (learnt_in_period_int < 1)
error("mshocks: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option");
error("mshocks: value '" + to_string(learnt_in_period_int)
+ "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
{
end_mshocks(overwrite, relative_to_initval);
return;
}
for (auto& [symb_id, vals] : det_shocks)
for (auto [period1, period2, expr] : vals)
if (period1 < learnt_in_period_int)
error("mshocks: for variable " + mod_file->symbol_table.getName(symb_id) + ", shock period (" + to_string(period1) + ") is earlier than the period in which the shock is learnt (" + learnt_in_period + ")");
for (const auto& [period_range, expr] : vals)
if (holds_alternative<pair<int, int>>(period_range))
if (int period1 = get<pair<int, int>>(period_range).first;
period1 < learnt_in_period_int)
error("mshocks: for variable " + mod_file->symbol_table.getName(symb_id)
+ ", shock period (" + to_string(period1)
+ ") is earlier than the period in which the shock is learnt ("
+ to_string(learnt_in_period_int) + ")");
}
ShocksLearntInStatement::learnt_shocks_t learnt_shocks;
const auto type { relative_to_initval ?
ShocksLearntInStatement::LearntShockType::multiplyInitialSteadyState :
ShocksLearntInStatement::LearntShockType::multiplySteadyState };
const auto type {relative_to_initval
? ShocksLearntInStatement::LearntShockType::multiplyInitialSteadyState
: ShocksLearntInStatement::LearntShockType::multiplySteadyState};
for (const auto& [id, v] : det_shocks)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(type, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(type, period_range, value);
learnt_shocks[id] = v2;
}
mod_file->addStatement(make_unique<ShocksLearntInStatement>(learnt_in_period_int, overwrite,
move(learnt_shocks),
mod_file->symbol_table));
mod_file->addStatement(make_unique<ShocksLearntInStatement>(
move(learnt_in_period), overwrite, move(learnt_shocks), mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("mshocks: 'add' keyword not allowed");
......@@ -989,16 +1081,17 @@ ParsingDriver::end_mshocks_learnt_in(const string &learnt_in_period, bool overwr
void
ParsingDriver::end_heteroskedastic_shocks(bool overwrite)
{
mod_file->addStatement(make_unique<HeteroskedasticShocksStatement>(overwrite,
move(heteroskedastic_shocks_values),
move(heteroskedastic_shocks_scales),
mod_file->addStatement(make_unique<HeteroskedasticShocksStatement>(
overwrite, move(heteroskedastic_shocks_values), move(heteroskedastic_shocks_scales),
mod_file->symbol_table));
heteroskedastic_shocks_values.clear();
heteroskedastic_shocks_scales.clear();
}
void
ParsingDriver::add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, DetShockType type)
ParsingDriver::add_det_shock(const string& var,
const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, DetShockType type)
{
switch (type)
{
......@@ -1022,12 +1115,13 @@ ParsingDriver::add_det_shock(const string &var, const vector<pair<int, int>> &pe
error("shocks/conditional_forecast_paths: variable " + var + " declared twice");
if (periods.size() != values.size())
error("shocks/conditional_forecast_paths: variable " + var + ": number of periods is different from number of shock values");
error("shocks/conditional_forecast_paths: variable " + var
+ ": number of periods is different from number of shock values");
vector<tuple<int, int, expr_t>> v;
vector<pair<AbstractShocksStatement::period_range_t, expr_t>> v;
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i].first, periods[i].second, values[i]);
v.emplace_back(periods[i], values[i]);
switch (type)
{
......@@ -1045,10 +1139,15 @@ ParsingDriver::add_det_shock(const string &var, const vector<pair<int, int>> &pe
}
void
ParsingDriver::add_heteroskedastic_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool scales)
ParsingDriver::add_heteroskedastic_shock(
const string& var, const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, bool scales)
{
check_symbol_is_exogenous(var, false);
if (ranges::any_of(periods, [](auto& p) { return !holds_alternative<pair<int, int>>(p); }))
error("heteroskedastic_shocks: dates are not allowed in the 'periods' keyword");
int symb_id = mod_file->symbol_table.getID(var);
if ((!scales && heteroskedastic_shocks_values.contains(symb_id))
......@@ -1056,11 +1155,15 @@ ParsingDriver::add_heteroskedastic_shock(const string &var, const vector<pair<in
error("heteroskedastic_shocks: variable " + var + " declared twice");
if (periods.size() != values.size())
error("heteroskedastic_shocks: variable " + var + ": number of periods is different from number of shock values");
error("heteroskedastic_shocks: variable " + var
+ ": number of periods is different from number of shock values");
vector<tuple<int, int, expr_t>> v;
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i].first, periods[i].second, values[i]);
{
auto [period1, period2] = get<pair<int, int>>(periods[i]);
v.emplace_back(period1, period2, values[i]);
}
if (scales)
heteroskedastic_shocks_scales[symb_id] = v;
......@@ -1073,7 +1176,8 @@ ParsingDriver::add_stderr_shock(const string &var, expr_t value)
{
if (nostrict && !mod_file->symbol_table.exists(var))
{
warning("discarding shocks block declaration of the standard error of '" + var + "' as it was not declared");
warning("discarding shocks block declaration of the standard error of '" + var
+ "' as it was not declared");
return;
}
......@@ -1091,7 +1195,8 @@ ParsingDriver::add_var_shock(const string &var, expr_t value)
{
if (nostrict && !mod_file->symbol_table.exists(var))
{
warning("discarding shocks block declaration of the variance of '" + var + "' as it was not declared");
warning("discarding shocks block declaration of the variance of '" + var
+ "' as it was not declared");
return;
}
......@@ -1107,10 +1212,10 @@ ParsingDriver::add_var_shock(const string &var, expr_t value)
void
ParsingDriver::add_covar_shock(const string& var1, const string& var2, expr_t value)
{
if (nostrict &&
(!mod_file->symbol_table.exists(var1) || !mod_file->symbol_table.exists(var2)))
if (nostrict && (!mod_file->symbol_table.exists(var1) || !mod_file->symbol_table.exists(var2)))
{
warning("discarding shocks block declaration of the covariance of '" + var1 + "' and '" + var2 + "' as at least one was not declared");
warning("discarding shocks block declaration of the covariance of '" + var1 + "' and '" + var2
+ "' as at least one was not declared");
return;
}
......@@ -1121,10 +1226,10 @@ ParsingDriver::add_covar_shock(const string &var1, const string &var2, expr_t va
pair key {symb_id1, symb_id2}, key_inv {symb_id2, symb_id1};
if (covar_shocks.contains(key) || covar_shocks.contains(key_inv)
|| corr_shocks.contains(key) || corr_shocks.contains(key_inv))
error("shocks: covariance or correlation shock on variable pair (" + var1 + ", "
+ var2 + ") declared twice");
if (covar_shocks.contains(key) || covar_shocks.contains(key_inv) || corr_shocks.contains(key)
|| corr_shocks.contains(key_inv))
error("shocks: covariance or correlation shock on variable pair (" + var1 + ", " + var2
+ ") declared twice");
covar_shocks[key] = value;
}
......@@ -1132,10 +1237,10 @@ ParsingDriver::add_covar_shock(const string &var1, const string &var2, expr_t va
void
ParsingDriver::add_correl_shock(const string& var1, const string& var2, expr_t value)
{
if (nostrict &&
(!mod_file->symbol_table.exists(var1) || !mod_file->symbol_table.exists(var2)))
if (nostrict && (!mod_file->symbol_table.exists(var1) || !mod_file->symbol_table.exists(var2)))
{
warning("discarding shocks block declaration of the correlation of '" + var1 + "' and '" + var2 + "' as at least one was not declared");
warning("discarding shocks block declaration of the correlation of '" + var1 + "' and '"
+ var2 + "' as at least one was not declared");
return;
}
......@@ -1146,10 +1251,10 @@ ParsingDriver::add_correl_shock(const string &var1, const string &var2, expr_t v
pair key {symb_id1, symb_id2}, key_inv {symb_id2, symb_id1};
if (covar_shocks.contains(key) || covar_shocks.contains(key_inv)
|| corr_shocks.contains(key) || corr_shocks.contains(key_inv))
error("shocks: covariance or correlation shock on variable pair (" + var1 + ", "
+ var2 + ") declared twice");
if (covar_shocks.contains(key) || covar_shocks.contains(key_inv) || corr_shocks.contains(key)
|| corr_shocks.contains(key_inv))
error("shocks: covariance or correlation shock on variable pair (" + var1 + ", " + var2
+ ") declared twice");
corr_shocks[key] = value;
}
......@@ -1165,11 +1270,9 @@ ParsingDriver::begin_svar_identification()
void
ParsingDriver::end_svar_identification()
{
mod_file->addStatement(make_unique<SvarIdentificationStatement>(move(svar_ident_restrictions),
svar_upper_cholesky,
svar_lower_cholesky,
svar_constants_exclusion,
mod_file->symbol_table));
mod_file->addStatement(make_unique<SvarIdentificationStatement>(
move(svar_ident_restrictions), svar_upper_cholesky, svar_lower_cholesky,
svar_constants_exclusion, mod_file->symbol_table));
svar_equation_restrictions.clear();
svar_ident_restrictions.clear();
svar_Qi_restriction_nbr.clear();
......@@ -1206,7 +1309,8 @@ ParsingDriver::combine_lag_and_restriction(const string &lag)
}
void
ParsingDriver::add_restriction_in_equation(const string &equation, const vector<string> &symbol_list)
ParsingDriver::add_restriction_in_equation(const string& equation,
const vector<string>& symbol_list)
{
int eqn = stoi(equation);
if (eqn < 1)
......@@ -1249,9 +1353,10 @@ ParsingDriver::add_restriction_equal()
}
void
ParsingDriver::add_positive_restriction_element(expr_t value, const string &variable, const string &lag)
ParsingDriver::add_positive_restriction_element(expr_t value, const string& variable,
const string& lag)
{
// if the expression is not on the left handside, change its sign
// if the expression is not on the left-hand side, change its sign
if (!svar_left_handside)
value = add_uminus(value);
......@@ -1263,7 +1368,7 @@ ParsingDriver::add_positive_restriction_element(const string &variable, const st
{
expr_t value(data_tree->One);
// if the expression is not on the left handside, change its sign
// if the expression is not on the left-hand side, change its sign
if (!svar_left_handside)
value = add_uminus(value);
......@@ -1271,9 +1376,10 @@ ParsingDriver::add_positive_restriction_element(const string &variable, const st
}
void
ParsingDriver::add_negative_restriction_element(expr_t value, const string &variable, const string &lag)
ParsingDriver::add_negative_restriction_element(expr_t value, const string& variable,
const string& lag)
{
// if the expression is on the left handside, change its sign
// if the expression is on the left-hand side, change its sign
if (svar_left_handside)
value = add_uminus(value);
......@@ -1285,7 +1391,7 @@ ParsingDriver::add_negative_restriction_element(const string &variable, const st
{
expr_t value(data_tree->One);
// if the expression is on the left handside, change its sign
// if the expression is on the left-hand side, change its sign
if (svar_left_handside)
value = add_uminus(value);
......@@ -1316,7 +1422,8 @@ ParsingDriver::add_restriction_element(expr_t value, const string &variable, con
{
if ((svar_restriction_type == SvarRestrictionType::Qi_TYPE && current_lag > 0)
|| (svar_restriction_type == SvarRestrictionType::Ri_TYPE && current_lag == 0))
error("SVAR_IDENTIFICATION: a single restrictions must affect either Qi or Ri, but not both");
error(
"SVAR_IDENTIFICATION: a single restrictions must affect either Qi or Ri, but not both");
}
SvarIdentificationStatement::svar_identification_restriction new_restriction;
new_restriction.equation = svar_equation_nbr;
......@@ -1423,7 +1530,9 @@ ParsingDriver::option_symbol_list(string name_option, vector<string> symbol_list
if (name_option == "ms.parameters")
for (auto& it : symbol_list)
if (mod_file->symbol_table.getType(it) != SymbolType::parameter)
error("Variables passed to the parameters option of the markov_switching statement must be parameters. Caused by: " + it);
error("Variables passed to the parameters option of the markov_switching statement must be "
"parameters. Caused by: "
+ it);
options_list.set(move(name_option), OptionsList::SymbolListVal {move(symbol_list)});
}
......@@ -1519,7 +1628,8 @@ ParsingDriver::trend_component_model()
{
try
{
mod_file->trend_component_model_table.addTrendComponentModel(options_list.get<OptionsList::StringVal>("trend_component.name"),
mod_file->trend_component_model_table.addTrendComponentModel(
options_list.get<OptionsList::StringVal>("trend_component.name"),
options_list.get<OptionsList::VecStrVal>("trend_component.eqtags"),
options_list.get<OptionsList::VecStrVal>("trend_component.targets"));
}
......@@ -1539,8 +1649,11 @@ ParsingDriver::var_model()
{
try
{
mod_file->var_model_table.addVarModel(options_list.get<OptionsList::StringVal>("var.model_name"),
options_list.get_if<OptionsList::NumVal>("var.structural").value_or(OptionsList::NumVal{"false"}) == "true",
mod_file->var_model_table.addVarModel(
options_list.get<OptionsList::StringVal>("var.model_name"),
options_list.get_if<OptionsList::NumVal>("var.structural")
.value_or(OptionsList::NumVal {"false"})
== "true",
options_list.get<OptionsList::VecStrVal>("var.eqtags"));
}
catch (OptionsList::UnknownOptionException& e)
......@@ -1553,7 +1666,8 @@ ParsingDriver::var_model()
void
ParsingDriver::simul()
{
warning("The 'simul' statement is deprecated. Please use 'perfect_foresight_setup' and 'perfect_foresight_solver' instead.");
warning("The 'simul' statement is deprecated. Please use 'perfect_foresight_setup' and "
"'perfect_foresight_solver' instead.");
mod_file->addStatement(make_unique<SimulStatement>(move(options_list)));
options_list.clear();
}
......@@ -1592,7 +1706,8 @@ ParsingDriver::add_estimated_params_element()
check_symbol_existence(estim_params.name2);
SymbolType type2 = mod_file->symbol_table.getType(estim_params.name2);
if ((type != SymbolType::endogenous && type != SymbolType::exogenous) || type != type2)
error(estim_params.name + " and " + estim_params.name2 + " must either be both endogenous variables or both exogenous");
error(estim_params.name + " and " + estim_params.name2
+ " must either be both endogenous variables or both exogenous");
break;
}
}
......@@ -1611,25 +1726,24 @@ ParsingDriver::estimated_params(bool overwrite)
void
ParsingDriver::estimated_params_init(bool use_calibration)
{
mod_file->addStatement(make_unique<EstimatedParamsInitStatement>(move(estim_params_list),
mod_file->symbol_table,
use_calibration));
mod_file->addStatement(make_unique<EstimatedParamsInitStatement>(
move(estim_params_list), mod_file->symbol_table, use_calibration));
estim_params_list.clear();
}
void
ParsingDriver::estimated_params_bounds()
{
mod_file->addStatement(make_unique<EstimatedParamsBoundsStatement>(move(estim_params_list),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<EstimatedParamsBoundsStatement>(move(estim_params_list), mod_file->symbol_table));
estim_params_list.clear();
}
void
ParsingDriver::estimated_params_remove()
{
mod_file->addStatement(make_unique<EstimatedParamsRemoveStatement>(move(estim_params_list),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<EstimatedParamsRemoveStatement>(move(estim_params_list), mod_file->symbol_table));
estim_params_list.clear();
}
......@@ -1655,15 +1769,14 @@ void
ParsingDriver::set_unit_root_vars()
{
mod_file->addStatement(make_unique<UnitRootVarsStatement>());
warning("''unit_root_vars'' is now obsolete; use the ''diffuse_filter'' option of ''estimation'' instead");
warning("''unit_root_vars'' is now obsolete; use the ''diffuse_filter'' option of ''estimation'' "
"instead");
}
void
ParsingDriver::set_time(const string &arg)
ParsingDriver::set_time(string period)
{
option_date("initial_period", arg);
mod_file->addStatement(make_unique<SetTimeStatement>(move(options_list)));
options_list.clear();
mod_file->addStatement(make_unique<SetTimeStatement>(move(period)));
}
void
......@@ -1687,7 +1800,8 @@ ParsingDriver::set_subsamples(string name1, string name2)
}
void
ParsingDriver::copy_subsamples(string to_name1, string to_name2, string from_name1, string from_name2)
ParsingDriver::copy_subsamples(string to_name1, string to_name2, string from_name1,
string from_name2)
{
check_symbol_existence(to_name1);
check_symbol_existence(from_name1);
......@@ -1704,8 +1818,8 @@ ParsingDriver::copy_subsamples(string to_name1, string to_name2, string from_nam
error(err + " does not have an associated subsample statement.");
}
mod_file->addStatement(make_unique<SubsamplesEqualStatement>(to_name1, to_name2, from_name1, from_name2,
mod_file->symbol_table));
mod_file->addStatement(make_unique<SubsamplesEqualStatement>(to_name1, to_name2, from_name1,
from_name2, mod_file->symbol_table));
subsample_declarations[{move(to_name1), move(to_name2)}]
= subsample_declarations[{move(from_name1), move(from_name2)}];
......@@ -1738,7 +1852,8 @@ ParsingDriver::check_subsample_declaration_exists(const string &name1, const str
}
void
ParsingDriver::check_subsample_declaration_exists(const string &name1, const string &name2, const string &subsample_name)
ParsingDriver::check_subsample_declaration_exists(const string& name1, const string& name2,
const string& subsample_name)
{
if (subsample_name.empty())
return;
......@@ -1762,7 +1877,8 @@ ParsingDriver::check_subsample_declaration_exists(const string &name1, const str
auto tmp_map = it->second;
if (!tmp_map.contains(subsample_name))
error("The subsample name " + subsample_name + " was not previously declared in a subsample statement.");
error("The subsample name " + subsample_name
+ " was not previously declared in a subsample statement.");
}
void
......@@ -1782,8 +1898,8 @@ ParsingDriver::set_joint_prior(const vector<string> &symbol_vec)
{
for (auto& it : symbol_vec)
add_joint_parameter(it);
mod_file->addStatement(make_unique<JointPriorStatement>(move(joint_parameters), prior_shape,
move(options_list)));
mod_file->addStatement(
make_unique<JointPriorStatement>(move(joint_parameters), prior_shape, move(options_list)));
joint_parameters.clear();
options_list.clear();
prior_shape = PriorDistributions::noShape;
......@@ -1803,9 +1919,8 @@ ParsingDriver::set_prior_variance(expr_t variance)
}
void
ParsingDriver::copy_prior(string to_declaration_type, string to_name1,
string to_name2, string to_subsample_name,
string from_declaration_type, string from_name1,
ParsingDriver::copy_prior(string to_declaration_type, string to_name1, string to_name2,
string to_subsample_name, string from_declaration_type, string from_name1,
string from_name2, string from_subsample_name)
{
if (to_declaration_type == "par")
......@@ -1826,10 +1941,9 @@ ParsingDriver::copy_prior(string to_declaration_type, string to_name1,
check_symbol_is_endogenous_or_exogenous(from_name2, false);
}
mod_file->addStatement(make_unique<PriorEqualStatement>(move(to_declaration_type), move(to_name1),
move(to_name2), move(to_subsample_name),
move(from_declaration_type), move(from_name1),
move(from_name2), move(from_subsample_name),
mod_file->addStatement(make_unique<PriorEqualStatement>(
move(to_declaration_type), move(to_name1), move(to_name2), move(to_subsample_name),
move(from_declaration_type), move(from_name1), move(from_name2), move(from_subsample_name),
mod_file->symbol_table));
}
......@@ -1838,16 +1952,15 @@ ParsingDriver::set_options(string name, string subsample_name)
{
check_symbol_is_parameter(name);
check_subsample_declaration_exists(name, subsample_name);
mod_file->addStatement(make_unique<OptionsStatement>(move(name), move(subsample_name),
move(options_list)));
mod_file->addStatement(
make_unique<OptionsStatement>(move(name), move(subsample_name), move(options_list)));
options_list.clear();
}
void
ParsingDriver::copy_options(string to_declaration_type, string to_name1,
string to_name2, string to_subsample_name,
string from_declaration_type, string from_name1,
string from_name2, string from_subsample_name)
ParsingDriver::copy_options(string to_declaration_type, string to_name1, string to_name2,
string to_subsample_name, string from_declaration_type,
string from_name1, string from_name2, string from_subsample_name)
{
if (to_declaration_type == "par")
check_symbol_is_parameter(to_name1);
......@@ -1867,10 +1980,9 @@ ParsingDriver::copy_options(string to_declaration_type, string to_name1,
check_symbol_is_endogenous_or_exogenous(from_name2, false);
}
mod_file->addStatement(make_unique<OptionsEqualStatement>(move(to_declaration_type), move(to_name1),
move(to_name2), move(to_subsample_name),
move(from_declaration_type), move(from_name1),
move(from_name2), move(from_subsample_name),
mod_file->addStatement(make_unique<OptionsEqualStatement>(
move(to_declaration_type), move(to_name1), move(to_name2), move(to_subsample_name),
move(from_declaration_type), move(from_name1), move(from_name2), move(from_subsample_name),
mod_file->symbol_table));
}
......@@ -1922,8 +2034,8 @@ ParsingDriver::set_std_prior(string name, string subsample_name)
{
check_symbol_is_endogenous_or_exogenous(name, false);
check_subsample_declaration_exists(name, subsample_name);
mod_file->addStatement(make_unique<StdPriorStatement>(move(name), move(subsample_name),
prior_shape, prior_variance,
mod_file->addStatement(
make_unique<StdPriorStatement>(move(name), move(subsample_name), prior_shape, prior_variance,
move(options_list), mod_file->symbol_table));
options_list.clear();
set_prior_variance();
......@@ -1935,8 +2047,8 @@ ParsingDriver::set_std_options(string name, string subsample_name)
{
check_symbol_is_endogenous_or_exogenous(name, false);
check_subsample_declaration_exists(name, subsample_name);
mod_file->addStatement(make_unique<StdOptionsStatement>(move(name), move(subsample_name),
move(options_list), mod_file->symbol_table));
mod_file->addStatement(make_unique<StdOptionsStatement>(
move(name), move(subsample_name), move(options_list), mod_file->symbol_table));
options_list.clear();
}
......@@ -1946,9 +2058,9 @@ ParsingDriver::set_corr_prior(string name1, string name2, string subsample_name)
check_symbol_is_endogenous_or_exogenous(name1, false);
check_symbol_is_endogenous_or_exogenous(name2, false);
check_subsample_declaration_exists(name1, name2, subsample_name);
mod_file->addStatement(make_unique<CorrPriorStatement>(move(name1), move(name2),
move(subsample_name), prior_shape, prior_variance,
move(options_list), mod_file->symbol_table));
mod_file->addStatement(
make_unique<CorrPriorStatement>(move(name1), move(name2), move(subsample_name), prior_shape,
prior_variance, move(options_list), mod_file->symbol_table));
options_list.clear();
set_prior_variance();
prior_shape = PriorDistributions::noShape;
......@@ -1960,9 +2072,8 @@ ParsingDriver::set_corr_options(string name1, string name2, string subsample_nam
check_symbol_is_endogenous_or_exogenous(name1, false);
check_symbol_is_endogenous_or_exogenous(name2, false);
check_subsample_declaration_exists(name1, name2, subsample_name);
mod_file->addStatement(make_unique<CorrOptionsStatement>(move(name1), move(name2),
move(subsample_name), move(options_list),
mod_file->symbol_table));
mod_file->addStatement(make_unique<CorrOptionsStatement>(
move(name1), move(name2), move(subsample_name), move(options_list), mod_file->symbol_table));
options_list.clear();
}
......@@ -1975,9 +2086,9 @@ ParsingDriver::run_estimation(vector<string> symbol_list)
}
void
ParsingDriver::dynare_sensitivity()
ParsingDriver::sensitivity()
{
mod_file->addStatement(make_unique<DynareSensitivityStatement>(move(options_list)));
mod_file->addStatement(make_unique<SensitivityStatement>(move(options_list)));
options_list.clear();
}
......@@ -2016,16 +2127,16 @@ ParsingDriver::add_varexobs(const string &name)
void
ParsingDriver::set_trends()
{
mod_file->addStatement(make_unique<ObservationTrendsStatement>(move(trend_elements),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<ObservationTrendsStatement>(move(trend_elements), mod_file->symbol_table));
trend_elements.clear();
}
void
ParsingDriver::set_deterministic_trends()
{
mod_file->addStatement(make_unique<DeterministicTrendsStatement>(move(trend_elements),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<DeterministicTrendsStatement>(move(trend_elements), mod_file->symbol_table));
trend_elements.clear();
}
......@@ -2041,8 +2152,8 @@ ParsingDriver::set_trend_element(string arg1, expr_t arg2)
void
ParsingDriver::set_filter_initial_state()
{
mod_file->addStatement(make_unique<FilterInitialStateStatement>(move(filter_initial_state_elements),
mod_file->symbol_table));
mod_file->addStatement(make_unique<FilterInitialStateStatement>(
move(filter_initial_state_elements), mod_file->symbol_table));
filter_initial_state_elements.clear();
}
......@@ -2054,8 +2165,7 @@ ParsingDriver::set_filter_initial_state_element(const string &name, const string
SymbolType type = mod_file->symbol_table.getType(symb_id);
int ilag = stoi(lag);
if (type != SymbolType::endogenous
&& type != SymbolType::exogenous
if (type != SymbolType::endogenous && type != SymbolType::exogenous
&& type != SymbolType::exogenousDet)
error("filter_initial_state: " + name + " should be an endogenous or exogenous variable");
......@@ -2066,7 +2176,9 @@ ParsingDriver::set_filter_initial_state_element(const string &name, const string
error("filter_initial_state: (" + name + ", " + lag + ") declared twice");
if (mod_file->dynamic_model.minLagForSymbol(symb_id) > ilag - 1)
error("filter_initial_state: variable " + name + " does not appear in the model with the lag " + to_string(ilag-1) + " (see the reference manual for the timing convention in 'filter_initial_state')");
error("filter_initial_state: variable " + name + " does not appear in the model with the lag "
+ to_string(ilag - 1)
+ " (see the reference manual for the timing convention in 'filter_initial_state')");
filter_initial_state_elements[{symb_id, ilag}] = rhs;
}
......@@ -2077,7 +2189,7 @@ ParsingDriver::set_optim_weights(string name, expr_t value)
check_symbol_is_endogenous(name);
if (var_weights.contains(name))
error("optim_weights: " + name + " declared twice");
var_weights[move(name)] = move(value);
var_weights[move(name)] = value;
}
void
......@@ -2089,8 +2201,7 @@ ParsingDriver::set_optim_weights(const string &name1, const string &name2, expr_
pair covar_key {name1, name2};
if (covar_weights.contains(covar_key))
error("optim_weights: pair of variables (" + name1 + ", " + name2
+ ") declared twice");
error("optim_weights: pair of variables (" + name1 + ", " + name2 + ") declared twice");
covar_weights[covar_key] = value;
}
......@@ -2107,35 +2218,37 @@ ParsingDriver::optim_weights()
void
ParsingDriver::set_osr_params(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<OsrParamsStatement>(move(symbol_list), mod_file->symbol_table));
mod_file->addStatement(
make_unique<OsrParamsStatement>(move(symbol_list), mod_file->symbol_table));
}
void
ParsingDriver::run_osr(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<OsrStatement>(move(symbol_list), move(options_list),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<OsrStatement>(move(symbol_list), move(options_list), mod_file->symbol_table));
options_list.clear();
}
void
ParsingDriver::run_dynatype(string filename, vector<string> symbol_list)
{
mod_file->addStatement(make_unique<DynaTypeStatement>(move(symbol_list), move(filename),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<DynaTypeStatement>(move(symbol_list), move(filename), mod_file->symbol_table));
}
void
ParsingDriver::run_dynasave(string filename, vector<string> symbol_list)
{
mod_file->addStatement(make_unique<DynaSaveStatement>(move(symbol_list), move(filename),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<DynaSaveStatement>(move(symbol_list), move(filename), mod_file->symbol_table));
}
void
ParsingDriver::run_load_params_and_steady_state(const string& filename)
{
mod_file->addStatement(make_unique<LoadParamsAndSteadyStateStatement>(filename, mod_file->symbol_table, warnings));
mod_file->addStatement(
make_unique<LoadParamsAndSteadyStateStatement>(filename, mod_file->symbol_table, warnings));
}
void
......@@ -2163,8 +2276,8 @@ ParsingDriver::add_mc_filename(string filename, string prior)
void
ParsingDriver::run_model_comparison()
{
mod_file->addStatement(make_unique<ModelComparisonStatement>(move(filename_list),
move(options_list)));
mod_file->addStatement(
make_unique<ModelComparisonStatement>(move(filename_list), move(options_list)));
filename_list.clear();
options_list.clear();
}
......@@ -2172,9 +2285,9 @@ ParsingDriver::run_model_comparison()
void
ParsingDriver::begin_planner_objective()
{
planner_objective = make_unique<PlannerObjective>(mod_file->symbol_table,
mod_file->num_constants,
mod_file->external_functions_table);
planner_objective = make_unique<PlannerObjective>(mod_file->symbol_table, mod_file->num_constants,
mod_file->external_functions_table,
mod_file->heterogeneity_table);
set_current_data_tree(planner_objective.get());
}
......@@ -2185,7 +2298,7 @@ ParsingDriver::end_planner_objective(expr_t expr)
expr_t eq = model_tree->AddEqual(expr, model_tree->Zero);
model_tree->addEquation(eq, location.begin.line);
mod_file->addStatement(make_unique<PlannerObjectiveStatement>(*planner_objective));
mod_file->addStatement(make_unique<PlannerObjectiveStatement>(move(planner_objective)));
// Handle undeclared variables (see #81)
bool exit_after_write = false;
......@@ -2225,7 +2338,8 @@ ParsingDriver::ramsey_model()
init_param("optimal_policy_discount_factor", planner_discount);
}
else if (planner_discount)
error("ramsey_model: the 'planner_discount' option cannot be used when the 'optimal_policy_discount_factor' parameter is explicitly declared.");
error("ramsey_model: the 'planner_discount' option cannot be used when the "
"'optimal_policy_discount_factor' parameter is explicitly declared.");
// Check that instruments are declared endogenous (#72)
if (options_list.contains("instruments"))
......@@ -2241,7 +2355,8 @@ ParsingDriver::ramsey_model()
void
ParsingDriver::ramsey_policy(vector<string> symbol_list)
{
warning("The 'ramsey_policy' statement is deprecated. Please use 'ramsey_model', 'stoch_simul', and 'evaluate_planner_objective' instead.");
warning("The 'ramsey_policy' statement is deprecated. Please use 'ramsey_model', 'stoch_simul', "
"and 'evaluate_planner_objective' instead.");
// Some checks to ensure correct error messages (see #90)
if (ramsey_model_seen)
......@@ -2258,7 +2373,8 @@ ParsingDriver::ramsey_policy(vector<string> symbol_list)
init_param("optimal_policy_discount_factor", planner_discount);
}
else if (planner_discount)
error("ramsey_policy: the 'planner_discount' option cannot be used when the 'optimal_policy_discount_factor' parameter is explicitly declared.");
error("ramsey_policy: the 'planner_discount' option cannot be used when the "
"'optimal_policy_discount_factor' parameter is explicitly declared.");
// Check that instruments are declared endogenous (#72)
if (options_list.contains("instruments"))
......@@ -2324,9 +2440,8 @@ ParsingDriver::discretionary_policy(vector<string> symbol_list)
for (const auto& s : options_list.get<OptionsList::SymbolListVal>("instruments").getSymbols())
check_symbol_is_endogenous(s);
mod_file->addStatement(make_unique<DiscretionaryPolicyStatement>(move(symbol_list),
move(options_list),
mod_file->symbol_table));
mod_file->addStatement(make_unique<DiscretionaryPolicyStatement>(
move(symbol_list), move(options_list), mod_file->symbol_table));
options_list.clear();
planner_discount = nullptr;
}
......@@ -2334,25 +2449,29 @@ ParsingDriver::discretionary_policy(vector<string> symbol_list)
void
ParsingDriver::write_latex_dynamic_model(bool write_equation_tags)
{
mod_file->addStatement(make_unique<WriteLatexDynamicModelStatement>(mod_file->dynamic_model, write_equation_tags));
mod_file->addStatement(
make_unique<WriteLatexDynamicModelStatement>(mod_file->dynamic_model, write_equation_tags));
}
void
ParsingDriver::write_latex_static_model(bool write_equation_tags)
{
mod_file->addStatement(make_unique<WriteLatexStaticModelStatement>(mod_file->static_model, write_equation_tags));
mod_file->addStatement(
make_unique<WriteLatexStaticModelStatement>(mod_file->static_model, write_equation_tags));
}
void
ParsingDriver::write_latex_original_model(bool write_equation_tags)
{
mod_file->addStatement(make_unique<WriteLatexOriginalModelStatement>(mod_file->original_model, write_equation_tags));
mod_file->addStatement(
make_unique<WriteLatexOriginalModelStatement>(mod_file->original_model, write_equation_tags));
}
void
ParsingDriver::write_latex_steady_state_model()
{
mod_file->addStatement(make_unique<WriteLatexSteadyStateModelStatement>(mod_file->steady_state_model));
mod_file->addStatement(
make_unique<WriteLatexSteadyStateModelStatement>(mod_file->steady_state_model));
}
void
......@@ -2477,7 +2596,8 @@ ParsingDriver::markov_switching()
}
catch (OptionsList::UnknownOptionException& e)
{
error("A '" + e.name.substr(3) + "' option must be passed to the 'markov_switching' statement.");
error("A '" + e.name.substr(3)
+ "' option must be passed to the 'markov_switching' statement.");
}
mod_file->addStatement(make_unique<MarkovSwitchingStatement>(move(options_list)));
......@@ -2487,44 +2607,40 @@ ParsingDriver::markov_switching()
void
ParsingDriver::shock_decomposition(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<ShockDecompositionStatement>(move(symbol_list),
move(options_list),
mod_file->symbol_table));
mod_file->addStatement(make_unique<ShockDecompositionStatement>(
move(symbol_list), move(options_list), mod_file->symbol_table));
options_list.clear();
}
void
ParsingDriver::realtime_shock_decomposition(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<RealtimeShockDecompositionStatement>(move(symbol_list),
move(options_list),
mod_file->symbol_table));
mod_file->addStatement(make_unique<RealtimeShockDecompositionStatement>(
move(symbol_list), move(options_list), mod_file->symbol_table));
options_list.clear();
}
void
ParsingDriver::plot_shock_decomposition(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<PlotShockDecompositionStatement>(move(symbol_list),
move(options_list),
mod_file->symbol_table));
mod_file->addStatement(make_unique<PlotShockDecompositionStatement>(
move(symbol_list), move(options_list), mod_file->symbol_table));
options_list.clear();
}
void
ParsingDriver::initial_condition_decomposition(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<InitialConditionDecompositionStatement>(move(symbol_list),
move(options_list),
mod_file->symbol_table));
mod_file->addStatement(make_unique<InitialConditionDecompositionStatement>(
move(symbol_list), move(options_list), mod_file->symbol_table));
options_list.clear();
}
void
ParsingDriver::squeeze_shock_decomposition(vector<string> symbol_list)
{
mod_file->addStatement(make_unique<SqueezeShockDecompositionStatement>(move(symbol_list),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<SqueezeShockDecompositionStatement>(move(symbol_list), mod_file->symbol_table));
}
void
......@@ -2535,20 +2651,26 @@ ParsingDriver::conditional_forecast()
}
void
ParsingDriver::plot_conditional_forecast(const optional<string> &periods, vector<string> symbol_list)
ParsingDriver::plot_conditional_forecast(const optional<string>& periods,
vector<string> symbol_list)
{
optional<int> iperiods;
if (periods)
iperiods = stoi(*periods);
mod_file->addStatement(make_unique<PlotConditionalForecastStatement>(move(iperiods), move(symbol_list),
mod_file->addStatement(make_unique<PlotConditionalForecastStatement>(iperiods, move(symbol_list),
mod_file->symbol_table));
}
void
ParsingDriver::conditional_forecast_paths()
{
mod_file->addStatement(make_unique<ConditionalForecastPathsStatement>(move(det_shocks),
mod_file->symbol_table));
if (ranges::any_of(views::values(det_shocks), [](auto& v) {
return ranges::any_of(views::keys(v),
[](auto& p) { return !holds_alternative<pair<int, int>>(p); });
}))
error("conditional_forecast_paths: dates are not allowed in the 'periods' keyword");
mod_file->addStatement(
make_unique<ConditionalForecastPathsStatement>(move(det_shocks), mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("conditional_forecast_paths: 'add' keyword not allowed");
......@@ -2572,7 +2694,8 @@ ParsingDriver::extended_path()
}
expr_t
ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags)
ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags,
expr_t complementarity_condition)
{
expr_t id = model_tree->AddEqual(arg1, arg2);
......@@ -2580,61 +2703,179 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_
if (key == "endogenous")
declare_or_change_type(SymbolType::endogenous, value);
optional<tuple<int, expr_t, expr_t>> matched_complementarity_condition;
// Handle legacy “mcp” tags, for backward compatibility
if (eq_tags.contains("mcp"))
{
if (complementarity_condition)
error("Can't have both an 'mcp' tag and a complementarity condition after the "
"perpendicular symbol");
else
warning("Specifying complementarity conditions with the 'mcp' tag is obsolete. Please "
"consider switching to the new syntax using the perpendicular symbol.");
auto [var_name, is_lower_bound, constant] {[&]() -> tuple<string, bool, string> {
auto tagval = eq_tags.at("mcp");
if (auto less_pos = tagval.find('<'); less_pos != string::npos)
return {tagval.substr(0, less_pos), false, tagval.substr(less_pos + 1)};
else if (auto greater_pos = tagval.find('>'); greater_pos != string::npos)
return {tagval.substr(0, greater_pos), true, tagval.substr(greater_pos + 1)};
else
error("'mcp' tag does not contain an inequality");
}()};
// Trim whitespace
var_name.erase(var_name.find_last_not_of(" \n\t") + 1);
var_name.erase(0, var_name.find_first_not_of(" \n\t"));
constant.erase(constant.find_last_not_of(" \n\t") + 1);
constant.erase(0, constant.find_first_not_of(" \n\t"));
int symb_id {[&] {
try
{
return mod_file->symbol_table.getID(var_name);
}
catch (SymbolTable::UnknownSymbolNameException&)
{
error("Left-hand side of expression in 'mcp' tag is not a variable");
}
}()};
if (heterogeneous_model)
error("'mcp' tags are not allowed in heterogeneous model blocks");
if (mod_file->symbol_table.getType(symb_id) != SymbolType::endogenous)
error("Left-hand side of expression in 'mcp' tag is not an endogenous variable");
expr_t matched_constant {[&] {
char* str_end;
double d = strtod(constant.c_str(), &str_end);
if (str_end == constant.c_str())
error("Right-hand side of expression in 'mcp' tag should be a constant");
return data_tree->AddPossiblyNegativeConstant(d);
}()};
matched_complementarity_condition = {symb_id, is_lower_bound ? matched_constant : nullptr,
is_lower_bound ? nullptr : matched_constant};
}
if (complementarity_condition)
try
{
matched_complementarity_condition
= heterogeneous_model ? complementarity_condition->matchComplementarityCondition(
heterogeneous_model->heterogeneity_dimension)
: complementarity_condition->matchComplementarityCondition();
}
catch (ExprNode::MatchFailureException& e)
{
error("Complementarity condition has an incorrect form"s
+ (e.message.empty() ? ""s : ": "s + e.message));
}
if (eq_tags.contains("static"))
{
// If the equation is tagged [static]
if (!id->isInStaticForm())
error("An equation tagged [static] cannot contain leads, lags, expectations or STEADY_STATE operators");
error("An equation tagged [static] cannot contain leads, lags, expectations or "
"STEADY_STATE operators");
dynamic_model->addStaticOnlyEquation(id, location.begin.line, eq_tags);
dynamic_model->addStaticOnlyEquation(id, location.begin.line,
move(matched_complementarity_condition), eq_tags);
}
else if (eq_tags.contains("bind") || eq_tags.contains("relax"))
{
// If the equation has a “bind” or “relax” tag (occbin case)
if (!eq_tags.contains("name"))
error("An equation with a 'bind' or 'relax' tag must have a 'name' tag");
auto regimes_bind = DataTree::strsplit(eq_tags["bind"], ',');
auto regimes_relax = DataTree::strsplit(eq_tags["relax"], ',');
auto regimes_all = regimes_bind;
regimes_all.insert(regimes_all.end(), regimes_relax.begin(), regimes_relax.end()); // Concatenate the two vectors
for (const auto &regime : regimes_all)
{
if (!isSymbolIdentifier(regime))
error("The string '" + regime + "' is not a valid Occbin regime name (contains unauthorized characters)");
string param_name = buildOccbinBindParamName(regime);
auto constraints_bind = DataTree::strsplit(eq_tags["bind"], ',');
auto constraints_relax = DataTree::strsplit(eq_tags["relax"], ',');
auto constraints_all = constraints_bind;
constraints_all.insert(constraints_all.end(), constraints_relax.begin(),
constraints_relax.end()); // Concatenate the two vectors
for (const auto& constraint : constraints_all)
{
if (!isSymbolIdentifier(constraint))
error("The string '" + constraint
+ "' is not a valid Occbin constraint name (contains unauthorized characters)");
string param_name = buildOccbinBindParamName(constraint);
try
{
if (mod_file->symbol_table.getType(param_name) != SymbolType::parameter)
error("The name '" + param_name + "' is already used. Please use another name for Occbin regime '" + regime + "'");
error("The name '" + param_name
+ "' is already used. Please use another name for Occbin constraint '"
+ constraint + "'");
}
catch (SymbolTable::UnknownSymbolNameException& e)
{
// Declare and initialize the new parameter
int symb_id = mod_file->symbol_table.addSymbol(param_name, SymbolType::parameter);
mod_file->addStatement(make_unique<InitParamStatement>(symb_id, dynamic_model->Zero, mod_file->symbol_table));
mod_file->addStatement(make_unique<InitParamStatement>(symb_id, dynamic_model->Zero,
mod_file->symbol_table));
}
}
eq_tags.erase("bind");
eq_tags.erase("relax");
dynamic_model->addOccbinEquation(id, location.begin.line, move(eq_tags), regimes_bind, regimes_relax);
try
{
dynamic_model->addOccbinEquation(id, location.begin.line, move(eq_tags), constraints_bind,
constraints_relax);
}
catch (DynamicModel::OccbinRegimeTracker::ConstraintInBothBindAndRelaxException& e)
{
error("The constraint '" + e.constraint + "' is both in the 'bind' and 'relax' tags");
}
catch (DynamicModel::OccbinRegimeTracker::RegimeAlreadyPresentException& e)
{
stringstream s;
if (!e.constraints_bind.empty())
{
s << "bind='";
for (bool first_printed {false}; const auto& c : e.constraints_bind)
{
if (exchange(first_printed, true))
s << ",";
s << c;
}
}
if (!e.constraints_bind.empty() && !e.constraints_relax.empty())
s << "' and ";
if (!e.constraints_relax.empty())
{
s << "relax='";
for (bool first_printed {false}; const auto& c : e.constraints_relax)
{
if (exchange(first_printed, true))
s << ",";
s << c;
}
}
s << "'";
error("The regime corresponding to " + s.str()
+ " has already been declared for this equation");
}
}
else // General case
model_tree->addEquation(id, location.begin.line, move(eq_tags));
model_tree->addEquation(id, location.begin.line, move(matched_complementarity_condition),
move(eq_tags));
return id;
}
expr_t
ParsingDriver::add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags)
ParsingDriver::add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags,
expr_t complementarity_condition)
{
return add_model_equal(arg, model_tree->Zero, move(eq_tags));
return add_model_equal(arg, model_tree->Zero, move(eq_tags), complementarity_condition);
}
void
ParsingDriver::model_local_variable(const vector<pair<string, string>>& symbol_list)
{
for (auto& [name, tex_name] : symbol_list)
declare_symbol(name, SymbolType::modelLocalVariable, tex_name, {});
declare_symbol(name, SymbolType::modelLocalVariable, tex_name, {}, {});
}
void
......@@ -2652,7 +2893,9 @@ ParsingDriver::declare_and_init_model_local_variable(const string &name, expr_t
ModelLocalVariable */
symb_id = mod_file->symbol_table.getID(name);
if (mod_file->symbol_table.getType(symb_id) != SymbolType::modelLocalVariable)
error(name + " has wrong type or was already used on the right-hand side. You cannot use it on the left-hand side of a pound ('#') expression");
error(name
+ " has wrong type or was already used on the right-hand side. You cannot use it on "
"the left-hand side of a pound ('#') expression");
}
try
......@@ -2681,9 +2924,9 @@ ParsingDriver::change_type(SymbolType new_type, const vector<string> &symbol_lis
}
// Check if symbol already used in a VariableNode
if (mod_file->expressions_tree.isSymbolUsed(id)
|| mod_file->dynamic_model.isSymbolUsed(id))
error("You cannot modify the type of symbol " + it + " after having used it in an expression");
if (mod_file->expressions_tree.isSymbolUsed(id) || mod_file->dynamic_model.isSymbolUsed(id))
error("You cannot modify the type of symbol " + it
+ " after having used it in an expression");
mod_file->symbol_table.changeType(id, new_type);
}
......@@ -2820,10 +3063,11 @@ ParsingDriver::pac_model()
{
auto discount {options_list.get<OptionsList::StringVal>("pac.discount")};
check_symbol_is_parameter(discount);
mod_file->pac_model_table.addPacModel(options_list.get<OptionsList::StringVal>("pac.model_name"),
options_list.get_if<OptionsList::StringVal>("pac.aux_model_name").value_or(OptionsList::StringVal{}),
move(discount), pac_growth,
pac_auxname, pac_kind);
mod_file->pac_model_table.addPacModel(
options_list.get<OptionsList::StringVal>("pac.model_name"),
options_list.get_if<OptionsList::StringVal>("pac.aux_model_name")
.value_or(OptionsList::StringVal {}),
move(discount), pac_growth, pac_auxname, pac_kind);
}
catch (OptionsList::UnknownOptionException& e)
{
......@@ -2868,9 +3112,8 @@ ParsingDriver::add_diff(expr_t arg1)
expr_t
ParsingDriver::add_adl(expr_t arg1, const string& name, const string& lag)
{
vector<int> lags(stoi(lag));
iota(lags.begin(), lags.end(), 1);
return add_adl(arg1, name, lags);
auto lags = views::iota(1, stoi(lag) + 1);
return add_adl(arg1, name, vector<int> {lags.begin(), lags.end()});
}
expr_t
......@@ -3051,40 +3294,61 @@ ParsingDriver::add_steady_state(expr_t arg1)
return data_tree->AddSteadyState(arg1);
}
expr_t
ParsingDriver::add_sum(expr_t arg)
{
if (heterogeneous_model)
error("The SUM() operator cannot be used inside a model(heterogeneity=...) block");
VariableNode* varg {dynamic_cast<VariableNode*>(arg)};
if (!varg)
error("The argument to the SUM() operator must be a single variable");
if (varg->lag != 0)
error("The argument to the SUM() operator must not have a lead or lag");
if (mod_file->symbol_table.getType(varg->symb_id) != SymbolType::heterogeneousEndogenous)
error("The argument to the SUM() operator must be a heterogeneous endogenous variable");
return data_tree->AddSum(arg);
}
void
ParsingDriver::external_function_option(const string& name_option, const string& opt)
{
if (name_option == "name")
{
if (opt.empty())
error("An argument must be passed to the 'name' option of the external_function() statement.");
declare_symbol(opt, SymbolType::externalFunction, "", {});
error("An argument must be passed to the 'name' option of the external_function() "
"statement.");
declare_symbol(opt, SymbolType::externalFunction, "", {}, {});
current_external_function_id = mod_file->symbol_table.getID(opt);
}
else if (name_option == "first_deriv_provided")
{
if (opt.empty())
current_external_function_options.firstDerivSymbID = ExternalFunctionsTable::IDSetButNoNameProvided;
current_external_function_options.firstDerivSymbID
= ExternalFunctionsTable::IDSetButNoNameProvided;
else
{
int symb_id = declare_symbol(opt, SymbolType::externalFunction, "", {});
int symb_id = declare_symbol(opt, SymbolType::externalFunction, "", {}, {});
current_external_function_options.firstDerivSymbID = symb_id;
}
}
else if (name_option == "second_deriv_provided")
{
if (opt.empty())
current_external_function_options.secondDerivSymbID = ExternalFunctionsTable::IDSetButNoNameProvided;
current_external_function_options.secondDerivSymbID
= ExternalFunctionsTable::IDSetButNoNameProvided;
else
{
int symb_id = declare_symbol(opt, SymbolType::externalFunction, "", {});
int symb_id = declare_symbol(opt, SymbolType::externalFunction, "", {}, {});
current_external_function_options.secondDerivSymbID = symb_id;
}
}
else if (name_option == "nargs")
current_external_function_options.nargs = stoi(opt);
else
error("Unexpected error in ParsingDriver::external_function_option(): Please inform Dynare Team.");
error("Unexpected error in ParsingDriver::external_function_option(): Please inform Dynare "
"Team.");
}
void
......@@ -3095,20 +3359,25 @@ ParsingDriver::external_function()
if (current_external_function_options.secondDerivSymbID >= 0
&& current_external_function_options.firstDerivSymbID == ExternalFunctionsTable::IDNotSet)
error("If the second derivative is provided to the external_function command, the first derivative must also be provided.");
if (current_external_function_options.secondDerivSymbID == ExternalFunctionsTable::IDSetButNoNameProvided
&& current_external_function_options.firstDerivSymbID != ExternalFunctionsTable::IDSetButNoNameProvided)
error("If the second derivative is provided in the top-level function, the first derivative must also be provided in that function.");
mod_file->external_functions_table.addExternalFunction(current_external_function_id, current_external_function_options, true);
error("If the second derivative is provided to the external_function command, the first "
"derivative must also be provided.");
if (current_external_function_options.secondDerivSymbID
== ExternalFunctionsTable::IDSetButNoNameProvided
&& current_external_function_options.firstDerivSymbID
!= ExternalFunctionsTable::IDSetButNoNameProvided)
error("If the second derivative is provided in the top-level function, the first derivative "
"must also be provided in that function.");
mod_file->external_functions_table.addExternalFunction(current_external_function_id,
current_external_function_options, true);
reset_current_external_function_options();
}
void
ParsingDriver::push_external_function_arg_vector_onto_stack()
{
stack_external_function_args.push({});
stack_external_function_args.emplace();
}
void
......@@ -3142,8 +3411,7 @@ ParsingDriver::is_there_one_integer_argument() const
return nullopt;
}
}
else
if (unaryNode->op_code != UnaryOpcode::uminus)
else if (unaryNode->op_code != UnaryOpcode::uminus)
return nullopt;
else
{
......@@ -3182,27 +3450,34 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b
optional<int> rv {is_there_one_integer_argument()};
if (!rv)
model_error("Symbol " + function_name
+" is being treated as if it were a function (i.e., takes an argument that is not an integer).", "");
error("Symbol " + function_name
+ " is being treated as if it were a function (i.e., takes an argument that is "
"not an integer).");
nid = add_model_variable(mod_file->symbol_table.getID(function_name), *rv);
stack_external_function_args.pop();
return nid;
}
else
{ // e.g. this function has already been referenced (either ad hoc or through the external_function() statement
{ // e.g. this function has already been referenced (either ad hoc or through the
// external_function() statement
// => check that the information matches previously declared info
int symb_id = mod_file->symbol_table.getID(function_name);
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.");
error("Using a derivative of an external function (" + function_name
+ ") in the model block is currently not allowed.");
if (in_model_block || parsing_epilogue)
{
if (mod_file->external_functions_table.getNargs(symb_id) == ExternalFunctionsTable::IDNotSet)
if (mod_file->external_functions_table.getNargs(symb_id)
== ExternalFunctionsTable::IDNotSet)
error("Before using " + function_name
+"() in the model block, you must first declare it via the external_function() statement");
else if (static_cast<int>(stack_external_function_args.top().size()) != mod_file->external_functions_table.getNargs(symb_id))
error("The number of arguments passed to " + function_name
+ "() in the model block, you must first declare it via the "
"external_function() statement");
else if (static_cast<int>(stack_external_function_args.top().size())
!= mod_file->external_functions_table.getNargs(symb_id))
error(
"The number of arguments passed to " + function_name
+ "() does not match those of a previous call or declaration of this function.");
}
}
......@@ -3227,16 +3502,18 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b
}
else
error("To use an external function (" + function_name
+") within the model block, you must first declare it via the external_function() statement.");
+ ") within the model block, you must first declare it via the "
"external_function() statement.");
}
int symb_id = declare_symbol(function_name, SymbolType::externalFunction, "", {});
int symb_id = declare_symbol(function_name, SymbolType::externalFunction, "", {}, {});
current_external_function_options.nargs = stack_external_function_args.top().size();
mod_file->external_functions_table.addExternalFunction(symb_id,
current_external_function_options, in_model_block);
mod_file->external_functions_table.addExternalFunction(
symb_id, current_external_function_options, in_model_block);
reset_current_external_function_options();
}
//By this point, we're sure that this function exists in the External Functions Table and is not a mod var
// By this point, we're sure that this function exists in the External Functions Table and is not
// a mod var
int symb_id = mod_file->symbol_table.getID(function_name);
nid = data_tree->AddExternalFunction(symb_id, stack_external_function_args.top());
stack_external_function_args.pop();
......@@ -3292,7 +3569,8 @@ ParsingDriver::add_steady_state_model_equal(const string &varname, expr_t expr)
}
if (SymbolType type = mod_file->symbol_table.getType(id);
type != SymbolType::endogenous && type != SymbolType::modFileLocalVariable && type != SymbolType::parameter)
type != SymbolType::endogenous && type != SymbolType::modFileLocalVariable
&& type != SymbolType::parameter)
error(varname + " has incorrect type");
mod_file->steady_state_model.addDefinition(id, expr);
......@@ -3316,7 +3594,8 @@ ParsingDriver::add_steady_state_model_equal_multiple(const vector<string> &symbo
id = mod_file->symbol_table.addSymbol(symb, SymbolType::modFileLocalVariable);
}
if (SymbolType type = mod_file->symbol_table.getType(id);
type != SymbolType::endogenous && type != SymbolType::modFileLocalVariable && type != SymbolType::parameter)
type != SymbolType::endogenous && type != SymbolType::modFileLocalVariable
&& type != SymbolType::parameter)
error(symb + " has incorrect type");
ids.push_back(id);
}
......@@ -3340,14 +3619,16 @@ ParsingDriver::process_graph_format_option()
void
ParsingDriver::initial_condition_decomp_process_graph_format_option()
{
options_list.set("initial_condition_decomp.graph_format", OptionsList::SymbolListVal{move(graph_formats)});
options_list.set("initial_condition_decomp.graph_format",
OptionsList::SymbolListVal {move(graph_formats)});
graph_formats.clear();
}
void
ParsingDriver::plot_shock_decomp_process_graph_format_option()
{
options_list.set("plot_shock_decomp.graph_format", OptionsList::SymbolListVal{move(graph_formats)});
options_list.set("plot_shock_decomp.graph_format",
OptionsList::SymbolListVal {move(graph_formats)});
graph_formats.clear();
}
......@@ -3364,7 +3645,8 @@ ParsingDriver::add_parallel_local_file(string filename)
}
void
ParsingDriver::add_moment_calibration_item(const string &endo1, const string &endo2, string lags, const pair<expr_t, expr_t> &range)
ParsingDriver::add_moment_calibration_item(const string& endo1, const string& endo2, string lags,
const pair<expr_t, expr_t>& range)
{
MomentCalibration::Constraint c;
......@@ -3385,13 +3667,14 @@ ParsingDriver::add_moment_calibration_item(const string &endo1, const string &en
void
ParsingDriver::end_moment_calibration()
{
mod_file->addStatement(make_unique<MomentCalibration>(move(moment_calibration_constraints),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<MomentCalibration>(move(moment_calibration_constraints), mod_file->symbol_table));
moment_calibration_constraints.clear();
}
void
ParsingDriver::add_irf_calibration_item(const string &endo, string periods, const string &exo, const pair<expr_t, expr_t> &range)
ParsingDriver::add_irf_calibration_item(const string& endo, string periods, const string& exo,
const pair<expr_t, expr_t>& range)
{
IrfCalibration::Constraint c;
......@@ -3415,8 +3698,7 @@ void
ParsingDriver::end_irf_calibration()
{
mod_file->addStatement(make_unique<IrfCalibration>(move(irf_calibration_constraints),
mod_file->symbol_table,
move(options_list)));
mod_file->symbol_table, move(options_list)));
irf_calibration_constraints.clear();
options_list.clear();
}
......@@ -3452,17 +3734,42 @@ ParsingDriver::perfect_foresight_solver()
void
ParsingDriver::perfect_foresight_with_expectation_errors_setup()
{
mod_file->addStatement(make_unique<PerfectForesightWithExpectationErrorsSetupStatement>(move(options_list)));
mod_file->addStatement(
make_unique<PerfectForesightWithExpectationErrorsSetupStatement>(move(options_list)));
options_list.clear();
}
void
ParsingDriver::perfect_foresight_with_expectation_errors_solver()
{
mod_file->addStatement(make_unique<PerfectForesightWithExpectationErrorsSolverStatement>(move(options_list)));
mod_file->addStatement(
make_unique<PerfectForesightWithExpectationErrorsSolverStatement>(move(options_list)));
options_list.clear();
}
void
ParsingDriver::perfect_foresight_controlled_paths(
const vector<tuple<string, vector<AbstractShocksStatement::period_range_t>, vector<expr_t>,
string>>& paths,
variant<int, string> learnt_in_period)
{
PerfectForesightControlledPathsStatement::paths_t paths_transformed;
for (const auto& [exogenize, periods, values, endogenize] : paths)
{
int exogenize_id = mod_file->symbol_table.getID(exogenize);
int endogenize_id = mod_file->symbol_table.getID(endogenize);
vector<pair<AbstractShocksStatement::period_range_t, expr_t>> v;
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i], values[i]);
paths_transformed.emplace_back(exogenize_id, move(v), endogenize_id);
}
mod_file->addStatement(make_unique<PerfectForesightControlledPathsStatement>(
move(paths_transformed), move(learnt_in_period), mod_file->symbol_table));
}
void
ParsingDriver::method_of_moments()
{
......@@ -3479,48 +3786,31 @@ ParsingDriver::prior_posterior_function(bool prior_func)
}
void
ParsingDriver::add_ramsey_constraints_statement()
ParsingDriver::begin_ramsey_constraints()
{
mod_file->addStatement(make_unique<RamseyConstraintsStatement>(mod_file->symbol_table,
move(ramsey_constraints)));
ramsey_constraints.clear();
set_current_data_tree(&mod_file->dynamic_model);
}
void
ParsingDriver::ramsey_constraint_add_less(const string &name, const expr_t rhs)
ParsingDriver::end_ramsey_constraints(const vector<expr_t>& constraints)
{
add_ramsey_constraint(name, BinaryOpcode::less, rhs);
}
void
ParsingDriver::ramsey_constraint_add_greater(const string &name, const expr_t rhs)
for (expr_t c : constraints)
try
{
add_ramsey_constraint(name, BinaryOpcode::greater, rhs);
}
auto [symb_id, lower_bound, upper_bound] = c->matchComplementarityCondition();
void
ParsingDriver::ramsey_constraint_add_less_equal(const string &name, const expr_t rhs)
{
add_ramsey_constraint(name, BinaryOpcode::lessEqual, rhs);
auto [it, success]
= mod_file->ramsey_constraints.try_emplace(symb_id, lower_bound, upper_bound);
if (!success)
error("The ramsey_constraints block contains two constraints for variable "
+ mod_file->symbol_table.getName(symb_id));
}
void
ParsingDriver::ramsey_constraint_add_greater_equal(const string &name, const expr_t rhs)
catch (ExprNode::MatchFailureException& e)
{
add_ramsey_constraint(name, BinaryOpcode::greaterEqual, rhs);
error("Ramsey constraint has an incorrect form: " + e.message);
}
void
ParsingDriver::add_ramsey_constraint(const string &name, BinaryOpcode op_code, const expr_t rhs)
{
check_symbol_is_endogenous(name);
int symb_id = mod_file->symbol_table.getID(name);
RamseyConstraintsStatement::Constraint C;
C.endo = symb_id;
C.code = op_code;
C.expression = rhs;
ramsey_constraints.push_back(C);
reset_data_tree();
}
void
......@@ -3572,8 +3862,8 @@ ParsingDriver::add_init2shocks(const string &endo_name, const string &exo_name)
void
ParsingDriver::end_init2shocks(string name)
{
mod_file->addStatement(make_unique<Init2shocksStatement>(move(init2shocks), move(name),
mod_file->symbol_table));
mod_file->addStatement(
make_unique<Init2shocksStatement>(move(init2shocks), move(name), mod_file->symbol_table));
init2shocks.clear();
}
......@@ -3584,13 +3874,15 @@ ParsingDriver::var_expectation_model()
{
string v {options_list.get<OptionsList::StringVal>("variable")};
if (var_expectation_model_expression)
error("You can't pass both the 'variable' or the 'expression' options to the var_expectation_model statement.");
error("You can't pass both the 'variable' or the 'expression' options to the "
"var_expectation_model statement.");
var_expectation_model_expression = data_tree->AddVariable(mod_file->symbol_table.getID(v));
}
catch (OptionsList::UnknownOptionException&)
{
if (!var_expectation_model_expression)
error("You must pass either the 'variable' or the 'expression' option to the var_expectation_model statement.");
error("You must pass either the 'variable' or the 'expression' option to the "
"var_expectation_model statement.");
}
if (var_expectation_model_discount)
......@@ -3604,17 +3896,17 @@ ParsingDriver::var_expectation_model()
else
var_expectation_model_discount = data_tree->One;
int time_shift { stoi(options_list.get_if<OptionsList::NumVal>("time_shift").value_or(OptionsList::NumVal{"0"})) };
int time_shift {stoi(
options_list.get_if<OptionsList::NumVal>("time_shift").value_or(OptionsList::NumVal {"0"}))};
if (time_shift > 0)
error("The 'time_shift' option must be a non-positive integer");
try
{
mod_file->var_expectation_model_table.addVarExpectationModel(options_list.get<OptionsList::StringVal>("model_name"),
var_expectation_model_expression,
mod_file->var_expectation_model_table.addVarExpectationModel(
options_list.get<OptionsList::StringVal>("model_name"), var_expectation_model_expression,
options_list.get<OptionsList::StringVal>("auxiliary_model_name"),
options_list.get<OptionsList::NumVal>("horizon"),
var_expectation_model_discount,
options_list.get<OptionsList::NumVal>("horizon"), var_expectation_model_discount,
time_shift);
}
catch (OptionsList::UnknownOptionException& e)
......@@ -3648,8 +3940,8 @@ ParsingDriver::end_matched_moments(const vector<expr_t> &moments)
{
error("Matched moment expression has incorrect format: " + e.message);
}
mod_file->addStatement(make_unique<MatchedMomentsStatement>(mod_file->symbol_table,
move(parsed_moments)));
mod_file->addStatement(
make_unique<MatchedMomentsStatement>(mod_file->symbol_table, move(parsed_moments)));
reset_data_tree();
}
......@@ -3661,28 +3953,28 @@ ParsingDriver::begin_occbin_constraints()
and those would trigger the non-linearity warning in a stochastic context
if added to the main DynamicModel tree. It also simplifies the
enforcement of various constraints at parsing time. */
occbin_constraints_tree = make_unique<DataTree>(mod_file->symbol_table,
mod_file->num_constants,
occbin_constraints_tree = make_unique<DataTree>(mod_file->symbol_table, mod_file->num_constants,
mod_file->external_functions_table,
false);
mod_file->heterogeneity_table, false);
set_current_data_tree(occbin_constraints_tree.get());
}
void
ParsingDriver::end_occbin_constraints(vector<tuple<string, BinaryOpNode *, BinaryOpNode *, expr_t, expr_t>> constraints)
ParsingDriver::end_occbin_constraints(
vector<tuple<string, BinaryOpNode*, BinaryOpNode*, expr_t, expr_t>> constraints)
{
// Perform a few checks
for (const auto& [name, bind, relax, error_bind, error_relax] : constraints)
{
string param_name = buildOccbinBindParamName(name);
if (!mod_file->symbol_table.exists(param_name))
error("No equation has been declared for regime '" + name + "'");
error("No equation has been declared for constraint '" + name + "'");
if (!bind)
error("The 'bind' expression is missing in constraint '" + name + "'");
}
mod_file->addStatement(make_unique<OccbinConstraintsStatement>(*occbin_constraints_tree,
move(constraints)));
mod_file->addStatement(
make_unique<OccbinConstraintsStatement>(*occbin_constraints_tree, move(constraints)));
reset_data_tree();
}
......@@ -3716,7 +4008,8 @@ void
ParsingDriver::add_pac_target_info_component(expr_t component_expr)
{
get<0>(pac_target_info_component) = component_expr;
mod_file->pac_model_table.addTargetComponent(pac_target_info_name, exchange(pac_target_info_component, {}));
mod_file->pac_model_table.addTargetComponent(pac_target_info_name,
exchange(pac_target_info_component, {}));
}
void
......@@ -3742,8 +4035,7 @@ ParsingDriver::isSymbolIdentifier(const string &str)
{
if (str.empty())
return false;
auto myisalpha = [](char ch)
{
auto myisalpha = [](char ch) {
// We cannot use std::isalpha(), because it is locale-dependent
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
};
......@@ -3785,3 +4077,39 @@ ParsingDriver::resid()
mod_file->addStatement(make_unique<ResidStatement>(move(options_list)));
options_list.clear();
}
void
ParsingDriver::matched_irfs(MatchedIrfsStatement::matched_irfs_t values_weights, bool overwrite)
{
mod_file->addStatement(make_unique<MatchedIrfsStatement>(move(values_weights), overwrite));
}
void
ParsingDriver::matched_irfs_weights(MatchedIrfsWeightsStatement::matched_irfs_weights_t weights,
bool overwrite)
{
mod_file->addStatement(make_unique<MatchedIrfsWeightsStatement>(move(weights), overwrite));
}
void
ParsingDriver::heterogeneity_dimension(const vector<string>& dims)
{
for (const auto& dim : dims)
{
int het_dim_id {[&] {
try
{
return mod_file->heterogeneity_table.addDimension(dim);
}
catch (HeterogeneityTable::AlreadyDeclaredDimensionException&)
{
error("Heterogeneity dimension '" + dim + "' already declared");
}
}()};
assert(static_cast<int>(mod_file->heterogeneous_models.size()) == het_dim_id);
mod_file->heterogeneous_models.emplace_back(mod_file->symbol_table, mod_file->num_constants,
mod_file->external_functions_table,
mod_file->heterogeneity_table, het_dim_id);
}
}
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,31 +17,31 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _PARSING_DRIVER_HH
#define _PARSING_DRIVER_HH
#ifndef PARSING_DRIVER_HH
#define PARSING_DRIVER_HH
#ifdef _MACRO_DRIVER_HH
#ifdef MACRO_DRIVER_HH
# error Impossible to include both ParsingDriver.hh and macro/Driver.hh
#endif
#include <string>
#include <vector>
#include <istream>
#include <stack>
#include <optional>
#include <stack>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
#include "ModFile.hh"
#include "SymbolList.hh"
class ParsingDriver;
#include "ExprNode.hh"
#include "DynareBison.hh"
#include "ExprNode.hh"
#include "ComputingTasks.hh"
#include "Shocks.hh"
#include "NumericalInitialization.hh"
#include "DynamicModel.hh"
#include "NumericalInitialization.hh"
#include "Shocks.hh"
using namespace std;
......@@ -66,8 +66,7 @@ public:
//! The main lexing function
Dynare::parser::token_type lex(Dynare::parser::semantic_type* yylval,
Dynare::parser::location_type *yylloc,
ParsingDriver &driver);
Dynare::parser::location_type* yylloc, ParsingDriver& driver);
//! The filename being parsed
/*! The bison parser locations (begin and end) contain a pointer to that string */
......@@ -75,9 +74,6 @@ public:
//! Increment the location counter given a token
static void location_increment(Dynare::parser::location_type* yylloc, const char* yytext);
//! Count parens in dates statement
int dates_parens_nb;
};
//! Drives the scanning and parsing of the .mod file, and constructs its abstract representation
......@@ -88,27 +84,35 @@ private:
//! Checks that a given symbol exists, and stops with an error message if it doesn't
void check_symbol_existence(const string& name);
//! Checks that a given symbol exists and is a parameter, and stops with an error message if it isn't
//! Checks that a given symbol exists and is a parameter, and stops with an error message if it
//! isn't
void check_symbol_is_parameter(const string& name);
//! Checks that a given symbol was assigned within a Statement
void check_symbol_is_statement_variable(const string& name);
//! Checks that a given symbol exists and is a endogenous or exogenous, and stops with an error message if it isn't
//! Checks that a given symbol exists and is a endogenous or exogenous, and stops with an error
//! message if it isn't
void check_symbol_is_endogenous_or_exogenous(const string& name, bool allow_exo_det);
//! Checks that a given symbol exists and is a endogenous, and stops with an error message if it isn't
public:
//! Checks that a given symbol exists and is a endogenous, and stops with an error message if it
//! isn't
void check_symbol_is_endogenous(const string& name);
//! Checks that a given symbol exists and is a exogenous, and stops with an error message if it isn't
//! Checks that a given symbol exists and is a exogenous, and stops with an error message if it
//! isn't
void check_symbol_is_exogenous(const string& name, bool allow_exo_det);
//! Checks for symbol existence in model block. If it doesn't exist, an error message is stored to be printed at
//! the end of the model block
private:
//! Checks for symbol existence in model block. If it doesn't exist, an error message is stored to
//! be printed at the end of the model block
void check_symbol_existence_in_model_block(const string& name);
//! Helper to add a symbol declaration (returns its symbol ID)
int declare_symbol(const string &name, SymbolType type, const string &tex_name, const vector<pair<string, string>> &partition_value);
int declare_symbol(const string& name, SymbolType type, const string& tex_name,
const vector<pair<string, string>>& partition_value,
const optional<int>& heterogeneity_dimension);
//! Temporary store for the planner objective
unique_ptr<PlannerObjective> planner_objective;
......@@ -122,13 +126,20 @@ private:
DataTree* data_tree;
//! The model tree in which to add expressions currently parsed
/*! It is only a dynamic cast of data_tree pointer, and is therefore null if data_tree is not a ModelTree instance */
/*! It is only a dynamic cast of data_tree pointer, and is therefore null if data_tree is not a
* ModelTree instance */
ModelTree* model_tree;
//! The dynamic model tree in which to add expressions currently parsed
/*! It is only a dynamic cast of data_tree pointer, and is therefore null if data_tree is not a DynamicModel instance */
/*! It is only a dynamic cast of data_tree pointer, and is therefore null if data_tree is not a
* DynamicModel instance */
DynamicModel* dynamic_model;
//! The heterogeneous model tree in which to add expressions currently parsed
/*! It is only a dynamic cast of data_tree pointer, and is therefore null if data_tree is not a
* HeterogeneousModel instance */
HeterogeneousModel* heterogeneous_model;
//! Sets data_tree and model_tree pointers
void set_current_data_tree(DataTree* data_tree_arg);
......@@ -163,7 +174,8 @@ private:
//! Temporary storage for correlations of shocks
ShocksStatement::covar_and_corr_shocks_t corr_shocks;
//! Temporary storage for values and scales of heteroskedastic_shocks
HeteroskedasticShocksStatement::heteroskedastic_shocks_t heteroskedastic_shocks_values, heteroskedastic_shocks_scales;
HeteroskedasticShocksStatement::heteroskedastic_shocks_t heteroskedastic_shocks_values,
heteroskedastic_shocks_scales;
//! Temporary storage for initval blocks
InitOrEndValStatement::init_values_t init_values;
/* Temporary storage for endval blocks. Uses a type that encompasses both
......@@ -177,11 +189,10 @@ private:
MomentCalibration::constraints_t moment_calibration_constraints;
//! Temporary storage for irf_calibration
IrfCalibration::constraints_t irf_calibration_constraints;
//! Temporary storage for ramsey_constraints
RamseyConstraintsStatement::constraints_t ramsey_constraints;
//! Temporary storage for svar_identification blocks
SvarIdentificationStatement::svar_identification_restrictions_t svar_ident_restrictions;
//! Temporary storage for mapping the equation number to the restrictions within an svar_identification block
//! Temporary storage for mapping the equation number to the restrictions within an
//! svar_identification block
map<int, vector<int>> svar_equation_restrictions;
//! Temporary storage for constants exculsion within an svar_identification
bool svar_constants_exclusion;
......@@ -191,7 +202,8 @@ private:
bool svar_lower_cholesky;
//! Temporary storage for equation number for a restriction within an svar_identification block
int svar_equation_nbr;
//! Temporary storage for left/right handside of a restriction equation within an svar_identificaton block
//! Temporary storage for left/right handside of a restriction equation within an
//! svar_identificaton block
bool svar_left_handside;
//! Temporary storage for current restriction number in svar_identification block
map<int, int> svar_Qi_restriction_nbr;
......@@ -214,15 +226,18 @@ private:
stack<vector<expr_t>> stack_external_function_args;
//! Temporary storage for parameters in joint prior statement
vector<string> joint_parameters;
//! Temporary storage for the symb_id associated with the "name" symbol of the current external_function statement
//! Temporary storage for the symb_id associated with the "name" symbol of the current
//! external_function statement
int current_external_function_id;
//! Temporary storage for option list provided to external_function()
ExternalFunctionsTable::external_function_options current_external_function_options;
//! Temporary storage for a variance declared in the prior statement
expr_t prior_variance;
SubsamplesStatement::subsample_declaration_map_t subsample_declaration_map;
//! Temporary storage for subsample statement: map<pair<var_name1, var_name2>>, subsample_declaration_map >
using subsample_declarations_t = map<pair<string, string >, SubsamplesStatement::subsample_declaration_map_t >;
//! Temporary storage for subsample statement: map<pair<var_name1, var_name2>>,
//! subsample_declaration_map >
using subsample_declarations_t
= map<pair<string, string>, SubsamplesStatement::subsample_declaration_map_t>;
subsample_declarations_t subsample_declarations;
//! Temporary storage for shock_groups
vector<string> shock_group;
......@@ -255,7 +270,6 @@ private:
bool nostrict;
vector<pair<string, string>> model_errors;
vector<pair<string, string>> undeclared_model_variable_errors;
//! True when parsing the epilogue block
......@@ -273,7 +287,7 @@ public:
ParsingDriver(WarningConsolidation& warnings_arg, bool nostrict_arg) :
warnings {warnings_arg}, nostrict {nostrict_arg}
{
};
}
ParsingDriver(const ParsingDriver&) = delete;
ParsingDriver& operator=(const ParsingDriver&) = delete;
......@@ -302,20 +316,16 @@ public:
expr_t var_expectation_model_discount {nullptr};
//! Error handler with explicit location
void error(const Dynare::parser::location_type &l, const string &m) __attribute__ ((noreturn));
[[noreturn]] void error(const Dynare::parser::location_type& l, const string& m);
//! Error handler using saved location
void error(const string &m) __attribute__ ((noreturn));
[[noreturn]] void error(const string& m);
//! Warning handler using saved location
void warning(const string& m);
//! Error handler with explicit location (used in model block, accumulating error messages to be printed later)
void model_error(const string &m, const string &var);
//! Error handler with explicit location (used in model block, accumulating error messages to be
//! printed later)
void undeclared_model_variable_error(const string& m, const string& var);
//! Code shared between model_error() and error()
void create_error_string(const Dynare::parser::location_type &l, const string &m, const string &var);
void create_error_string(const Dynare::parser::location_type &l, const string &m, ostream &stream);
//! Check if a given symbol exists in the parsing context, and is not a mod file local variable
bool symbol_exists_and_is_not_modfile_local_or_external_function(const string& s);
//! Sets mode of ModelTree class to use C output
......@@ -352,19 +362,25 @@ public:
//! Sets the FILENAME for the initial value in initval
void initval_file();
//! Declares an endogenous variable (and returns its symbol ID)
int declare_endogenous(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {});
int declare_endogenous(const string& name, const string& tex_name = "",
const vector<pair<string, string>>& partition_value = {});
// Handles a “var” or “var(log)” statement (without “deflator” or “log_deflator” options)
void var(const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list, bool log_option);
void var(const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
const optional<string>& heterogeneity_dimension, bool log_option);
//! Declares an exogenous variable (and returns its symbol ID)
int declare_exogenous(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {});
int declare_exogenous(const string& name, const string& tex_name = "",
const vector<pair<string, string>>& partition_value = {});
// Handles a “varexo” statement
void varexo(const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list);
void varexo(const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
const optional<string>& heterogeneity_dimension);
// Handles a “varexo_det” statement
void varexo_det(const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list);
//! Declares a parameter (and returns its symbol ID)
int declare_parameter(const string &name, const string &tex_name = "", const vector<pair<string, string>> &partition_value = {});
int declare_parameter(const string& name, const string& tex_name = "",
const vector<pair<string, string>>& partition_value = {});
// Handles a “parameters” statement
void parameters(const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list);
void parameters(const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
const optional<string>& heterogeneity_dimension);
// Handles a “model_local_variable” statement
void model_local_variable(const vector<pair<string, string>>& symbol_list);
//! Declares a statement local variable
......@@ -375,7 +391,8 @@ public:
void set_subsample_name_equal_to_date_range(string name, string date1, string date2);
//! Checks that a subsample statement (and given name) were provided for the pair name1 & name2
void check_subsample_declaration_exists(const string& name1, const string& subsample_name);
void check_subsample_declaration_exists(const string &name1, const string &name2, const string &subsample_name);
void check_subsample_declaration_exists(const string& name1, const string& name2,
const string& subsample_name);
//! Copies the set of subsamples from_name to_name
void copy_subsamples(string to_name1, string to_name2, string from_name1, string from_name2);
//! Sets the value of the planner_discount option of ramsey_{model,policy}
......@@ -421,7 +438,7 @@ public:
//! Writes end of an endval block
void end_endval(bool all_values_required);
//! Writes end of an endval(learnt_in=…) block
void end_endval_learnt_in(const string &learnt_in_period);
void end_endval_learnt_in(variant<int, string> learnt_in_period);
//! Writes end of an histval block
void end_histval(bool all_values_required);
//! Writes end of an homotopy_setup block
......@@ -434,10 +451,11 @@ public:
void add_epilogue_variable(const string& varname);
//! Add equation in epilogue block
void add_epilogue_equal(const string& varname, expr_t expr);
/* Begin a model or model_replace block, or an expression as an option value
of some statement.
Must be followed by a call to reset_data_tree(). */
/* Begin a model block (without heterogeneity option), or an expression as an option value of some
statement. Must be followed by a call to reset_data_tree(). */
void begin_model();
// Begin a model(heterogeneity=…) block
void begin_heterogeneous_model(const string& heterogeneity_dimension);
//! End a model or model_replace block, printing errors that were encountered in parsing
void end_model();
//! Writes a shocks statement
......@@ -447,9 +465,12 @@ public:
//! Writes a shocks(surprise) statement
void end_shocks_surprise(bool overwrite);
//! Writes a shocks(learnt_in=…) block
void end_shocks_learnt_in(const string &learnt_in_period, bool overwrite);
void end_shocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite);
// For a shocks(heterogeneity=…) block
void end_heterogeneous_shocks(const string& heterogeneity_dimension, bool overwrite);
//! Writes a mshocks(learnt_in=…) block
void end_mshocks_learnt_in(const string &learnt_in_period, bool overwrite, bool relative_to_initval);
void end_mshocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite,
bool relative_to_initval);
//! Writes a heteroskedastic_shocks statement
void end_heteroskedastic_shocks(bool overwrite);
/* Adds a deterministic shock, a path element inside a
......@@ -461,9 +482,13 @@ public:
multiply, // for “multiply” in “shocks(learnt_in)”
conditional_forecast
};
void add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, DetShockType type);
void add_det_shock(const string& var,
const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, DetShockType type);
//! Adds a heteroskedastic shock (either values or scales)
void add_heteroskedastic_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool scales);
void add_heteroskedastic_shock(const string& var,
const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, bool scales);
//! Adds a std error shock
void add_stderr_shock(const string& var, expr_t value);
//! Adds a variance shock
......@@ -537,8 +562,8 @@ public:
void osr_params_bounds();
//! Add a line in an osr params block
void add_osr_params_element();
//! Sets the frequency of the data
void set_time(const string &arg);
// Sets the initial period for estimation
void set_time(string period);
//! Estimation Data
void estimation_data();
//! Sets the prior for a parameter
......@@ -550,13 +575,15 @@ public:
//! Adds the variance option to its temporary holding place
void set_prior_variance(expr_t variance = nullptr);
//! Copies the prior from_name to_name
void copy_prior(string to_declaration_type, string to_name1, string to_name2, string to_subsample_name,
string from_declaration_type, string from_name1, string from_name2, string from_subsample_name);
void copy_prior(string to_declaration_type, string to_name1, string to_name2,
string to_subsample_name, string from_declaration_type, string from_name1,
string from_name2, string from_subsample_name);
//! Sets the options for a parameter
void set_options(string name, string subsample_name);
//! Copies the options from_name to_name
void copy_options(string to_declaration_type, string to_name1, string to_name2, string to_subsample_name,
string from_declaration_type, string from_name1, string from_name2, string from_subsample_name);
void copy_options(string to_declaration_type, string to_name1, string to_name2,
string to_subsample_name, string from_declaration_type, string from_name1,
string from_name2, string from_subsample_name);
//! Sets the prior for estimated std dev
void set_std_prior(string name, string subsample_name);
//! Sets the options for estimated std dev
......@@ -567,8 +594,8 @@ public:
void set_corr_options(string name1, string name2, string subsample_name);
//! Runs estimation process
void run_estimation(vector<string> symbol_list);
//! Runs dynare_sensitivy()
void dynare_sensitivity();
//! Runs sensitivity
void sensitivity();
//! Check that no observed variable has yet be defined
void check_varobs();
//! Add a new observed variable
......@@ -640,18 +667,9 @@ public:
void end_planner_objective(expr_t expr);
//! Ramsey model statement
void ramsey_model();
//! Ramsey constraints statement
void add_ramsey_constraints_statement();
//! Ramsey less constraint
void ramsey_constraint_add_less(const string &name, const expr_t rhs);
//! Ramsey greater constraint
void ramsey_constraint_add_greater(const string &name, const expr_t rhs);
//! Ramsey less or equal constraint
void ramsey_constraint_add_less_equal(const string &name, const expr_t rhs);
//! Ramsey greater or equal constraint
void ramsey_constraint_add_greater_equal(const string &name, const expr_t rhs);
//! Ramsey constraint helper function
void add_ramsey_constraint(const string &name, BinaryOpcode op_code, const expr_t rhs);
// Ramsey constraints statement
void begin_ramsey_constraints();
void end_ramsey_constraints(const vector<expr_t>& constraints);
//! Ramsey policy statement
void ramsey_policy(vector<string> symbol_list);
//! Evaluate Planner Objective
......@@ -721,9 +739,11 @@ public:
//! Extended path
void extended_path();
//! Writes token "arg1=arg2" to model tree
expr_t add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags);
expr_t add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags,
expr_t complementarity_condition = nullptr);
//! Writes token "arg=0" to model tree
expr_t add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags);
expr_t add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags,
expr_t complementarity_condition = nullptr);
//! Writes token "arg1+arg2" to model tree
expr_t add_plus(expr_t arg1, expr_t arg2);
//! Writes token "arg1-arg2" to model tree
......@@ -826,21 +846,25 @@ public:
expr_t add_erfc(expr_t arg);
//! Writes token "steadyState(arg1)" to model tree
expr_t add_steady_state(expr_t arg1);
// Add a “sum(arg)” node to model tree
expr_t add_sum(expr_t arg);
//! Pushes empty vector onto stack when a symbol is encountered (mod_var or ext_fun)
void push_external_function_arg_vector_onto_stack();
//! Adds an external function argument
void add_external_function_arg(expr_t arg);
//! Test to see if model/external function has exactly one integer argument
optional<int> is_there_one_integer_argument() const;
[[nodiscard]] optional<int> is_there_one_integer_argument() const;
//! Adds an external function call node
expr_t add_model_var_or_external_function(const string& function_name, bool in_model_block);
//! Adds a native statement
void add_native(string s);
//! Adds a native statement, first removing the set of characters passed in token (and everything after)
//! Adds a native statement, first removing the set of characters passed in token (and everything
//! after)
void add_native_remove_charset(string_view str, string_view token);
//! Adds a verbatim statement
void add_verbatim(string s);
//! Adds a verbatim statement, first removing the set of characters passed in token (and everything after)
//! Adds a verbatim statement, first removing the set of characters passed in token (and
//! everything after)
void add_verbatim_remove_charset(string_view str, string_view token);
//! Resets data_tree and model_tree pointers to default (i.e. mod_file->expressions_tree)
void reset_data_tree();
......@@ -851,14 +875,19 @@ public:
//! Add a multiple assignment equation in steady_state_model block
void add_steady_state_model_equal_multiple(const vector<string>& symbol_list, expr_t expr);
//! Ends declaration of trend variable
void end_trend_var(bool log_trend, expr_t growth_factor, const vector<pair<string, string>> &symbol_list);
void end_trend_var(bool log_trend, expr_t growth_factor,
const vector<pair<string, string>>& symbol_list);
//! Handles a “var(deflator=…)”, “var(log, deflator=…)” or “var(log_deflator=…)” statement
void end_nonstationary_var(bool log_deflator, expr_t deflator, const vector<tuple<string, string, vector<pair<string, string>>>> &symbol_list, bool log_option);
void end_nonstationary_var(
bool log_deflator, expr_t deflator,
const vector<tuple<string, string, vector<pair<string, string>>>>& symbol_list,
bool log_option);
//! Add a graph format to the list of formats requested
void add_graph_format(string name);
//! Add the graph_format option to the OptionsList structure
void process_graph_format_option();
//! Add the graph_format option to the initial_condition_decomp substructure of the OptionsList structure
//! Add the graph_format option to the initial_condition_decomp substructure of the OptionsList
//! structure
void initial_condition_decomp_process_graph_format_option();
//! Add the graph_format option to the plot_shock_decomp substructure of the OptionsList structure
void plot_shock_decomp_process_graph_format_option();
......@@ -867,11 +896,13 @@ public:
//! Processing the parallel_local_files option
void add_parallel_local_file(string filename);
//! Add an item of a moment_calibration statement
void add_moment_calibration_item(const string &endo1, const string &endo2, string lags, const pair<expr_t, expr_t> &range);
void add_moment_calibration_item(const string& endo1, const string& endo2, string lags,
const pair<expr_t, expr_t>& range);
//! End a moment_calibration statement
void end_moment_calibration();
//! Add an item of an irf_calibration statement
void add_irf_calibration_item(const string &endo, string periods, const string &exo, const pair<expr_t, expr_t> &range);
void add_irf_calibration_item(const string& endo, string periods, const string& exo,
const pair<expr_t, expr_t>& range);
//! End a moment_calibration statement
void end_irf_calibration();
//! Add a shock to a group
......@@ -890,6 +921,10 @@ public:
void perfect_foresight_solver();
void perfect_foresight_with_expectation_errors_setup();
void perfect_foresight_with_expectation_errors_solver();
void perfect_foresight_controlled_paths(
const vector<tuple<string, vector<AbstractShocksStatement::period_range_t>, vector<expr_t>,
string>>& paths,
variant<int, string> learnt_in_period);
void prior_posterior_function(bool prior_func);
//! Method of Moments estimation statement
void method_of_moments();
......@@ -902,7 +937,8 @@ public:
//! Start parsing an occbin_constraints block
void begin_occbin_constraints();
//! Add an occbin_constraints block
void end_occbin_constraints(vector<tuple<string, BinaryOpNode *, BinaryOpNode *, expr_t, expr_t>> constraints);
void end_occbin_constraints(
vector<tuple<string, BinaryOpNode*, BinaryOpNode*, expr_t, expr_t>> constraints);
// Process a model_remove statement
void model_remove(const vector<map<string, string>>& listed_eqs_by_tags);
// Begin a model_replace statement
......@@ -919,13 +955,21 @@ public:
void set_pac_target_info_component_kind(PacTargetKind kind);
// Add a resid statement
void resid();
// Add a matched_irfs block
void matched_irfs(MatchedIrfsStatement::matched_irfs_t values_weights, bool overwrite);
// Add a matched_irfs_weights block
void matched_irfs_weights(MatchedIrfsWeightsStatement::matched_irfs_weights_t weights,
bool overwrite);
void heterogeneity_dimension(const vector<string>& dims);
// Returns true iff the string is a legal symbol identifier (see NAME token in lexer)
static bool isSymbolIdentifier(const string& str);
// Given an Occbin regime name, returns the corresponding auxiliary parameter
static string buildOccbinBindParamName(const string &regime)
static string
buildOccbinBindParamName(const string& regime)
{
return "occbin_" + regime + "_bind";
}
};
#endif // ! PARSING_DRIVER_HH
#endif
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -19,11 +19,43 @@
#include <cassert>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <utility>
#include "Shocks.hh"
static auto print_matlab_period_range = []<class T>(ostream& output, const T& arg) {
if constexpr (is_same_v<T, pair<int, int>>)
output << arg.first << ":" << arg.second;
else if constexpr (is_same_v<T, pair<string, string>>)
output << "(" << arg.first << "):(" << arg.second << ")";
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
};
static auto print_json_period_range = []<class T>(ostream& output, const T& arg) {
if constexpr (is_same_v<T, pair<int, int>>)
output << R"("period1": )" << arg.first << ", "
<< R"("period2": )" << arg.second;
else if constexpr (is_same_v<T, pair<string, string>>)
output << R"("period1": ")" << arg.first << R"(", )"
<< R"("period2": ")" << arg.second << '"';
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
};
static auto print_matlab_learnt_in = [](ostream& output, const auto& p) { output << p; };
static auto print_json_learnt_in = []<class T>(ostream& output, const T& p) {
if constexpr (is_same_v<T, int>)
output << p;
else if constexpr (is_same_v<T, string>)
output << '"' << p << '"';
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
};
AbstractShocksStatement::AbstractShocksStatement(bool overwrite_arg, ShockType type_arg,
det_shocks_t det_shocks_arg,
const SymbolTable& symbol_table_arg) :
......@@ -37,47 +69,38 @@ AbstractShocksStatement::AbstractShocksStatement(bool overwrite_arg, ShockType t
void
AbstractShocksStatement::writeDetShocks(ostream& output) const
{
int exo_det_length = 0;
for (const auto& [id, shock_vec] : det_shocks)
for (bool exo_det = (symbol_table.getType(id) == SymbolType::exogenousDet);
const auto &[period1, period2, value] : shock_vec)
const auto& [period_range, value] : shock_vec)
{
output << "M_.det_shocks = [ M_.det_shocks;" << endl
<< boolalpha
<< "struct('exo_det'," << exo_det
<< ",'exo_id'," << symbol_table.getTypeSpecificID(id)+1
<< ",'type','" << typeToString(type) << "'"
<< ",'periods'," << period1 << ":" << period2
<< ",'value',";
<< boolalpha << "struct('exo_det'," << exo_det << ",'exo_id',"
<< symbol_table.getTypeSpecificID(id) + 1 << ",'type','" << typeToString(type) << "'"
<< ",'periods',";
visit(bind(print_matlab_period_range, ref(output), placeholders::_1), period_range);
output << ",'value',";
value->writeOutput(output);
output << ") ];" << endl;
if (exo_det && period2 > exo_det_length)
exo_det_length = period2;
}
output << "M_.exo_det_length = " << exo_det_length << ";\n";
}
void
AbstractShocksStatement::writeJsonDetShocks(ostream& output) const
{
output << R"("deterministic_shocks": [)";
for (bool printed_something{false};
const auto &[id, shock_vec] : det_shocks)
for (bool printed_something {false}; const auto& [id, shock_vec] : det_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2{false};
const auto &[period1, period2, value] : shock_vec)
for (bool printed_something2 {false}; const auto& [period_range, value] : shock_vec)
{
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("value": ")";
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -101,14 +124,14 @@ AbstractShocksStatement::typeToString(ShockType type)
__builtin_unreachable(); // Silence GCC warning
}
ShocksStatement::ShocksStatement(bool overwrite_arg,
det_shocks_t det_shocks_arg,
ShocksStatement::ShocksStatement(bool overwrite_arg, det_shocks_t det_shocks_arg,
var_and_std_shocks_t var_shocks_arg,
var_and_std_shocks_t std_shocks_arg,
covar_and_corr_shocks_t covar_shocks_arg,
covar_and_corr_shocks_t corr_shocks_arg,
const SymbolTable& symbol_table_arg) :
AbstractShocksStatement{overwrite_arg, ShockType::level, move(det_shocks_arg), symbol_table_arg},
AbstractShocksStatement {overwrite_arg, ShockType::level, move(det_shocks_arg),
symbol_table_arg},
var_shocks {move(var_shocks_arg)},
std_shocks {move(std_shocks_arg)},
covar_shocks {move(covar_shocks_arg)},
......@@ -120,16 +143,14 @@ void
ShocksStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
output << "%" << endl
<< "% SHOCKS instructions" << endl
<< "%" << endl;
output << "%" << endl << "% SHOCKS instructions" << endl << "%" << endl;
if (overwrite)
{
output << "M_.det_shocks = [];" << endl;
output << "M_.Sigma_e = zeros(" << symbol_table.exo_nbr() << ", "
<< symbol_table.exo_nbr() << ");" << endl
output << "M_.Sigma_e = zeros(" << symbol_table.exo_nbr() << ", " << symbol_table.exo_nbr()
<< ");" << endl
<< "M_.Correlation_matrix = eye(" << symbol_table.exo_nbr() << ", "
<< symbol_table.exo_nbr() << ");" << endl;
......@@ -139,9 +160,7 @@ ShocksStatement::writeOutput(ostream &output, [[maybe_unused]] const string &bas
<< "M_.Correlation_matrix_ME = eye(" << symbol_table.observedVariablesNbr() << ", "
<< symbol_table.observedVariablesNbr() << ");" << endl;
else
output << "M_.H = 0;" << endl
<< "M_.Correlation_matrix_ME = 1;" << endl;
output << "M_.H = 0;" << endl << "M_.Correlation_matrix_ME = 1;" << endl;
}
writeDetShocks(output);
......@@ -169,8 +188,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
writeJsonDetShocks(output);
}
output << R"(, "variance": [)";
for (bool printed_something{false};
auto &[id, value] : var_shocks)
for (bool printed_something {false}; auto& [id, value] : var_shocks)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -181,8 +199,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
}
output << "]"
<< R"(, "stderr": [)";
for (bool printed_something{false};
auto &[id, value] : std_shocks)
for (bool printed_something {false}; auto& [id, value] : std_shocks)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -193,8 +210,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
}
output << "]"
<< R"(, "covariance": [)";
for (bool printed_something{false};
auto &[ids, value] : covar_shocks)
for (bool printed_something {false}; auto& [ids, value] : covar_shocks)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -207,8 +223,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
}
output << "]"
<< R"(, "correlation": [)";
for (bool printed_something{false};
auto &[ids, value] : corr_shocks)
for (bool printed_something {false}; auto& [ids, value] : corr_shocks)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -224,8 +239,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const
}
void
ShocksStatement::writeVarOrStdShock(ostream &output, const pair<int, expr_t> &it,
bool stddev) const
ShocksStatement::writeVarOrStdShock(ostream& output, const pair<int, expr_t>& it, bool stddev) const
{
SymbolType type = symbol_table.getType(it.first);
assert(type == SymbolType::exogenous || symbol_table.isObservedVariable(it.first));
......@@ -268,7 +282,8 @@ ShocksStatement::writeCovarOrCorrShock(ostream &output, const pair<pair<int, int
SymbolType type1 = symbol_table.getType(it.first.first);
SymbolType type2 = symbol_table.getType(it.first.second);
assert((type1 == SymbolType::exogenous && type2 == SymbolType::exogenous)
|| (symbol_table.isObservedVariable(it.first.first) && symbol_table.isObservedVariable(it.first.second)));
|| (symbol_table.isObservedVariable(it.first.first)
&& symbol_table.isObservedVariable(it.first.second)));
string matrix, corr_matrix;
int id1, id2;
if (type1 == SymbolType::exogenous)
......@@ -289,19 +304,19 @@ ShocksStatement::writeCovarOrCorrShock(ostream &output, const pair<pair<int, int
output << matrix << "(" << id1 << ", " << id2 << ") = ";
it.second->writeOutput(output);
if (corr)
output << "*sqrt(" << matrix << "(" << id1 << ", " << id1 << ")*"
<< matrix << "(" << id2 << ", " << id2 << "))";
output << "*sqrt(" << matrix << "(" << id1 << ", " << id1 << ")*" << matrix << "(" << id2
<< ", " << id2 << "))";
output << ";" << endl
<< matrix << "(" << id2 << ", " << id1 << ") = "
<< matrix << "(" << id1 << ", " << id2 << ");" << endl;
<< matrix << "(" << id2 << ", " << id1 << ") = " << matrix << "(" << id1 << ", " << id2
<< ");" << endl;
if (corr)
{
output << corr_matrix << "(" << id1 << ", " << id2 << ") = ";
it.second->writeOutput(output);
output << ";" << endl
<< corr_matrix << "(" << id2 << ", " << id1 << ") = "
<< corr_matrix << "(" << id1 << ", " << id2 << ");" << endl;
<< corr_matrix << "(" << id2 << ", " << id1 << ") = " << corr_matrix << "(" << id1
<< ", " << id2 << ");" << endl;
}
}
......@@ -324,22 +339,24 @@ ShocksStatement::checkPass(ModFileStructure &mod_file_struct,
Also Determine if there is a calibrated measurement error */
for (auto [id, val] : var_shocks)
{
if (symbol_table.getType(id) != SymbolType::exogenous
&& !symbol_table.isObservedVariable(id))
if (symbol_table.getType(id) != SymbolType::exogenous && !symbol_table.isObservedVariable(id))
{
cerr << "shocks: setting a variance on '"
<< symbol_table.getName(id) << "' is not allowed, because it is neither an exogenous variable nor an observed endogenous variable" << endl;
cerr << "shocks: setting a variance on '" << symbol_table.getName(id)
<< "' is not allowed, because it is neither an exogenous variable nor an observed "
"endogenous variable"
<< endl;
exit(EXIT_FAILURE);
}
}
for (auto [id, val] : std_shocks)
{
if (symbol_table.getType(id) != SymbolType::exogenous
&& !symbol_table.isObservedVariable(id))
if (symbol_table.getType(id) != SymbolType::exogenous && !symbol_table.isObservedVariable(id))
{
cerr << "shocks: setting a standard error on '"
<< symbol_table.getName(id) << "' is not allowed, because it is neither an exogenous variable nor an observed endogenous variable" << endl;
cerr << "shocks: setting a standard error on '" << symbol_table.getName(id)
<< "' is not allowed, because it is neither an exogenous variable nor an observed "
"endogenous variable"
<< endl;
exit(EXIT_FAILURE);
}
}
......@@ -353,9 +370,11 @@ ShocksStatement::checkPass(ModFileStructure &mod_file_struct,
|| (symbol_table.isObservedVariable(symb_id1)
&& symbol_table.isObservedVariable(symb_id2))))
{
cerr << "shocks: setting a covariance between '"
<< symbol_table.getName(symb_id1) << "' and '"
<< symbol_table.getName(symb_id2) << "'is not allowed; covariances can only be specified for exogenous or observed endogenous variables of same type" << endl;
cerr << "shocks: setting a covariance between '" << symbol_table.getName(symb_id1)
<< "' and '" << symbol_table.getName(symb_id2)
<< "'is not allowed; covariances can only be specified for exogenous or observed "
"endogenous variables of same type"
<< endl;
exit(EXIT_FAILURE);
}
}
......@@ -369,9 +388,11 @@ ShocksStatement::checkPass(ModFileStructure &mod_file_struct,
|| (symbol_table.isObservedVariable(symb_id1)
&& symbol_table.isObservedVariable(symb_id2))))
{
cerr << "shocks: setting a correlation between '"
<< symbol_table.getName(symb_id1) << "' and '"
<< symbol_table.getName(symb_id2) << "'is not allowed; correlations can only be specified for exogenous or observed endogenous variables of same type" << endl;
cerr << "shocks: setting a correlation between '" << symbol_table.getName(symb_id1)
<< "' and '" << symbol_table.getName(symb_id2)
<< "'is not allowed; correlations can only be specified for exogenous or observed "
"endogenous variables of same type"
<< endl;
exit(EXIT_FAILURE);
}
}
......@@ -402,13 +423,11 @@ ShocksStatement::has_calibrated_measurement_errors() const
return true;
for (const auto& [ids, val] : covar_shocks)
if (symbol_table.isObservedVariable(ids.first)
|| symbol_table.isObservedVariable(ids.second))
if (symbol_table.isObservedVariable(ids.first) || symbol_table.isObservedVariable(ids.second))
return true;
for (const auto& [ids, val] : corr_shocks)
if (symbol_table.isObservedVariable(ids.first)
|| symbol_table.isObservedVariable(ids.second))
if (symbol_table.isObservedVariable(ids.first) || symbol_table.isObservedVariable(ids.second))
return true;
return false;
......@@ -418,7 +437,8 @@ MShocksStatement::MShocksStatement(bool overwrite_arg, bool relative_to_initval_
det_shocks_t det_shocks_arg,
const SymbolTable& symbol_table_arg) :
AbstractShocksStatement {overwrite_arg,
relative_to_initval_arg ? ShockType::multiplyInitialSteadyState : ShockType::multiplySteadyState,
relative_to_initval_arg ? ShockType::multiplyInitialSteadyState
: ShockType::multiplySteadyState,
move(det_shocks_arg), symbol_table_arg},
relative_to_initval {relative_to_initval_arg}
{
......@@ -428,9 +448,7 @@ void
MShocksStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
output << "%" << endl
<< "% MSHOCKS instructions" << endl
<< "%" << endl;
output << "%" << endl << "% MSHOCKS instructions" << endl << "%" << endl;
if (overwrite)
output << "M_.det_shocks = [];" << endl;
......@@ -442,8 +460,8 @@ void
MShocksStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "mshocks")"
<< R"(, "overwrite": )" << boolalpha << overwrite
<< R"(, "relative_to_initval": )" << boolalpha << relative_to_initval;
<< R"(, "overwrite": )" << boolalpha << overwrite << R"(, "relative_to_initval": )"
<< boolalpha << relative_to_initval;
if (!det_shocks.empty())
{
output << ", ";
......@@ -452,10 +470,11 @@ MShocksStatement::writeJsonOutput(ostream &output) const
output << "}";
}
ShocksSurpriseStatement::ShocksSurpriseStatement(bool overwrite_arg,
AbstractShocksStatement::det_shocks_t surprise_shocks_arg,
ShocksSurpriseStatement::ShocksSurpriseStatement(
bool overwrite_arg, AbstractShocksStatement::det_shocks_t surprise_shocks_arg,
const SymbolTable& symbol_table_arg) :
overwrite{overwrite_arg}, surprise_shocks{move(surprise_shocks_arg)},
overwrite {overwrite_arg},
surprise_shocks {move(surprise_shocks_arg)},
symbol_table {symbol_table_arg}
{
}
......@@ -476,11 +495,11 @@ ShocksSurpriseStatement::writeOutput(ostream &output, [[maybe_unused]] const str
else
output << "M_.surprise_shocks = [ M_.surprise_shocks;" << endl;
for (const auto& [id, shock_vec] : surprise_shocks)
for (const auto &[period1, period2, value] : shock_vec)
for (const auto& [period_range, value] : shock_vec)
{
output << "struct('exo_id'," << symbol_table.getTypeSpecificID(id)+1
<< ",'periods'," << period1 << ":" << period2
<< ",'value',";
auto [period1, period2] = get<pair<int, int>>(period_range);
output << "struct('exo_id'," << symbol_table.getTypeSpecificID(id) + 1 << ",'periods',"
<< period1 << ":" << period2 << ",'value',";
value->writeOutput(output);
output << ");" << endl;
}
......@@ -493,16 +512,15 @@ ShocksSurpriseStatement::writeJsonOutput(ostream &output) const
output << R"({"statementName": "shocks")"
<< R"(, "surprise": true)"
<< R"(, "surprise_shocks": [)";
for (bool printed_something{false};
const auto &[id, shock_vec] : surprise_shocks)
for (bool printed_something {false}; const auto& [id, shock_vec] : surprise_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2{false};
const auto &[period1, period2, value] : shock_vec)
for (bool printed_something2 {false}; const auto& [period_range, value] : shock_vec)
{
auto [period1, period2] = get<pair<int, int>>(period_range);
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
......@@ -516,11 +534,14 @@ ShocksSurpriseStatement::writeJsonOutput(ostream &output) const
output << "]}";
}
ShocksLearntInStatement::ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg,
ShocksLearntInStatement::ShocksLearntInStatement(variant<int, string> learnt_in_period_arg,
bool overwrite_arg,
learnt_shocks_t learnt_shocks_arg,
const SymbolTable& symbol_table_arg) :
learnt_in_period{learnt_in_period_arg}, overwrite{overwrite_arg},
learnt_shocks{move(learnt_shocks_arg)}, symbol_table{symbol_table_arg}
learnt_in_period {move(learnt_in_period_arg)},
overwrite {overwrite_arg},
learnt_shocks {move(learnt_shocks_arg)},
symbol_table {symbol_table_arg}
{
}
......@@ -555,18 +576,29 @@ ShocksLearntInStatement::writeOutput(ostream &output, [[maybe_unused]] const str
[[maybe_unused]] bool minimal_workspace) const
{
if (overwrite)
{
output << "if ~isempty(M_.learnt_shocks)" << endl
<< " M_.learnt_shocks = M_.learnt_shocks([M_.learnt_shocks.learnt_in] ~= " << learnt_in_period << ");" << endl
<< "end" << endl;
<< " M_.learnt_shocks = M_.learnt_shocks(cellfun(@(x) ~isa(x, '";
if (holds_alternative<int>(learnt_in_period))
output << "numeric";
else
output << "dates";
output << "') || x ~= ";
/* NB: date expression not parenthesized since it can only contain a + operator, which has
higher precedence than ~= and || */
visit(bind(print_matlab_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << ", {M_.learnt_shocks.learnt_in}));" << endl << "end" << endl;
}
output << "M_.learnt_shocks = [ M_.learnt_shocks;" << endl;
for (const auto& [id, shock_vec] : learnt_shocks)
for (const auto &[type, period1, period2, value] : shock_vec)
for (const auto& [type, period_range, value] : shock_vec)
{
output << "struct('learnt_in'," << learnt_in_period
<< ",'exo_id'," << symbol_table.getTypeSpecificID(id)+1
<< ",'periods'," << period1 << ":" << period2
<< ",'type','" << typeToString(type) << "'"
output << "struct('learnt_in',";
visit(bind(print_matlab_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << ",'exo_id'," << symbol_table.getTypeSpecificID(id) + 1 << ",'periods',";
visit(bind(print_matlab_period_range, ref(output), placeholders::_1), period_range);
output << ",'type','" << typeToString(type) << "'"
<< ",'value',";
value->writeOutput(output);
output << ");" << endl;
......@@ -578,24 +610,22 @@ void
ShocksLearntInStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "shocks")"
<< R"(, "learnt_in": )" << learnt_in_period
<< R"(, "overwrite": )" << boolalpha << overwrite
<< R"(, "learnt_shocks": [)";
for (bool printed_something{false};
const auto &[id, shock_vec] : learnt_shocks)
<< R"(, "learnt_in": )";
visit(bind(print_json_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << R"(, "overwrite": )" << boolalpha << overwrite << R"(, "learnt_shocks": [)";
for (bool printed_something {false}; const auto& [id, shock_vec] : learnt_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2{false};
const auto &[type, period1, period2, value] : shock_vec)
for (bool printed_something2 {false}; const auto& [type, period_range, value] : shock_vec)
{
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("type": ")" << typeToString(type) << R"(", )"
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "type": ")" << typeToString(type) << R"(", )"
<< R"("value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
......@@ -605,22 +635,231 @@ ShocksLearntInStatement::writeJsonOutput(ostream &output) const
output << "]}";
}
ConditionalForecastPathsStatement::ConditionalForecastPathsStatement(AbstractShocksStatement::det_shocks_t paths_arg,
const SymbolTable &symbol_table_arg) :
paths{move(paths_arg)},
HeterogeneousShocksStatement::HeterogeneousShocksStatement(
int heterogeneity_dimension_arg, bool overwrite_arg, var_and_std_shocks_t var_shocks_arg,
var_and_std_shocks_t std_shocks_arg, covar_and_corr_shocks_t covar_shocks_arg,
covar_and_corr_shocks_t corr_shocks_arg, const SymbolTable& symbol_table_arg,
const HeterogeneityTable& heterogeneity_table_arg) :
heterogeneity_dimension {heterogeneity_dimension_arg},
overwrite {overwrite_arg},
var_shocks {move(var_shocks_arg)},
std_shocks {move(std_shocks_arg)},
covar_shocks {move(covar_shocks_arg)},
corr_shocks {move(corr_shocks_arg)},
symbol_table {symbol_table_arg},
path_length{computePathLength(paths)}
heterogeneity_table {heterogeneity_table_arg}
{
}
void
HeterogeneousShocksStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
if (overwrite)
output << sigmaeName() << " = zeros(" << symbol_table.het_exo_nbr(heterogeneity_dimension)
<< ", " << symbol_table.het_exo_nbr(heterogeneity_dimension) << ");" << endl;
writeVarAndStdShocks(output);
writeCovarAndCorrShocks(output);
}
void
HeterogeneousShocksStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "shocks")"
<< R"(, "heterogeneity": ")" << heterogeneity_table.getName(heterogeneity_dimension)
<< R"(", "overwrite": )" << boolalpha << overwrite;
output << R"(, "variance": [)";
for (bool printed_something {false}; auto& [id, value] : var_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"name": ")" << symbol_table.getName(id) << R"(", )"
<< R"("variance": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
output << "]"
<< R"(, "stderr": [)";
for (bool printed_something {false}; auto& [id, value] : std_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"name": ")" << symbol_table.getName(id) << R"(", )"
<< R"("stderr": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
output << "]"
<< R"(, "covariance": [)";
for (bool printed_something {false}; auto& [ids, value] : covar_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << "{"
<< R"("name": ")" << symbol_table.getName(ids.first) << R"(", )"
<< R"("name2": ")" << symbol_table.getName(ids.second) << R"(", )"
<< R"("covariance": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
output << "]"
<< R"(, "correlation": [)";
for (bool printed_something {false}; auto& [ids, value] : corr_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << "{"
<< R"("name": ")" << symbol_table.getName(ids.first) << R"(", )"
<< R"("name2": ")" << symbol_table.getName(ids.second) << R"(", )"
<< R"("correlation": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
output << "]"
<< "}";
}
void
HeterogeneousShocksStatement::writeVarOrStdShock(ostream& output, const pair<int, expr_t>& it,
bool stddev) const
{
SymbolType type = symbol_table.getType(it.first);
assert(type == SymbolType::heterogeneousExogenous);
int id {symbol_table.getTypeSpecificID(it.first) + 1};
output << sigmaeName() << "(" << id << ", " << id << ") = ";
if (stddev)
output << "(";
it.second->writeOutput(output);
if (stddev)
output << ")^2";
output << ";" << endl;
}
void
HeterogeneousShocksStatement::writeVarAndStdShocks(ostream& output) const
{
for (const auto& it : var_shocks)
writeVarOrStdShock(output, it, false);
for (const auto& it : std_shocks)
writeVarOrStdShock(output, it, true);
}
void
HeterogeneousShocksStatement::writeCovarOrCorrShock(ostream& output,
const pair<pair<int, int>, expr_t>& it,
bool corr) const
{
assert(symbol_table.getType(it.first.first) == SymbolType::heterogeneousExogenous
&& symbol_table.getType(it.first.second) == SymbolType::heterogeneousExogenous);
int id1 {symbol_table.getTypeSpecificID(it.first.first) + 1},
id2 {symbol_table.getTypeSpecificID(it.first.second) + 1};
output << sigmaeName() << "(" << id1 << ", " << id2 << ") = ";
it.second->writeOutput(output);
if (corr)
output << "*sqrt(" << sigmaeName() << "(" << id1 << ", " << id1 << ")*" << sigmaeName() << "("
<< id2 << ", " << id2 << "))";
output << ";" << endl
<< sigmaeName() << "(" << id2 << ", " << id1 << ") = " << sigmaeName() << "(" << id1
<< ", " << id2 << ");" << endl;
}
void
HeterogeneousShocksStatement::writeCovarAndCorrShocks(ostream& output) const
{
for (const auto& it : covar_shocks)
writeCovarOrCorrShock(output, it, false);
for (const auto& it : corr_shocks)
writeCovarOrCorrShock(output, it, true);
}
void
HeterogeneousShocksStatement::checkPass(ModFileStructure& mod_file_struct,
[[maybe_unused]] WarningConsolidation& warnings)
{
/* Error out if variables are not of the right type. This must be done here
and not at parsing time (see #448). */
for (auto [id, val] : var_shocks)
if (symbol_table.getType(id) != SymbolType::heterogeneousExogenous)
{
cerr << "shocks: setting a variance on '" << symbol_table.getName(id)
<< "' is not allowed, because it is not a heterogeneous exogenous variable" << endl;
exit(EXIT_FAILURE);
}
for (auto [id, val] : std_shocks)
if (symbol_table.getType(id) != SymbolType::heterogeneousExogenous)
{
cerr << "shocks: setting a standard error on '" << symbol_table.getName(id)
<< "' is not allowed, because it is not a heterogeneous exogenous variable" << endl;
exit(EXIT_FAILURE);
}
for (const auto& [ids, val] : covar_shocks)
{
auto& [symb_id1, symb_id2] = ids;
if (!(symbol_table.getType(symb_id1) == SymbolType::heterogeneousExogenous
&& symbol_table.getType(symb_id2) == SymbolType::heterogeneousExogenous))
{
cerr << "shocks: setting a covariance between '" << symbol_table.getName(symb_id1)
<< "' and '" << symbol_table.getName(symb_id2)
<< "'is not allowed; covariances can only be specified for heterogeneous exogenous "
"variables"
<< endl;
exit(EXIT_FAILURE);
}
}
for (const auto& [ids, val] : corr_shocks)
{
auto& [symb_id1, symb_id2] = ids;
if (!(symbol_table.getType(symb_id1) == SymbolType::heterogeneousExogenous
&& symbol_table.getType(symb_id2) == SymbolType::heterogeneousExogenous))
{
cerr << "shocks: setting a correlation between '" << symbol_table.getName(symb_id1)
<< "' and '" << symbol_table.getName(symb_id2)
<< "'is not allowed; covariances can only be specified for heterogeneous exogenous "
"variables"
<< endl;
exit(EXIT_FAILURE);
}
}
// Fill in mod_file_struct.parameters_with_shocks_values (related to #469)
for (auto [id, val] : var_shocks)
val->collectVariables(SymbolType::parameter, mod_file_struct.parameters_within_shocks_values);
for (auto [id, val] : std_shocks)
val->collectVariables(SymbolType::parameter, mod_file_struct.parameters_within_shocks_values);
for (const auto& [ids, val] : covar_shocks)
val->collectVariables(SymbolType::parameter, mod_file_struct.parameters_within_shocks_values);
for (const auto& [ids, val] : corr_shocks)
val->collectVariables(SymbolType::parameter, mod_file_struct.parameters_within_shocks_values);
}
ConditionalForecastPathsStatement::ConditionalForecastPathsStatement(
AbstractShocksStatement::det_shocks_t paths_arg, const SymbolTable& symbol_table_arg) :
paths {move(paths_arg)}, symbol_table {symbol_table_arg}, path_length {computePathLength(paths)}
{
}
int
ConditionalForecastPathsStatement::computePathLength(const AbstractShocksStatement::det_shocks_t &paths)
ConditionalForecastPathsStatement::computePathLength(
const AbstractShocksStatement::det_shocks_t& paths)
{
int length {0};
for (const auto& [ignore, elems] : paths)
for (auto &[period1, period2, value] : elems)
for (auto& [period_range, value] : elems)
{
auto [period1, period2] = get<pair<int, int>>(period_range);
// Period1 < Period2, as enforced in ParsingDriver::add_period()
length = max(length, period2);
}
return length;
}
......@@ -633,17 +872,17 @@ ConditionalForecastPathsStatement::writeOutput(ostream &output,
output << "constrained_vars_ = [];" << endl
<< "constrained_paths_ = NaN(" << paths.size() << ", " << path_length << ");" << endl;
for (int k{1};
const auto &[id, elems] : paths)
for (int k {1}; const auto& [id, elems] : paths)
{
if (k == 1)
output << "constrained_vars_ = " << symbol_table.getTypeSpecificID(id) + 1 << ";" << endl;
else
output << "constrained_vars_ = [constrained_vars_; " << symbol_table.getTypeSpecificID(id) + 1 << "];" << endl;
for (const auto &[period1, period2, value] : elems)
for (int j = period1; j <= period2; j++)
output << "constrained_vars_ = [constrained_vars_; "
<< symbol_table.getTypeSpecificID(id) + 1 << "];" << endl;
for (const auto& [period_range, value] : elems)
{
output << "constrained_paths_(" << k << "," << j << ")=";
auto [period1, period2] = get<pair<int, int>>(period_range);
output << "constrained_paths_(" << k << "," << period1 << ":" << period2 << ")=";
value->writeOutput(output);
output << ";" << endl;
}
......@@ -656,21 +895,19 @@ ConditionalForecastPathsStatement::writeJsonOutput(ostream &output) const
{
output << R"({"statementName": "conditional_forecast_paths")"
<< R"(, "paths": [)";
for (bool printed_something{false};
const auto &[id, elems] : paths)
for (bool printed_something {false}; const auto& [id, elems] : paths)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2{false};
const auto &[period1, period2, value] : elems)
for (bool printed_something2 {false}; const auto& [period_range, value] : elems)
{
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("value": ")";
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -679,9 +916,68 @@ ConditionalForecastPathsStatement::writeJsonOutput(ostream &output) const
output << "]}";
}
PerfectForesightControlledPathsStatement::PerfectForesightControlledPathsStatement(
paths_t paths_arg, variant<int, string> learnt_in_period_arg,
const SymbolTable& symbol_table_arg) :
paths {move(paths_arg)},
learnt_in_period {move(learnt_in_period_arg)},
symbol_table {symbol_table_arg}
{
}
void
PerfectForesightControlledPathsStatement::writeOutput(ostream& output,
[[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
for (const auto& [exogenize_id, constraints, endogenize_id] : paths)
for (const auto& [period_range, value] : constraints)
{
output << "M_.perfect_foresight_controlled_paths = [ "
"M_.perfect_foresight_controlled_paths;"
<< endl
<< "struct('exogenize_id'," << symbol_table.getTypeSpecificID(exogenize_id) + 1
<< ",'periods',";
visit(bind(print_matlab_period_range, ref(output), placeholders::_1), period_range);
output << ",'value',";
value->writeOutput(output);
output << ",'endogenize_id'," << symbol_table.getTypeSpecificID(endogenize_id) + 1
<< ",'learnt_in',";
visit(bind(print_matlab_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << ") ];" << endl;
}
}
void
PerfectForesightControlledPathsStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "perfect_foresight_controlled_paths")"
<< R"(, "paths": [)";
for (bool printed_something {false};
const auto& [exogenize_id, constraints, endogenize_id] : paths)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"exogenize": ")" << symbol_table.getName(exogenize_id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2 {false}; const auto& [period_range, value] : constraints)
{
if (exchange(printed_something2, true))
output << ", ";
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
output << R"(], "endogenize": ")" << symbol_table.getName(endogenize_id) << R"("})";
}
output << "]}";
}
MomentCalibration::MomentCalibration(constraints_t constraints_arg,
const SymbolTable &symbol_table_arg)
: constraints{move(constraints_arg)}, symbol_table{symbol_table_arg}
const SymbolTable& symbol_table_arg) :
constraints {move(constraints_arg)}, symbol_table {symbol_table_arg}
{
}
......@@ -693,14 +989,12 @@ MomentCalibration::writeOutput(ostream &output, [[maybe_unused]] const string &b
for (const auto& c : constraints)
{
output << "'" << symbol_table.getName(c.endo1) << "', "
<< "'" << symbol_table.getName(c.endo2) << "', "
<< c.lags << ", "
<< "'" << symbol_table.getName(c.endo2) << "', " << c.lags << ", "
<< "[ ";
c.lower_bound->writeOutput(output);
output << ", ";
c.upper_bound->writeOutput(output);
output << " ];"
<< endl;
output << " ];" << endl;
}
output << "};" << endl;
}
......@@ -710,8 +1004,7 @@ MomentCalibration::writeJsonOutput(ostream &output) const
{
output << R"({"statementName": "moment_calibration")"
<< R"(, "moment_calibration_criteria": [)";
for (bool printed_something{false};
const auto &c : constraints)
for (bool printed_something {false}; const auto& c : constraints)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -730,10 +1023,11 @@ MomentCalibration::writeJsonOutput(ostream &output) const
<< "}";
}
IrfCalibration::IrfCalibration(constraints_t constraints_arg,
const SymbolTable &symbol_table_arg,
OptionsList options_list_arg)
: constraints{move(constraints_arg)}, symbol_table{symbol_table_arg}, options_list{move(options_list_arg)}
IrfCalibration::IrfCalibration(constraints_t constraints_arg, const SymbolTable& symbol_table_arg,
OptionsList options_list_arg) :
constraints {move(constraints_arg)},
symbol_table {symbol_table_arg},
options_list {move(options_list_arg)}
{
}
......@@ -747,14 +1041,12 @@ IrfCalibration::writeOutput(ostream &output, [[maybe_unused]] const string &base
for (const auto& c : constraints)
{
output << "'" << symbol_table.getName(c.endo) << "', "
<< "'" << symbol_table.getName(c.exo) << "', "
<< c.periods << ", "
<< "'" << symbol_table.getName(c.exo) << "', " << c.periods << ", "
<< "[ ";
c.lower_bound->writeOutput(output);
output << ", ";
c.upper_bound->writeOutput(output);
output << " ];"
<< endl;
output << " ];" << endl;
}
output << "};" << endl;
}
......@@ -770,8 +1062,7 @@ IrfCalibration::writeJsonOutput(ostream &output) const
}
output << R"(, "irf_restrictions": [)";
for (bool printed_something{false};
const auto &c : constraints)
for (bool printed_something {false}; const auto& c : constraints)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -790,8 +1081,8 @@ IrfCalibration::writeJsonOutput(ostream &output) const
<< "}";
}
ShockGroupsStatement::ShockGroupsStatement(group_t shock_groups_arg, string name_arg)
: shock_groups{move(shock_groups_arg)}, name{move(name_arg)}
ShockGroupsStatement::ShockGroupsStatement(group_t shock_groups_arg, string name_arg) :
shock_groups {move(shock_groups_arg)}, name {move(name_arg)}
{
}
......@@ -814,10 +1105,9 @@ ShockGroupsStatement::writeOutput(ostream &output, [[maybe_unused]] const string
if (unique_label)
{
output << "M_.shock_groups." << name
<< ".group" << i << ".label = '" << it->name << "';" << endl
<< "M_.shock_groups." << name
<< ".group" << i << ".shocks = {";
output << "M_.shock_groups." << name << ".group" << i << ".label = '" << it->name << "';"
<< endl
<< "M_.shock_groups." << name << ".group" << i << ".shocks = {";
for (const auto& it1 : it->list)
output << " '" << it1 << "'";
output << "};" << endl;
......@@ -847,8 +1137,7 @@ ShockGroupsStatement::writeJsonOutput(ostream &output) const
output << ", ";
output << R"({"group_name": ")" << it->name << R"(",)"
<< R"("shocks": [)";
for (bool printed_something2{false};
const auto &it1 : it->list)
for (bool printed_something2 {false}; const auto& it1 : it->list)
{
if (exchange(printed_something2, true))
output << ", ";
......@@ -861,8 +1150,8 @@ ShockGroupsStatement::writeJsonOutput(ostream &output) const
}
Init2shocksStatement::Init2shocksStatement(vector<pair<int, int>> init2shocks_arg, string name_arg,
const SymbolTable &symbol_table_arg)
: init2shocks{move(init2shocks_arg)}, name{move(name_arg)}, symbol_table{symbol_table_arg}
const SymbolTable& symbol_table_arg) :
init2shocks {move(init2shocks_arg)}, name {move(name_arg)}, symbol_table {symbol_table_arg}
{
}
......@@ -887,7 +1176,8 @@ Init2shocksStatement::writeOutput(ostream &output, [[maybe_unused]] const string
{
output << "M_.init2shocks." << name << " = {" << endl;
for (const auto& [id1, id2] : init2shocks)
output << "{'" << symbol_table.getName(id1) << "', '" << symbol_table.getName(id2) << "'};" << endl;
output << "{'" << symbol_table.getName(id1) << "', '" << symbol_table.getName(id2) << "'};"
<< endl;
output << "};" << endl;
}
......@@ -895,8 +1185,7 @@ void
Init2shocksStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "init2shocks", "name": ")" << name << R"(", "groups": [)";
for (bool printed_something{false};
const auto &[id1, id2] : init2shocks)
for (bool printed_something {false}; const auto& [id1, id2] : init2shocks)
{
if (exchange(printed_something, true))
output << ",";
......@@ -906,17 +1195,19 @@ Init2shocksStatement::writeJsonOutput(ostream &output) const
output << "]}";
}
HeteroskedasticShocksStatement::HeteroskedasticShocksStatement(bool overwrite_arg,
heteroskedastic_shocks_t values_arg,
heteroskedastic_shocks_t scales_arg,
const SymbolTable &symbol_table_arg)
: overwrite{overwrite_arg}, values{move(values_arg)}, scales{move(scales_arg)},
HeteroskedasticShocksStatement::HeteroskedasticShocksStatement(
bool overwrite_arg, heteroskedastic_shocks_t values_arg, heteroskedastic_shocks_t scales_arg,
const SymbolTable& symbol_table_arg) :
overwrite {overwrite_arg},
values {move(values_arg)},
scales {move(scales_arg)},
symbol_table {symbol_table_arg}
{
}
void
HeteroskedasticShocksStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basename,
HeteroskedasticShocksStatement::writeOutput(ostream& output,
[[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
// NB: The first initialization of the fields is done in ModFile::writeMOutput()
......@@ -928,9 +1219,9 @@ HeteroskedasticShocksStatement::writeOutput(ostream &output, [[maybe_unused]] co
for (int tsid = symbol_table.getTypeSpecificID(symb_id);
const auto& [period1, period2, value] : vec)
{
output << "M_.heteroskedastic_shocks.Qvalue_orig = [M_.heteroskedastic_shocks.Qvalue_orig; struct('exo_id', "
<< tsid+1 << ",'periods',"
<< period1 << ":" << period2 << ",'value',";
output << "M_.heteroskedastic_shocks.Qvalue_orig = [M_.heteroskedastic_shocks.Qvalue_orig; "
"struct('exo_id', "
<< tsid + 1 << ",'periods'," << period1 << ":" << period2 << ",'value',";
value->writeOutput(output);
output << ")];" << endl;
}
......@@ -938,9 +1229,9 @@ HeteroskedasticShocksStatement::writeOutput(ostream &output, [[maybe_unused]] co
for (int tsid = symbol_table.getTypeSpecificID(symb_id);
const auto& [period1, period2, scale] : vec)
{
output << "M_.heteroskedastic_shocks.Qscale_orig = [M_.heteroskedastic_shocks.Qscale_orig; struct('exo_id', "
<< tsid+1 << ",'periods',"
<< period1 << ":" << period2 << ",'scale',";
output << "M_.heteroskedastic_shocks.Qscale_orig = [M_.heteroskedastic_shocks.Qscale_orig; "
"struct('exo_id', "
<< tsid + 1 << ",'periods'," << period1 << ":" << period2 << ",'scale',";
scale->writeOutput(output);
output << ")];" << endl;
}
......@@ -950,17 +1241,14 @@ void
HeteroskedasticShocksStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "heteroskedastic_shocks")"
<< R"(, "overwrite": )" << boolalpha << overwrite
<< R"(, "shocks_values": [)";
for (bool printed_something{false};
const auto &[symb_id, vec] : values)
<< R"(, "overwrite": )" << boolalpha << overwrite << R"(, "shocks_values": [)";
for (bool printed_something {false}; const auto& [symb_id, vec] : values)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(symb_id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2{false};
const auto &[period1, period2, value] : vec)
for (bool printed_something2 {false}; const auto& [period1, period2, value] : vec)
{
if (exchange(printed_something2, true))
output << ", ";
......@@ -973,15 +1261,13 @@ HeteroskedasticShocksStatement::writeJsonOutput(ostream &output) const
output << "]}";
}
output << R"(], "shocks_scales": [)";
for (bool printed_something{false};
const auto &[symb_id, vec] : scales)
for (bool printed_something {false}; const auto& [symb_id, vec] : scales)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(symb_id) << R"(", )"
<< R"("scales": [)";
for (bool printed_something2{false};
const auto &[period1, period2, value] : vec)
for (bool printed_something2 {false}; const auto& [period1, period2, value] : vec)
{
if (exchange(printed_something2, true))
output << ", ";
......
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,30 +17,37 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SHOCKS_HH
#define _SHOCKS_HH
#ifndef SHOCKS_HH
#define SHOCKS_HH
#include <map>
#include <string>
#include <variant>
#include <vector>
#include <map>
#include "ExprNode.hh"
#include "HeterogeneityTable.hh"
#include "Statement.hh"
#include "SymbolTable.hh"
#include "ExprNode.hh"
using namespace std;
class AbstractShocksStatement : public Statement
{
public:
// The tuple is (period1, period2, value)
using det_shocks_t = map<int, vector<tuple<int, int, expr_t>>>;
// A period range is either two indices (1-based), or two dates (from dseries)
using period_range_t = variant<pair<int, int>, pair<string, string>>;
// The pair is (period range, value)
using det_shocks_t = map<int, vector<pair<period_range_t, expr_t>>>;
enum class ShockType
{
level, // The value is the level of the exogenous (“values” statement in “shocks”)
multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state (“values” statement in “mshocks”)
multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady state (“values” statement in “mshocks(relative_to_initval)”)
multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state
// (“values” statement in “mshocks”)
multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady
// state (“values” statement in “mshocks(relative_to_initval)”)
};
protected:
//! Does this "shocks" statement replace the previous ones?
const bool overwrite;
......@@ -51,8 +58,7 @@ protected:
void writeJsonDetShocks(ostream& output) const;
static string typeToString(ShockType type);
AbstractShocksStatement(bool overwrite_arg, ShockType type_arg,
det_shocks_t det_shocks_arg,
AbstractShocksStatement(bool overwrite_arg, ShockType type_arg, det_shocks_t det_shocks_arg,
const SymbolTable& symbol_table_arg);
};
......@@ -61,21 +67,21 @@ class ShocksStatement : public AbstractShocksStatement
public:
using var_and_std_shocks_t = map<int, expr_t>;
using covar_and_corr_shocks_t = map<pair<int, int>, expr_t>;
private:
const var_and_std_shocks_t var_shocks, std_shocks;
const covar_and_corr_shocks_t covar_shocks, corr_shocks;
void writeVarOrStdShock(ostream& output, const pair<int, expr_t>& it, bool stddev) const;
void writeVarAndStdShocks(ostream& output) const;
void writeCovarOrCorrShock(ostream &output, const pair<pair<int, int>, expr_t> &it, bool corr) const;
void writeCovarOrCorrShock(ostream& output, const pair<pair<int, int>, expr_t>& it,
bool corr) const;
void writeCovarAndCorrShocks(ostream& output) const;
bool has_calibrated_measurement_errors() const;
[[nodiscard]] bool has_calibrated_measurement_errors() const;
public:
ShocksStatement(bool overwrite_arg,
det_shocks_t det_shocks_arg,
var_and_std_shocks_t var_shocks_arg,
var_and_std_shocks_t std_shocks_arg,
covar_and_corr_shocks_t covar_shocks_arg,
covar_and_corr_shocks_t corr_shocks_arg,
ShocksStatement(bool overwrite_arg, det_shocks_t det_shocks_arg,
var_and_std_shocks_t var_shocks_arg, var_and_std_shocks_t std_shocks_arg,
covar_and_corr_shocks_t covar_shocks_arg, covar_and_corr_shocks_t corr_shocks_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -86,8 +92,7 @@ class MShocksStatement : public AbstractShocksStatement
{
public:
const bool relative_to_initval;
MShocksStatement(bool overwrite_arg, bool relative_to_initval_arg,
det_shocks_t det_shocks_arg,
MShocksStatement(bool overwrite_arg, bool relative_to_initval_arg, det_shocks_t det_shocks_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -102,8 +107,10 @@ public:
//! Does this "shocks(surprise)" statement replace the previous ones?
const bool overwrite;
const AbstractShocksStatement::det_shocks_t surprise_shocks;
private:
const SymbolTable& symbol_table;
public:
ShocksSurpriseStatement(bool overwrite_arg,
AbstractShocksStatement::det_shocks_t surprise_shocks_arg,
......@@ -119,27 +126,76 @@ public:
class ShocksLearntInStatement : public Statement
{
public:
const int learnt_in_period;
const variant<int, string> learnt_in_period;
//! Does this “shocks(learnt_in=…)” or “mshocks(learnt_in=…)” block replace the previous ones?
const bool overwrite;
enum class LearntShockType
{
level, // The value is the level of the exogenous (“values” statement in “shocks(learnt_in=…)”)
add, // The value is the additive change of the exogenous compared to previous information period (“add” statement in “shocks(learnt_in=…)”)
multiply, // The value is the multiplicative change of the exogenous compared to previous information period (“multiply” statement in “shocks(learnt_in=…)”)
multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state as anticipated in the same informational period (“values” statement in “mshocks(learnt_in=…)”)
multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady state as anticipated in the same informational period (“values” statement in “mshocks(learnt_in=…, relative_to_initval)”)
add, // The value is the additive change of the exogenous compared to previous information
// period (“add” statement in “shocks(learnt_in=…)”)
multiply, // The value is the multiplicative change of the exogenous compared to previous
// information period (“multiply” statement in “shocks(learnt_in=…)”)
multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state
// as anticipated in the same informational period (“values” statement in
// “mshocks(learnt_in=…)”)
multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady
// state as anticipated in the same informational period (“values”
// statement in “mshocks(learnt_in=…, relative_to_initval)”)
};
// The tuple is (type, period1, period2, value)
using learnt_shocks_t = map<int, vector<tuple<LearntShockType, int, int, expr_t>>>;
// The tuple is (type, period range, value)
using learnt_shocks_t
= map<int, vector<tuple<LearntShockType, AbstractShocksStatement::period_range_t, expr_t>>>;
const learnt_shocks_t learnt_shocks;
private:
const SymbolTable& symbol_table;
static string typeToString(LearntShockType type);
public:
ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg,
learnt_shocks_t learnt_shocks_arg,
const SymbolTable &symbol_table_arg);
ShocksLearntInStatement(variant<int, string> learnt_in_period_arg, bool overwrite_arg,
learnt_shocks_t learnt_shocks_arg, const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class HeterogeneousShocksStatement : public Statement
{
public:
const int heterogeneity_dimension;
const bool overwrite;
using var_and_std_shocks_t = map<int, expr_t>;
using covar_and_corr_shocks_t = map<pair<int, int>, expr_t>;
const var_and_std_shocks_t var_shocks, std_shocks;
const covar_and_corr_shocks_t covar_shocks, corr_shocks;
private:
const SymbolTable& symbol_table;
const HeterogeneityTable& heterogeneity_table;
void writeVarOrStdShock(ostream& output, const pair<int, expr_t>& it, bool stddev) const;
void writeVarAndStdShocks(ostream& output) const;
void writeCovarOrCorrShock(ostream& output, const pair<pair<int, int>, expr_t>& it,
bool corr) const;
void writeCovarAndCorrShocks(ostream& output) const;
string
sigmaeName() const
{
return "M_.heterogeneity("s + to_string(heterogeneity_dimension + 1) + ").Sigma_e"s;
}
public:
HeterogeneousShocksStatement(int heterogeneity_dimension_arg, bool overwrite_arg,
var_and_std_shocks_t var_shocks_arg,
var_and_std_shocks_t std_shocks_arg,
covar_and_corr_shocks_t covar_shocks_arg,
covar_and_corr_shocks_t corr_shocks_arg,
const SymbolTable& symbol_table_arg,
const HeterogeneityTable& heterogeneity_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -151,6 +207,7 @@ private:
const AbstractShocksStatement::det_shocks_t paths;
const SymbolTable& symbol_table;
const int path_length;
public:
ConditionalForecastPathsStatement(AbstractShocksStatement::det_shocks_t paths_arg,
const SymbolTable& symbol_table_arg);
......@@ -159,6 +216,26 @@ public:
static int computePathLength(const AbstractShocksStatement::det_shocks_t& paths);
};
class PerfectForesightControlledPathsStatement : public Statement
{
public:
// (exogenize_id, vector of (period range, value), endogenize_id)
using paths_t
= vector<tuple<int, vector<pair<AbstractShocksStatement::period_range_t, expr_t>>, int>>;
private:
const paths_t paths;
const variant<int, string> learnt_in_period;
const SymbolTable& symbol_table;
public:
PerfectForesightControlledPathsStatement(paths_t paths_arg,
variant<int, string> learnt_in_period_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class MomentCalibration : public Statement
{
public:
......@@ -169,12 +246,13 @@ public:
expr_t lower_bound, upper_bound;
};
using constraints_t = vector<Constraint>;
private:
constraints_t constraints;
const SymbolTable& symbol_table;
public:
MomentCalibration(constraints_t constraints_arg,
const SymbolTable &symbol_table_arg);
MomentCalibration(constraints_t constraints_arg, const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -190,13 +268,14 @@ public:
expr_t lower_bound, upper_bound;
};
using constraints_t = vector<Constraint>;
private:
constraints_t constraints;
const SymbolTable& symbol_table;
const OptionsList options_list;
public:
IrfCalibration(constraints_t constraints_arg,
const SymbolTable &symbol_table_arg,
IrfCalibration(constraints_t constraints_arg, const SymbolTable& symbol_table_arg,
OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -211,9 +290,11 @@ public:
vector<string> list;
};
using group_t = vector<Group>;
private:
group_t shock_groups;
string name;
public:
ShockGroupsStatement(group_t shock_groups_arg, string name_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -226,8 +307,10 @@ private:
const vector<pair<int, int>> init2shocks;
const string name;
const SymbolTable& symbol_table;
public:
Init2shocksStatement(vector<pair<int, int>> init2shocks_arg, string name_arg, const SymbolTable &symbol_table_arg);
Init2shocksStatement(vector<pair<int, int>> init2shocks_arg, string name_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -238,10 +321,12 @@ class HeteroskedasticShocksStatement : public Statement
public:
// Maps exo symb_id to list of tuples (period1, period2, value/scale)
using heteroskedastic_shocks_t = map<int, vector<tuple<int, int, expr_t>>>;
private:
const bool overwrite;
const heteroskedastic_shocks_t values, scales;
const SymbolTable& symbol_table;
public:
HeteroskedasticShocksStatement(bool overwrite_arg, heteroskedastic_shocks_t values_arg,
heteroskedastic_shocks_t scales_arg,
......
/*
* Copyright © 2006-2022 Dynare Team
* Copyright © 2006-2023 Dynare Team
*
* This file is part of Dynare.
*
......@@ -45,7 +45,16 @@ NativeStatement::writeOutput(ostream &output, [[maybe_unused]] const string &bas
[[maybe_unused]] bool minimal_workspace) const
{
using namespace boost::xpressive;
string date_regex = R"((-?\d+([YyAa]|[Mm]([1-9]|1[0-2])|[Qq][1-4]|[SsHh][1-2])))";
/* NB: in date_regex, for monthly dates, “1[0-2]” must come before “[1-9]” in the alternative,
otherwise 2023M12 will be matched as 2023M1 (see dynare#1918). Technically, it seems that
boost::xpressive does not look for the longest match in an alternation, but stops at the first
match from left to right. */
string date_regex = R"((-?\d+([YyAa]|[Mm](1[0-2]|[1-9])|[Qq][1-4]|[SsHh][12])))";
/* NB: the following dance around the dollar sign (exclude it from lookbehind, then use it in a
temporary string after the first replace, then remove it in the second replace) has a purpose:
it allows the user to disable the substitution mechanism. For example, if the user writes
“$2024Q4” in a native statement, it will be transformed into “2024Q4” and not
“$dates('2024Q4')”. */
sregex regex_lookbehind = sregex::compile(R"((?<!\$|\d|[a-zA-Z_]|-|'))" + date_regex);
sregex regex_dollar = sregex::compile(R"((\$))" + date_regex);
......@@ -168,10 +177,10 @@ void
OptionsList::writeOutput(ostream& output, const string& option_group) const
{
// Initialize option_group as an empty struct iff the field does not exist!
if (size_t idx = option_group.find_last_of(".");
idx != string::npos)
if (size_t idx = option_group.find_last_of('.'); idx != string::npos)
{
output << "if ~isfield(" << option_group.substr(0, idx) << ",'" << option_group.substr(idx+1) << "')" << endl;
output << "if ~isfield(" << option_group.substr(0, idx) << ",'"
<< option_group.substr(idx + 1) << "')" << endl;
output << " " << option_group << " = struct();" << endl;
output << "end" << endl;
}
......@@ -184,9 +193,10 @@ OptionsList::writeOutput(ostream &output, const string &option_group) const
void
OptionsList::writeOutputCommon(ostream& output, const string& option_group) const
{
// NOLINTBEGIN(clang-analyzer-core.CallAndMessage)
for (const auto& [name, val] : options)
std::visit([&]<class T>(const T &v)
{
std::visit(
[&]<class T>(const T& v) {
if constexpr (is_same_v<T, SymbolListVal>)
v.writeOutput(option_group + "." + name, output);
else
......@@ -259,7 +269,9 @@ OptionsList::writeOutputCommon(ostream &output, const string &option_group) cons
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
output << ";" << endl;
}
}, val);
},
val);
// NOLINTEND(clang-analyzer-core.CallAndMessage)
}
void
......@@ -270,14 +282,13 @@ OptionsList::writeJsonOutput(ostream &output) const
output << R"("options": {)";
for (bool opt_written {false};
const auto &[name, val] : options)
for (bool opt_written {false}; const auto& [name, val] : options)
{
if (exchange(opt_written, true))
output << ", ";
output << R"(")" << name << R"(": )";
std::visit([&]<class T>(const T &v)
{
std::visit(
[&]<class T>(const T& v) {
if constexpr (is_same_v<T, NumVal>)
output << v;
else if constexpr (is_same_v<T, pair<string, string>>)
......@@ -295,8 +306,7 @@ OptionsList::writeJsonOutput(ostream &output) const
|| is_same_v<T, vector<vector<string>>>)
{
output << '[';
for (bool printed_something{false};
const auto &it : v)
for (bool printed_something {false}; const auto& it : v)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -307,8 +317,7 @@ OptionsList::writeJsonOutput(ostream &output) const
else // vector<vector<string>>
{
output << '[';
for (bool printed_something2{false};
const auto &it2 : it)
for (bool printed_something2 {false}; const auto& it2 : it)
{
if (exchange(printed_something2, true))
output << ", ";
......@@ -321,7 +330,8 @@ OptionsList::writeJsonOutput(ostream &output) const
}
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
}, val);
},
val);
}
output << "}";
......
/*
* Copyright © 2006-2023 Dynare Team
* Copyright © 2006-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,19 +17,23 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _STATEMENT_HH
#define _STATEMENT_HH
#ifndef STATEMENT_HH
#define STATEMENT_HH
#include <ostream>
#include <string>
#include <map>
#include <set>
#include <optional>
#include <ostream>
#include <set>
#include <string>
#include <variant>
#include "SymbolList.hh"
#include "WarningConsolidation.hh"
// Helper constant for visitors
template<class>
inline constexpr bool always_false_v {false};
struct ModFileStructure
{
//! Whether check is present
......@@ -60,13 +64,15 @@ struct ModFileStructure
bool extended_path_present {false};
//! The value of the "order" option of stoch_simul, estimation, osr, ramsey_policy
//! Derivation order
/*! First initialized to zero. If user sets order option somewhere in the MOD file, it will be equal to the maximum of order options. Otherwise will default to 2 */
/*! First initialized to zero. If user sets order option somewhere in the MOD file, it will be
* equal to the maximum of order options. Otherwise will default to 2 */
int order_option {0};
//! Whether a bvar_density, bvar_forecast, sbvar, ms_sbvar statement is present
bool bvar_present {false};
//! Whether an svar_identification statement is present
bool svar_identification_present {false};
//! Whether an identification statement is present or the identification option of dynare_sensitivity statement is equal to one
//! Whether an identification statement is present or the identification option of
//! dynare_sensitivity statement is equal to one
bool identification_present {false};
//! The maximum of the “order” option in identification statements
int identification_order {0};
......@@ -167,8 +173,6 @@ struct ModFileStructure
bool endval_learnt_in_present {false};
// Whether an occbin_constraints block appears
bool occbin_constraints_present {false};
// Whether a ramsey_constraints block appears
bool ramsey_constraints_present{false};
};
class Statement
......@@ -190,9 +194,11 @@ public:
//! Write Matlab output code
/*!
\param output is the output stream of the main matlab file
\param basename is the name of the modfile (without extension) which can be used to build auxiliary files
\param basename is the name of the modfile (without extension) which can be used to build
auxiliary files
*/
virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const = 0;
virtual void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const
= 0;
virtual void writeJsonOutput(ostream& output) const = 0;
};
......@@ -200,6 +206,7 @@ class NativeStatement : public Statement
{
private:
const string native_statement;
public:
explicit NativeStatement(string native_statement_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -210,6 +217,7 @@ class VerbatimStatement : public Statement
{
private:
const string verbatim_statement;
public:
explicit VerbatimStatement(string verbatim_statement_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -248,10 +256,16 @@ public:
{
};
bool empty() const;
// pair<string, string> corresponds to a pair of numerical values
// vector<vector<string>> corresponds to a vector of vectors of numerical values
using OptionValue
= variant<NumVal, pair<string, string>, StringVal, DateVal, SymbolListVal, vector<int>,
VecStrVal, VecCellStrVal, VecValueVal, vector<vector<string>>>;
[[nodiscard]] bool empty() const;
void clear();
// Whether there is an option with that name that has been given a value
bool contains(const string &name) const;
[[nodiscard]] bool contains(const string& name) const;
// Erase the option with that name
void erase(const string& name);
......@@ -275,7 +289,8 @@ public:
/* Retrieves the value of the option with that name.
Throws UnknownOptionException if there is no option with that name.
Throws bad_variant_access if the option has a value of a different type. */
template<class T>
template<typename T>
requires requires(T p) { std::get<T>(OptionValue {}); }
T
get(const string& name) const
{
......@@ -289,7 +304,8 @@ public:
/* Retrieves the value of the option with that name.
Returns nullopt if there is no option with that name.
Throws bad_variant_access if the option has a value of a different type. */
template<class T>
template<typename T>
requires requires(T p) { std::get<T>(OptionValue {}); }
optional<T>
get_if(const string& name) const
{
......@@ -303,6 +319,7 @@ public:
/* Applies a variant visitor to the value of the option with that name.
Throws UnknownOptionException if there is no option with that name. */
template<class Visitor>
requires invocable<Visitor, OptionValue>
decltype(auto)
visit(const string& name, Visitor&& vis) const
{
......@@ -318,13 +335,8 @@ public:
void writeJsonOutput(ostream& output) const;
private:
// pair<string, string> corresponds to a pair of numerical values
// vector<vector<string>> corresponds to a vector of vectors of numerical values
map<string, variant<NumVal, pair<string, string>, StringVal, DateVal, SymbolListVal, vector<int>,
VecStrVal, VecCellStrVal, VecValueVal, vector<vector<string>>>> options;
map<string, OptionValue> options;
void writeOutputCommon(ostream& output, const string& option_group) const;
// Helper constant for visitors
template<class> static constexpr bool always_false_v {false};
};
#endif // ! _STATEMENT_HH
#endif
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,22 +17,24 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cassert>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <numeric>
#include <ranges>
#include <sstream>
#include <unordered_map>
#include "StaticModel.hh"
#include "DynamicModel.hh"
#include "StaticModel.hh"
StaticModel::StaticModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg) :
ModelTree{symbol_table_arg, num_constants_arg, external_functions_table_arg}
StaticModel::StaticModel(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg) :
ModelTree {symbol_table_arg, num_constants_arg, external_functions_table_arg,
heterogeneity_table_arg}
{
}
......@@ -72,7 +74,7 @@ StaticModel::operator=(const StaticModel &m)
}
StaticModel::StaticModel(const DynamicModel& m) :
ModelTree{m.symbol_table, m.num_constants, m.external_functions_table}
ModelTree {m.symbol_table, m.num_constants, m.external_functions_table, m.heterogeneity_table}
{
// Convert model local variables (need to be done first)
for (int it : m.local_variables_vector)
......@@ -87,23 +89,24 @@ StaticModel::StaticModel(const DynamicModel &m) :
// If equation is dynamic, replace it by an equation marked [static]
if (dynamic_equations.contains(i))
{
auto [static_only_equations,
static_only_equations_lineno,
static_only_equations_equation_tags] = m.getStaticOnlyEquationsInfo();
auto [static_only_equations, static_only_equations_lineno,
static_only_complementarity_conditions, static_only_equations_equation_tags]
= m.getStaticOnlyEquationsInfo();
addEquation(static_only_equations[static_only_index]->toStatic(*this),
static_only_equations_lineno[static_only_index],
static_only_complementarity_conditions[static_only_index],
static_only_equations_equation_tags.getTagsByEqn(static_only_index));
static_only_index++;
}
else
addEquation(m.equations[i]->toStatic(*this),
m.equations_lineno[i],
m.equation_tags.getTagsByEqn(i));
addEquation(m.equations[i]->toStatic(*this), m.equations_lineno[i],
m.complementarity_conditions[i], m.equation_tags.getTagsByEqn(i));
}
catch (DataTree::DivisionByZeroException)
{
cerr << "...division by zero error encountered when converting equation " << i << " to static" << endl;
cerr << "...division by zero error encountered when converting equation " << i
<< " to static" << endl;
exit(EXIT_FAILURE);
}
......@@ -132,21 +135,19 @@ StaticModel::writeStaticBytecode(const string &basename) const
// First write the .bin file
int u_count_int {writeBytecodeBinFile(basename + "/model/bytecode/static.bin", false)};
BytecodeWriter code_file {basename + "/model/bytecode/static.cod"};
vector<int> eq_idx(equations.size());
iota(eq_idx.begin(), eq_idx.end(), 0);
vector<int> endo_idx(symbol_table.endo_nbr());
iota(endo_idx.begin(), endo_idx.end(), 0);
Bytecode::Writer code_file {basename + "/model/bytecode/static.cod"};
auto eq_idx = views::iota(0, static_cast<int>(equations.size()));
auto endo_idx = views::iota(0, symbol_table.endo_nbr());
// Declare temporary terms and the (single) block
code_file << FDIMST_{static_cast<int>(temporary_terms_derivatives[0].size()
code_file << Bytecode::FDIMST {static_cast<int>(temporary_terms_derivatives[0].size()
+ temporary_terms_derivatives[1].size())}
<< FBEGINBLOCK_{symbol_table.endo_nbr(),
<< Bytecode::FBEGINBLOCK {symbol_table.endo_nbr(),
BlockSimulationType::solveForwardComplete,
0,
symbol_table.endo_nbr(),
endo_idx,
eq_idx,
{endo_idx.begin(), endo_idx.end()},
{eq_idx.begin(), eq_idx.end()},
false,
u_count_int,
symbol_table.endo_nbr()};
......@@ -157,7 +158,7 @@ StaticModel::writeStaticBytecode(const string &basename) const
void
StaticModel::writeStaticBlockBytecode(const string& basename) const
{
BytecodeWriter code_file {basename + "/model/bytecode/block/static.cod"};
Bytecode::Writer code_file {basename + "/model/bytecode/block/static.cod"};
const filesystem::path bin_filename {basename + "/model/bytecode/block/static.bin"};
ofstream bin_file {bin_filename, ios::out | ios::binary};
......@@ -168,7 +169,7 @@ StaticModel::writeStaticBlockBytecode(const string &basename) const
}
// Temporary variables declaration
code_file << FDIMST_{static_cast<int>(blocks_temporary_terms_idxs.size())};
code_file << Bytecode::FDIMST {static_cast<int>(blocks_temporary_terms_idxs.size())};
temporary_terms_t temporary_terms_written;
......@@ -182,7 +183,7 @@ StaticModel::writeStaticBlockBytecode(const string &basename) const
? writeBlockBytecodeBinFile(bin_file, block)
: 0};
code_file << FBEGINBLOCK_{blocks[block].mfs_size,
code_file << Bytecode::FBEGINBLOCK {blocks[block].mfs_size,
simulation_type,
blocks[block].first_equation,
block_size,
......@@ -194,11 +195,13 @@ StaticModel::writeStaticBlockBytecode(const string &basename) const
writeBlockBytecodeHelper<false>(code_file, block, temporary_terms_written);
}
code_file << FEND_{};
code_file << Bytecode::FEND {};
}
void
StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll)
StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder,
const eval_context_t& eval_context, bool no_tmp_terms, bool block,
bool use_dll)
{
initializeVariablesAndEquations();
......@@ -211,7 +214,8 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co
with DynamicModel::computingPass(). */
if (log2(symbol_table.endo_nbr()) * derivsOrder >= numeric_limits<int>::digits)
{
cerr << "ERROR: The derivatives matrix of the " << modelClassName() << " is too large. Please decrease the approximation order." << endl;
cerr << "ERROR: The derivatives matrix of the " << modelClassName()
<< " is too large. Please decrease the approximation order." << endl;
exit(EXIT_FAILURE);
}
......@@ -230,7 +234,8 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co
if (paramsDerivsOrder > 0)
{
cout << "Computing " << modelClassName() << " derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl;
cout << "Computing " << modelClassName() << " derivatives w.r.t. parameters (order "
<< paramsDerivsOrder << ")." << endl;
computeParamsDerivatives(paramsDerivsOrder);
}
......@@ -242,227 +247,18 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co
computingPassBlock(eval_context, no_tmp_terms);
if (!block_decomposed && block)
{
cerr << "ERROR: Block decomposition requested but failed. If your model does not have a steady state, you may want to try the 'no_static' option of the 'model' block." << endl;
exit(EXIT_FAILURE);
}
}
void
StaticModel::writeStaticMFile(const string &basename) const
{
auto [d_output, tt_output] = writeModelFileHelper<ExprNodeOutputType::matlabStaticModel>();
ostringstream init_output, end_output;
init_output << "residual = zeros(" << equations.size() << ", 1);";
writeStaticMFileHelper(basename, "static_resid", "residual", "static_resid_tt",
temporary_terms_derivatives[0].size(),
"", init_output, end_output,
d_output[0], tt_output[0]);
init_output.str("");
end_output.str("");
init_output << "g1 = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ");";
writeStaticMFileHelper(basename, "static_g1", "g1", "static_g1_tt",
temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size(),
"static_resid_tt",
init_output, end_output,
d_output[1], tt_output[1]);
writeStaticMWrapperFunction(basename, "g1");
// For order ≥ 2
int ncols{symbol_table.endo_nbr()};
int ntt { static_cast<int>(temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size()) };
for (size_t i{2}; i < derivatives.size(); i++)
{
ncols *= symbol_table.endo_nbr();
ntt += temporary_terms_derivatives[i].size();
string gname{"g" + to_string(i)};
string gprevname{"g" + to_string(i-1)};
init_output.str("");
end_output.str("");
if (derivatives[i].size())
{
init_output << gname << "_i = zeros(" << NNZDerivatives[i] << ",1);" << endl
<< gname << "_j = zeros(" << NNZDerivatives[i] << ",1);" << endl
<< gname << "_v = zeros(" << NNZDerivatives[i] << ",1);" << endl;
end_output << gname << " = sparse("
<< gname << "_i," << gname << "_j," << gname << "_v,"
<< equations.size() << "," << ncols << ");";
}
else
init_output << gname << " = sparse([],[],[]," << equations.size() << "," << ncols << ");";
writeStaticMFileHelper(basename, "static_" + gname, gname,
"static_" + gname + "_tt",
ntt,
"static_" + gprevname + "_tt",
init_output, end_output,
d_output[i], tt_output[i]);
if (i <= 3)
writeStaticMWrapperFunction(basename, gname);
}
writeStaticMCompatFile(basename);
}
void
StaticModel::writeStaticMWrapperFunction(const string &basename, const string &ending) const
{
string name;
if (ending == "g1")
name = "static_resid_g1";
else if (ending == "g2")
name = "static_resid_g1_g2";
else if (ending == "g3")
name = "static_resid_g1_g2_g3";
filesystem::path filename {packageDir(basename) / (name + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
if (ending == "g1")
output << "function [residual, g1] = " << name << "(T, y, x, params, T_flag)" << endl
<< "% function [residual, g1] = " << name << "(T, y, x, params, T_flag)" << endl;
else if (ending == "g2")
output << "function [residual, g1, g2] = " << name << "(T, y, x, params, T_flag)" << endl
<< "% function [residual, g1, g2] = " << name << "(T, y, x, params, T_flag)" << endl;
else if (ending == "g3")
output << "function [residual, g1, g2, g3] = " << name << "(T, y, x, params, T_flag)" << endl
<< "% function [residual, g1, g2, g3] = " << name << "(T, y, x, params, T_flag)" << endl;
output << "%" << endl
<< "% Wrapper function automatically created by Dynare" << endl
<< "%" << endl
<< endl
<< " if T_flag" << endl
<< " T = " << basename << ".static_" << ending << "_tt(T, y, x, params);" << endl
<< " end" << endl;
if (ending == "g1")
output << " residual = " << basename << ".static_resid(T, y, x, params, false);" << endl
<< " g1 = " << basename << ".static_g1(T, y, x, params, false);" << endl;
else if (ending == "g2")
output << " [residual, g1] = " << basename << ".static_resid_g1(T, y, x, params, false);" << endl
<< " g2 = " << basename << ".static_g2(T, y, x, params, false);" << endl;
else if (ending == "g3")
output << " [residual, g1, g2] = " << basename << ".static_resid_g1_g2(T, y, x, params, false);" << endl
<< " g3 = " << basename << ".static_g3(T, y, x, params, false);" << endl;
output << endl << "end" << endl;
output.close();
}
void
StaticModel::writeStaticMFileHelper(const string &basename,
const string &name, const string &retvalname,
const string &name_tt, size_t ttlen,
const string &previous_tt_name,
const ostringstream &init_s, const ostringstream &end_s,
const ostringstream &s, const ostringstream &s_tt) const
{
filesystem::path filename {packageDir(basename) / (name_tt + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output << "function T = " << name_tt << "(T, y, x, params)" << endl
<< "% function T = " << name_tt << "(T, y, x, params)" << endl
<< "%" << endl
<< "% File created by Dynare Preprocessor from .mod file" << endl
<< "%" << endl
<< "% Inputs:" << endl
<< "% T [#temp variables by 1] double vector of temporary terms to be filled by function" << endl
<< "% y [M_.endo_nbr by 1] double vector of endogenous variables in declaration order" << endl
<< "% x [M_.exo_nbr by 1] double vector of exogenous variables in declaration order" << endl
<< "% params [M_.param_nbr by 1] double vector of parameter values in declaration order" << endl
<< "%" << endl
<< "% Output:" << endl
<< "% T [#temp variables by 1] double vector of temporary terms" << endl
<< "%" << endl << endl
<< "assert(length(T) >= " << ttlen << ");" << endl
cerr << "ERROR: Block decomposition requested but failed. If your model does not have a "
"steady state, you may want to try the 'no_static' option of the 'model' block."
<< endl;
if (!previous_tt_name.empty())
output << "T = " << basename << "." << previous_tt_name << "(T, y, x, params);" << endl << endl;
output << s_tt.str() << endl
<< "end" << endl;
output.close();
filename = packageDir(basename) / (name + ".m");
output.open(filename, ios::out | ios::binary);
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output << "function " << retvalname << " = " << name << "(T, y, x, params, T_flag)" << endl
<< "% function " << retvalname << " = " << name << "(T, y, x, params, T_flag)" << endl
<< "%" << endl
<< "% File created by Dynare Preprocessor from .mod file" << endl
<< "%" << endl
<< "% Inputs:" << endl
<< "% T [#temp variables by 1] double vector of temporary terms to be filled by function" << endl
<< "% y [M_.endo_nbr by 1] double vector of endogenous variables in declaration order" << endl
<< "% x [M_.exo_nbr by 1] double vector of exogenous variables in declaration order" << endl
<< "% params [M_.param_nbr by 1] double vector of parameter values in declaration order" << endl
<< "% to evaluate the model" << endl
<< "% T_flag boolean boolean flag saying whether or not to calculate temporary terms" << endl
<< "%" << endl
<< "% Output:" << endl
<< "% " << retvalname << endl
<< "%" << endl << endl;
if (!name_tt.empty())
output << "if T_flag" << endl
<< " T = " << basename << "." << name_tt << "(T, y, x, params);" << endl
<< "end" << endl;
output << init_s.str() << endl
<< s.str()
<< end_s.str() << endl
<< "end" << endl;
output.close();
computeMCPEquationsReordering();
}
void
StaticModel::writeStaticMCompatFile(const string &basename) const
{
filesystem::path filename {packageDir(basename) / "static.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
int ntt { static_cast<int>(temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size()) };
output << "function [residual, g1, g2, g3] = static(y, x, params)" << endl
<< " T = NaN(" << ntt << ", 1);" << endl
<< " if nargout <= 1" << endl
<< " residual = " << basename << ".static_resid(T, y, x, params, true);" << endl
<< " elseif nargout == 2" << endl
<< " [residual, g1] = " << basename << ".static_resid_g1(T, y, x, params, true);" << endl
<< " elseif nargout == 3" << endl
<< " [residual, g1, g2] = " << basename << ".static_resid_g1_g2(T, y, x, params, true);" << endl
<< " else" << endl
<< " [residual, g1, g2, g3] = " << basename << ".static_resid_g1_g2_g3(T, y, x, params, true);" << endl
<< " end" << endl
<< "end" << endl;
output.close();
}
void
StaticModel::writeStaticFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, bool julia) const
StaticModel::writeStaticFile(const string& basename, bool use_dll, const string& mexext,
const filesystem::path& matlabroot, bool julia) const
{
filesystem::path model_dir {basename};
model_dir /= "model";
......@@ -491,13 +287,6 @@ StaticModel::writeStaticFile(const string &basename, bool use_dll, const string
}
create_directories(model_dir / "bytecode" / "block");
// Legacy representation
if (use_dll)
writeModelCFile<false>(basename, mexext, matlabroot);
else if (!julia) // M-files
writeStaticMFile(basename);
// The legacy representation is no longer produced for Julia
/* PlannerObjective subclass or discretionary optimal policy models don’t
have as many variables as equations; bytecode does not support that
case */
......@@ -516,10 +305,13 @@ StaticModel::writeStaticFile(const string &basename, bool use_dll, const string
writeSetAuxiliaryVariablesFile<false>(basename, julia);
// Support for model debugging
if (!julia)
{
writeComplementarityConditionsFile<false>(basename);
// Support for model debugging
writeDebugModelMFiles<false>(basename);
}
}
bool
StaticModel::exoPresentInEqs() const
......@@ -541,7 +333,12 @@ StaticModel::writeDriverOutput(ostream &output) const
if (block_decomposed)
writeBlockDriverOutput(output);
writeDriverSparseIndicesHelper<false>(output);
writeDriverSparseIndicesHelper("static", output);
output << "M_.static_mcp_equations_reordering = [";
for (auto i : mcp_equations_reordering)
output << i + 1 << "; ";
output << "];" << endl;
}
void
......@@ -549,14 +346,17 @@ StaticModel::writeBlockDriverOutput(ostream &output) const
{
for (int blk = 0; blk < static_cast<int>(blocks.size()); blk++)
{
output << "M_.block_structure_stat.block(" << blk+1 << ").Simulation_Type = " << static_cast<int>(blocks[blk].simulation_type) << ";" << endl
<< "M_.block_structure_stat.block(" << blk+1 << ").endo_nbr = " << blocks[blk].size << ";" << endl
<< "M_.block_structure_stat.block(" << blk+1 << ").mfs = " << blocks[blk].mfs_size << ";" << endl
output << "M_.block_structure_stat.block(" << blk + 1
<< ").Simulation_Type = " << static_cast<int>(blocks[blk].simulation_type) << ";"
<< endl
<< "M_.block_structure_stat.block(" << blk + 1 << ").endo_nbr = " << blocks[blk].size
<< ";" << endl
<< "M_.block_structure_stat.block(" << blk + 1 << ").mfs = " << blocks[blk].mfs_size
<< ";" << endl
<< "M_.block_structure_stat.block(" << blk + 1 << ").equation = [";
for (int eq = 0; eq < blocks[blk].size; eq++)
output << " " << getBlockEquationID(blk, eq) + 1;
output << "];" << endl
<< "M_.block_structure_stat.block(" << blk+1 << ").variable = [";
output << "];" << endl << "M_.block_structure_stat.block(" << blk + 1 << ").variable = [";
for (int var = 0; var < blocks[blk].size; var++)
output << " " << getBlockVariableID(blk, var) + 1;
output << "];" << endl;
......@@ -564,16 +364,14 @@ StaticModel::writeBlockDriverOutput(ostream &output) const
output << "M_.block_structure_stat.variable_reordered = [";
for (int i = 0; i < symbol_table.endo_nbr(); i++)
output << " " << endo_idx_block2orig[i] + 1;
output << "];" << endl
<< "M_.block_structure_stat.equation_reordered = [";
output << "];" << endl << "M_.block_structure_stat.equation_reordered = [";
for (int i = 0; i < symbol_table.endo_nbr(); i++)
output << " " << eq_idx_block2orig[i] + 1;
output << "];" << endl;
set<pair<int, int>> row_incidence;
for (const auto& [indices, d1] : derivatives[1])
if (int deriv_id = indices[1];
getTypeByDerivID(deriv_id) == SymbolType::endogenous)
if (int deriv_id = indices[1]; getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{
int eq = indices[0];
int var {getTypeSpecificIDByDerivID(deriv_id)};
......@@ -583,8 +381,8 @@ StaticModel::writeBlockDriverOutput(ostream &output) const
for (auto [eq, var] : row_incidence)
output << " " << eq + 1 << " " << var + 1 << ";" << endl;
output << "];" << endl
<< "M_.block_structure_stat.tmp_nbr = " << blocks_temporary_terms_idxs.size()
<< ";" << endl;
<< "M_.block_structure_stat.tmp_nbr = " << blocks_temporary_terms_idxs.size() << ";"
<< endl;
writeBlockDriverSparseIndicesHelper<false>(output);
}
......@@ -665,7 +463,8 @@ StaticModel::computeChainRuleJacobian()
map<int, BinaryOpNode*> recursive_vars;
for (int i = 0; i < nb_recursives; i++)
{
int deriv_id = getDerivID(symbol_table.getID(SymbolType::endogenous, getBlockVariableID(blk, i)), 0);
int deriv_id = getDerivID(
symbol_table.getID(SymbolType::endogenous, getBlockVariableID(blk, i)), 0);
if (getBlockEquationType(blk, i) == EquationType::evaluateRenormalized)
recursive_vars[deriv_id] = getBlockEquationRenormalizedExpr(blk, i);
else
......@@ -684,7 +483,9 @@ StaticModel::computeChainRuleJacobian()
for (int var = nb_recursives; var < size; var++)
{
int var_orig = getBlockVariableID(blk, var);
expr_t d1 = equations[eq_orig]->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, var_orig), 0), recursive_vars, non_null_chain_rule_derivatives, chain_rule_deriv_cache);
expr_t d1 = equations[eq_orig]->getChainRuleDerivative(
getDerivID(symbol_table.getID(SymbolType::endogenous, var_orig), 0),
recursive_vars, non_null_chain_rule_derivatives, chain_rule_deriv_cache);
if (d1 != Zero)
blocks_derivatives[blk][{eq, var, 0}] = d1;
}
......@@ -698,9 +499,11 @@ StaticModel::computeChainRuleJacobian()
{
auto& [eq, var, lag] {indices};
assert(eq >= nb_recursives && var >= nb_recursives && lag == 0);
blocks_jacobian_sparse_column_major_order[blk].try_emplace({eq-nb_recursives, var-nb_recursives}, d1);
blocks_jacobian_sparse_column_major_order[blk].try_emplace(
{eq - nb_recursives, var - nb_recursives}, d1);
}
blocks_jacobian_sparse_colptr[blk] = computeCSCColPtr(blocks_jacobian_sparse_column_major_order[blk], blocks[blk].mfs_size);
blocks_jacobian_sparse_colptr[blk] = computeCSCColPtr(
blocks_jacobian_sparse_column_major_order[blk], blocks[blk].mfs_size);
}
}
}
......@@ -708,7 +511,8 @@ StaticModel::computeChainRuleJacobian()
void
StaticModel::writeLatexFile(const string& basename, bool write_equation_tags) const
{
writeLatexModelFile(basename, "static", ExprNodeOutputType::latexStaticModel, write_equation_tags);
writeLatexModelFile(basename, "static", ExprNodeOutputType::latexStaticModel,
write_equation_tags);
}
void
......@@ -734,7 +538,8 @@ StaticModel::writeLatexAuxVarRecursiveDefinitions(ostream &output) const
for (auto aux_equation : aux_equations)
{
output << R"(\begin{dmath})" << endl;
dynamic_cast<ExprNode *>(aux_equation)->writeOutput(output, ExprNodeOutputType::latexStaticModel);
dynamic_cast<ExprNode*>(aux_equation)
->writeOutput(output, ExprNodeOutputType::latexStaticModel);
output << endl << R"(\end{dmath})" << endl;
}
}
......@@ -750,8 +555,7 @@ StaticModel::writeJsonAuxVarRecursiveDefinitions(ostream &output) const
{
vector<string> efout;
aux_equation->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms, false);
for (bool printed_something{false};
const auto &it : efout)
for (bool printed_something {false}; const auto& it : efout)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -773,8 +577,7 @@ void
StaticModel::writeJsonOutput(ostream& output) const
{
output << R"("static_tmp_nbr": [)";
for (bool printed_something {false};
const auto &tts : temporary_terms_derivatives)
for (bool printed_something {false}; const auto& tts : temporary_terms_derivatives)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -805,22 +608,17 @@ StaticModel::writeJsonParamsDerivatives(ostream &output, bool writeDetails) cons
if (!params_derivatives.size())
return;
auto [mlv_output, tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output, g3p_output]
{ writeJsonParamsDerivativesHelper<false>(writeDetails) };
auto [mlv_output, tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output,
g3p_output] {writeJsonParamsDerivativesHelper<false>(writeDetails)};
// g3p_output is ignored
if (writeDetails)
output << R"("static_model_params_derivative": {)";
else
output << R"("static_model_params_derivatives_simple": {)";
output << mlv_output.str()
<< ", " << tt_output.str()
<< ", " << rp_output.str()
<< ", " << gp_output.str()
<< ", " << rpp_output.str()
<< ", " << gpp_output.str()
<< ", " << hp_output.str()
<< "}";
output << mlv_output.str() << ", " << tt_output.str() << ", " << rp_output.str() << ", "
<< gp_output.str() << ", " << rpp_output.str() << ", " << gpp_output.str() << ", "
<< hp_output.str() << "}";
}
void
......@@ -830,6 +628,7 @@ StaticModel::computeRamseyMultipliersDerivatives(int ramsey_orig_endo_nbr, bool
// Compute derivation IDs of Lagrange multipliers
set<int> mult_symb_ids {symbol_table.getLagrangeMultipliers()};
vector<int> mult_deriv_ids;
mult_deriv_ids.reserve(mult_symb_ids.size());
for (int symb_id : mult_symb_ids)
mult_deriv_ids.push_back(getDerivID(symb_id, 0));
......@@ -843,7 +642,7 @@ StaticModel::computeRamseyMultipliersDerivatives(int ramsey_orig_endo_nbr, bool
Lagrange multiplier. We use the guarantee given by SymbolTable that
symbol IDs are increasing. */
if (varexpr->symb_id > *mult_symb_ids.crbegin())
recursive_variables.emplace(getDerivID(varexpr->symb_id, 0), aux_eq);
recursive_variables.emplace(varexpr->getDerivID(), aux_eq);
}
// Compute the chain rule derivatives w.r.t. multipliers
......@@ -866,17 +665,16 @@ StaticModel::computeRamseyMultipliersDerivatives(int ramsey_orig_endo_nbr, bool
not optional) */
if (no_tmp_terms)
for (auto& it : temp_terms_map)
erase_if(it.second,
[](expr_t e) { return !dynamic_cast<AbstractExternalFunctionNode *>(e); });
copy(temp_terms_map[{1, 0}].begin(), temp_terms_map[{1, 0}].end(),
inserter(ramsey_multipliers_derivatives_temporary_terms, ramsey_multipliers_derivatives_temporary_terms.begin()));
for (int idx {0};
auto it : ramsey_multipliers_derivatives_temporary_terms)
erase_if(it.second, [](expr_t e) { return !dynamic_cast<AbstractExternalFunctionNode*>(e); });
ranges::copy(temp_terms_map[{1, 0}],
inserter(ramsey_multipliers_derivatives_temporary_terms,
ramsey_multipliers_derivatives_temporary_terms.begin()));
for (int idx {0}; auto it : ramsey_multipliers_derivatives_temporary_terms)
ramsey_multipliers_derivatives_temporary_terms_idxs[it] = idx++;
// Compute the CSC format
ramsey_multipliers_derivatives_sparse_colptr = computeCSCColPtr(ramsey_multipliers_derivatives,
mult_deriv_ids.size());
ramsey_multipliers_derivatives_sparse_colptr
= computeCSCColPtr(ramsey_multipliers_derivatives, mult_deriv_ids.size());
}
void
......@@ -885,19 +683,18 @@ StaticModel::writeDriverRamseyMultipliersDerivativesSparseIndices(ostream &outpu
output << "M_.ramsey_multipliers_static_g1_sparse_rowval = int32([";
for (auto& [row_col, d] : ramsey_multipliers_derivatives)
output << row_col.first + 1 << ' ';
output << "]);" << endl
<< "M_.ramsey_multipliers_static_g1_sparse_colval = int32([";
output << "]);" << endl << "M_.ramsey_multipliers_static_g1_sparse_colval = int32([";
for (auto& [row_col, d] : ramsey_multipliers_derivatives)
output << row_col.second + 1 << ' ';
output << "]);" << endl
<< "M_.ramsey_multipliers_static_g1_sparse_colptr = int32([";
output << "]);" << endl << "M_.ramsey_multipliers_static_g1_sparse_colptr = int32([";
for (int it : ramsey_multipliers_derivatives_sparse_colptr)
output << it + 1 << ' ';
output << "]);" << endl;
}
void
StaticModel::writeRamseyMultipliersDerivativesMFile(const string &basename, int ramsey_orig_endo_nbr) const
StaticModel::writeRamseyMultipliersDerivativesMFile(const string& basename,
int ramsey_orig_endo_nbr) const
{
constexpr auto output_type {ExprNodeOutputType::matlabStaticModel};
filesystem::path filename {packageDir(basename) / "ramsey_multipliers_static_g1.m"};
......@@ -908,23 +705,23 @@ StaticModel::writeRamseyMultipliersDerivativesMFile(const string &basename, int
exit(EXIT_FAILURE);
}
output_file << "function g1m = ramsey_multipliers_static_g1(y, x, params, sparse_rowval, sparse_colval, sparse_colptr)" << endl
output_file << "function g1m = ramsey_multipliers_static_g1(y, x, params, sparse_rowval, "
"sparse_colval, sparse_colptr)"
<< endl
<< "g1m_v=NaN(" << ramsey_multipliers_derivatives.size() << ",1);" << endl;
writeRamseyMultipliersDerivativesHelper<output_type>(output_file);
// On MATLAB < R2020a, sparse() does not accept int32 indices
output_file << "if ~isoctave && matlab_ver_less_than('9.8')" << endl
<< " sparse_rowval = double(sparse_rowval);" << endl
<< " sparse_colval = double(sparse_colval);" << endl
<< "end" << endl
<< "g1m = sparse(sparse_rowval, sparse_colval, g1m_v, " << ramsey_orig_endo_nbr << ", " << symbol_table.getLagrangeMultipliers().size() << ");" << endl
output_file << "g1m = sparse(sparse_rowval, sparse_colval, g1m_v, " << ramsey_orig_endo_nbr
<< ", " << symbol_table.getLagrangeMultipliers().size() << ");" << endl
<< "end" << endl;
output_file.close();
}
void
StaticModel::writeRamseyMultipliersDerivativesCFile(const string &basename, const string &mexext, const filesystem::path &matlabroot, int ramsey_orig_endo_nbr) const
StaticModel::writeRamseyMultipliersDerivativesCFile(const string& basename, const string& mexext,
const filesystem::path& matlabroot,
int ramsey_orig_endo_nbr) const
{
constexpr auto output_type {ExprNodeOutputType::CStaticModel};
const filesystem::path model_src_dir {filesystem::path {basename} / "model" / "src"};
......@@ -941,13 +738,16 @@ StaticModel::writeRamseyMultipliersDerivativesCFile(const string &basename, cons
exit(EXIT_FAILURE);
}
output << "#include <math.h>" << endl << endl
output << "#include <math.h>" << endl
<< endl
<< R"(#include "mex.h")" << endl // Needed for calls to external functions
<< endl;
writeCHelpersDefinition(output);
writeCHelpersDeclaration(output); // Provide external definition of helpers
output << endl
<< "void ramsey_multipliers_static_g1(const double *restrict y, const double *restrict x, const double *restrict params, double *restrict T, double *restrict g1m_v)" << endl
<< "void ramsey_multipliers_static_g1(const double *restrict y, const double *restrict x, "
"const double *restrict params, double *restrict T, double *restrict g1m_v)"
<< endl
<< "{" << endl;
writeRamseyMultipliersDerivativesHelper<output_type>(output);
output << "}" << endl
......@@ -958,19 +758,32 @@ StaticModel::writeRamseyMultipliersDerivativesCFile(const string &basename, cons
<< R"( mexErrMsgTxt("Accepts exactly 6 input arguments");)" << endl
<< " if (nlhs != 1)" << endl
<< R"( mexErrMsgTxt("Accepts exactly 1 output argument");)" << endl
<< " if (!(mxIsDouble(prhs[0]) && !mxIsComplex(prhs[0]) && !mxIsSparse(prhs[0]) && mxGetNumberOfElements(prhs[0]) == " << symbol_table.endo_nbr() << "))" << endl
<< R"( mexErrMsgTxt("y must be a real dense numeric array with )" << symbol_table.endo_nbr() << R"( elements");)" << endl
<< " if (!(mxIsDouble(prhs[0]) && !mxIsComplex(prhs[0]) && !mxIsSparse(prhs[0]) && "
"mxGetNumberOfElements(prhs[0]) == "
<< symbol_table.endo_nbr() << "))" << endl
<< R"( mexErrMsgTxt("y must be a real dense numeric array with )"
<< symbol_table.endo_nbr() << R"( elements");)" << endl
<< " const double *restrict y = mxGetPr(prhs[0]);" << endl
<< " if (!(mxIsDouble(prhs[1]) && !mxIsComplex(prhs[1]) && !mxIsSparse(prhs[1]) && mxGetNumberOfElements(prhs[1]) == " << xlen << "))" << endl
<< R"( mexErrMsgTxt("x must be a real dense numeric array with )" << xlen << R"( elements");)" << endl
<< " if (!(mxIsDouble(prhs[1]) && !mxIsComplex(prhs[1]) && !mxIsSparse(prhs[1]) && "
"mxGetNumberOfElements(prhs[1]) == "
<< xlen << "))" << endl
<< R"( mexErrMsgTxt("x must be a real dense numeric array with )" << xlen
<< R"( elements");)" << endl
<< " const double *restrict x = mxGetPr(prhs[1]);" << endl
<< " if (!(mxIsDouble(prhs[2]) && !mxIsComplex(prhs[2]) && !mxIsSparse(prhs[2]) && mxGetNumberOfElements(prhs[2]) == " << symbol_table.param_nbr() << "))" << endl
<< R"( mexErrMsgTxt("params must be a real dense numeric array with )" << symbol_table.param_nbr() << R"( elements");)" << endl
<< " if (!(mxIsDouble(prhs[2]) && !mxIsComplex(prhs[2]) && !mxIsSparse(prhs[2]) && "
"mxGetNumberOfElements(prhs[2]) == "
<< symbol_table.param_nbr() << "))" << endl
<< R"( mexErrMsgTxt("params must be a real dense numeric array with )"
<< symbol_table.param_nbr() << R"( elements");)" << endl
<< " const double *restrict params = mxGetPr(prhs[2]);" << endl
<< " if (!(mxIsInt32(prhs[3]) && mxGetNumberOfElements(prhs[3]) == " << nzval << "))" << endl
<< R"( mexErrMsgTxt("sparse_rowval must be an int32 array with )" << nzval << R"( elements");)" << endl
<< " if (!(mxIsInt32(prhs[5]) && mxGetNumberOfElements(prhs[5]) == " << ncols+1 << "))" << endl
<< R"( mexErrMsgTxt("sparse_colptr must be an int32 array with )" << ncols+1 << R"( elements");)" << endl
<< " if (!(mxIsInt32(prhs[3]) && mxGetNumberOfElements(prhs[3]) == " << nzval << "))"
<< endl
<< R"( mexErrMsgTxt("sparse_rowval must be an int32 array with )" << nzval
<< R"( elements");)" << endl
<< " if (!(mxIsInt32(prhs[5]) && mxGetNumberOfElements(prhs[5]) == " << ncols + 1 << "))"
<< endl
<< R"( mexErrMsgTxt("sparse_colptr must be an int32 array with )" << ncols + 1
<< R"( elements");)" << endl
<< "#if MX_HAS_INTERLEAVED_COMPLEX" << endl
<< " const int32_T *restrict sparse_rowval = mxGetInt32s(prhs[3]);" << endl
<< " const int32_T *restrict sparse_colptr = mxGetInt32s(prhs[5]);" << endl
......@@ -978,13 +791,15 @@ StaticModel::writeRamseyMultipliersDerivativesCFile(const string &basename, cons
<< " const int32_T *restrict sparse_rowval = (int32_T *) mxGetData(prhs[3]);" << endl
<< " const int32_T *restrict sparse_colptr = (int32_T *) mxGetData(prhs[5]);" << endl
<< "#endif" << endl
<< " plhs[0] = mxCreateSparse(" << ramsey_orig_endo_nbr << ", " << ncols << ", " << nzval << ", mxREAL);" << endl
<< " plhs[0] = mxCreateSparse(" << ramsey_orig_endo_nbr << ", " << ncols << ", " << nzval
<< ", mxREAL);" << endl
<< " mwIndex *restrict ir = mxGetIr(plhs[0]), *restrict jc = mxGetJc(plhs[0]);" << endl
<< " for (mwSize i = 0; i < " << nzval << "; i++)" << endl
<< " *ir++ = *sparse_rowval++ - 1;" << endl
<< " for (mwSize i = 0; i < " << ncols + 1 << "; i++)" << endl
<< " *jc++ = *sparse_colptr++ - 1;" << endl
<< " mxArray *T_mx = mxCreateDoubleMatrix(" << ramsey_multipliers_derivatives_temporary_terms.size() << ", 1, mxREAL);" << endl
<< " mxArray *T_mx = mxCreateDoubleMatrix("
<< ramsey_multipliers_derivatives_temporary_terms.size() << ", 1, mxREAL);" << endl
<< " ramsey_multipliers_static_g1(y, x, params, mxGetPr(T_mx), mxGetPr(plhs[0]));" << endl
<< " mxDestroyArray(T_mx);" << endl
<< "}" << endl;
......
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,14 +17,14 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _STATIC_MODEL_HH
#define _STATIC_MODEL_HH
#ifndef STATIC_MODEL_HH
#define STATIC_MODEL_HH
#include <fstream>
#include <filesystem>
#include <fstream>
#include "ModelTree.hh"
#include "Bytecode.hh"
#include "ModelTree.hh"
using namespace std;
......@@ -60,9 +60,6 @@ private:
block. See the DynamicModel class for the default value in that case. */
int static_mfs {0};
// Writes static model file (MATLAB/Octave version, legacy representation)
void writeStaticMFile(const string &basename) const;
//! Writes the code of the block-decomposed model in virtual machine bytecode
void writeStaticBlockBytecode(const string& basename) const;
......@@ -72,7 +69,8 @@ private:
//! Computes jacobian and prepares for equation normalization
/*! Using values from initval/endval blocks and parameter initializations:
- computes the jacobian for the model w.r. to contemporaneous variables
- removes edges of the incidence matrix when derivative w.r. to the corresponding variable is too close to zero (below the cutoff)
- removes edges of the incidence matrix when derivative w.r. to the corresponding variable is
too close to zero (below the cutoff)
*/
void evaluateJacobian(const eval_context_t& eval_context, jacob_map_t* j_m, bool dynamic);
......@@ -94,24 +92,9 @@ private:
void computeChainRuleJacobian() override;
/* Helper for writing MATLAB/Octave functions for residuals/derivatives and
their temporary terms (legacy representation) */
void writeStaticMFileHelper(const string &basename,
const string &name, const string &retvalname,
const string &name_tt, size_t ttlen,
const string &previous_tt_name,
const ostringstream &init_s, const ostringstream &end_s,
const ostringstream &s, const ostringstream &s_tt) const;
/* Writes MATLAB/Octave wrapper function for computing residuals and
derivatives at the same time (legacy representation) */
void writeStaticMWrapperFunction(const string &basename, const string &ending) const;
/* Create the compatibility static.m file for MATLAB/Octave not yet using the
temporary terms array interface (legacy representation) */
void writeStaticMCompatFile(const string &name) const;
int
getBlockJacobianEndoCol([[maybe_unused]] int blk, int var, [[maybe_unused]] int lag) const override
getBlockJacobianEndoCol([[maybe_unused]] int blk, int var,
[[maybe_unused]] int lag) const override
{
assert(var >= blocks[blk].getRecursiveSize());
return var - blocks[blk].getRecursiveSize();
......@@ -137,9 +120,9 @@ protected:
}
public:
StaticModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants,
ExternalFunctionsTable &external_functions_table_arg);
StaticModel(SymbolTable& symbol_table_arg, NumericalConstants& num_constants,
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg);
StaticModel(const StaticModel& m);
StaticModel& operator=(const StaticModel& m);
......@@ -155,12 +138,15 @@ public:
\param eval_context evaluation context for normalization
\param no_tmp_terms if true, no temporary terms will be computed in the static files
\param derivsOrder order of derivation with respect to endogenous
\param paramsDerivsOrder order of derivatives w.r. to a pair (endogenous, parameter) to be computed
\param paramsDerivsOrder order of derivatives w.r. to a pair (endogenous, parameter) to be
computed
*/
void computingPass(int derivsOrder, int paramsDerivsOrder, const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll);
void computingPass(int derivsOrder, int paramsDerivsOrder, const eval_context_t& eval_context,
bool no_tmp_terms, bool block, bool use_dll);
//! Writes static model file (+ bytecode)
void writeStaticFile(const string &basename, bool use_dll, const string &mexext, const filesystem::path &matlabroot, bool julia) const;
void writeStaticFile(const string& basename, bool use_dll, const string& mexext,
const filesystem::path& matlabroot, bool julia) const;
//! Write JSON Output (used by PlannerObjectiveStatement)
void writeJsonOutput(ostream& output) const;
......@@ -192,16 +178,20 @@ public:
void addAllParamDerivId(set<int>& deriv_id_set) override;
// Fills the ramsey_multipliers_derivatives structure (see the comment there)
void computeRamseyMultipliersDerivatives(int ramsey_orig_endo_nbr, bool is_matlab, bool no_tmp_terms);
void computeRamseyMultipliersDerivatives(int ramsey_orig_endo_nbr, bool is_matlab,
bool no_tmp_terms);
// Writes the sparse indices of ramsey_multipliers_derivatives to the driver file
void writeDriverRamseyMultipliersDerivativesSparseIndices(ostream& output) const;
// Writes ramsey_multipliers_derivatives (MATLAB/Octave version)
void writeRamseyMultipliersDerivativesMFile(const string &basename, int ramsey_orig_endo_nbr) const;
void writeRamseyMultipliersDerivativesMFile(const string& basename,
int ramsey_orig_endo_nbr) const;
// Writes ramsey_multipliers_derivatives (C version)
void writeRamseyMultipliersDerivativesCFile(const string &basename, const string &mexext, const filesystem::path &matlabroot, int ramsey_orig_endo_nbr) const;
void writeRamseyMultipliersDerivativesCFile(const string& basename, const string& mexext,
const filesystem::path& matlabroot,
int ramsey_orig_endo_nbr) const;
int
getMFS() const override
......@@ -217,10 +207,11 @@ StaticModel::writeParamsDerivativesFile(const string &basename) const
if (!params_derivatives.size())
return;
constexpr ExprNodeOutputType output_type { julia ? ExprNodeOutputType::juliaStaticModel : ExprNodeOutputType::matlabStaticModel };
constexpr ExprNodeOutputType output_type {julia ? ExprNodeOutputType::juliaStaticModel
: ExprNodeOutputType::matlabStaticModel};
auto [tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output, g3p_output]
{ writeParamsDerivativesFileHelper<output_type>() };
auto [tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output,
g3p_output] {writeParamsDerivativesFileHelper<output_type>()};
// g3p_output is ignored
if constexpr (!julia)
......@@ -232,56 +223,96 @@ StaticModel::writeParamsDerivativesFile(const string &basename) const
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
paramsDerivsFile << "function [rp, gp, rpp, gpp, hp] = static_params_derivs(y, x, params)" << endl
paramsDerivsFile
<< "function [rp, gp, rpp, gpp, hp] = static_params_derivs(y, x, params)" << endl
<< "%" << endl
<< "% Status : Computes derivatives of the static model with respect to the parameters" << endl
<< "% Status : Computes derivatives of the static model with respect to the parameters"
<< endl
<< "%" << endl
<< "% Inputs : " << endl
<< "% y [M_.endo_nbr by 1] double vector of endogenous variables in declaration order" << endl
<< "% x [M_.exo_nbr by 1] double vector of exogenous variables in declaration order" << endl
<< "% params [M_.param_nbr by 1] double vector of parameter values in declaration order" << endl
<< "% y [M_.endo_nbr by 1] double vector of endogenous variables in "
"declaration order"
<< endl
<< "% x [M_.exo_nbr by 1] double vector of exogenous variables in "
"declaration order"
<< endl
<< "% params [M_.param_nbr by 1] double vector of parameter values in declaration "
"order"
<< endl
<< "%" << endl
<< "% Outputs:" << endl
<< "% rp [M_.eq_nbr by #params] double Jacobian matrix of static model equations with respect to parameters " << endl
<< "% Dynare may prepend or append auxiliary equations, see M_.aux_vars" << endl
<< "% gp [M_.endo_nbr by M_.endo_nbr by #params] double Derivative of the Jacobian matrix of the static model equations with respect to the parameters" << endl
<< "% rows: variables in declaration order" << endl
<< "% rows: equations in order of declaration" << endl
<< "% rpp [#second_order_residual_terms by 4] double Hessian matrix of second derivatives of residuals with respect to parameters;" << endl
<< "% rows: respective derivative term" << endl
<< "% 1st column: equation number of the term appearing" << endl
<< "% 2nd column: number of the first parameter in derivative" << endl
<< "% 3rd column: number of the second parameter in derivative" << endl
<< "% 4th column: value of the Hessian term" << endl
<< "% gpp [#second_order_Jacobian_terms by 5] double Hessian matrix of second derivatives of the Jacobian with respect to the parameters;" << endl
<< "% rows: respective derivative term" << endl
<< "% 1st column: equation number of the term appearing" << endl
<< "% 2nd column: column number of variable in Jacobian of the static model" << endl
<< "% 3rd column: number of the first parameter in derivative" << endl
<< "% 4th column: number of the second parameter in derivative" << endl
<< "% 5th column: value of the Hessian term" << endl
<< "% rp [M_.eq_nbr by #params] double Jacobian matrix of static model "
"equations with respect to parameters "
<< endl
<< "% Dynare may prepend or append "
"auxiliary equations, see M_.aux_vars"
<< endl
<< "% gp [M_.endo_nbr by M_.endo_nbr by #params] double Derivative of the "
"Jacobian matrix of the static model equations with respect to the parameters"
<< endl
<< "% rows: variables in "
"declaration order"
<< endl
<< "% rows: equations in order "
"of declaration"
<< endl
<< "% rpp [#second_order_residual_terms by 4] double Hessian matrix of second "
"derivatives of residuals with respect to parameters;"
<< endl
<< "% rows: respective "
"derivative term"
<< endl
<< "% 1st column: equation "
"number of the term appearing"
<< endl
<< "% 2nd column: number of "
"the first parameter in derivative"
<< endl
<< "% 3rd column: number of "
"the second parameter in derivative"
<< endl
<< "% 4th column: value of "
"the Hessian term"
<< endl
<< "% gpp [#second_order_Jacobian_terms by 5] double Hessian matrix of second "
"derivatives of the Jacobian with respect to the parameters;"
<< endl
<< "% rows: respective "
"derivative term"
<< endl
<< "% 1st column: equation "
"number of the term appearing"
<< endl
<< "% 2nd column: column "
"number of variable in Jacobian of the static model"
<< endl
<< "% 3rd column: number of "
"the first parameter in derivative"
<< endl
<< "% 4th column: number of "
"the second parameter in derivative"
<< endl
<< "% 5th column: value of "
"the Hessian term"
<< endl
<< "%" << endl
<< "%" << endl
<< "% Warning : this file is generated automatically by Dynare" << endl
<< "% from model file (.mod)" << endl << endl
<< "% from model file (.mod)" << endl
<< endl
<< "T = NaN(" << params_derivs_temporary_terms_idxs.size() << ",1);" << endl
<< tt_output.str()
<< "rp = zeros(" << equations.size() << ", "
<< symbol_table.param_nbr() << ");" << endl
<< rp_output.str()
<< "gp = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ", "
<< tt_output.str() << "rp = zeros(" << equations.size() << ", "
<< symbol_table.param_nbr() << ");" << endl
<< gp_output.str()
<< "if nargout >= 3" << endl
<< rp_output.str() << "gp = zeros(" << equations.size() << ", " << symbol_table.endo_nbr()
<< ", " << symbol_table.param_nbr() << ");" << endl
<< gp_output.str() << "if nargout >= 3" << endl
<< "rpp = zeros(" << params_derivatives.at({0, 2}).size() << ",4);" << endl
<< rpp_output.str()
<< "gpp = zeros(" << params_derivatives.at({ 1, 2 }).size() << ",5);" << endl
<< gpp_output.str()
<< "end" << endl
<< rpp_output.str() << "gpp = zeros(" << params_derivatives.at({1, 2}).size() << ",5);"
<< endl
<< gpp_output.str() << "end" << endl
<< "if nargout >= 5" << endl
<< "hp = zeros(" << params_derivatives.at({2, 1}).size() << ",5);" << endl
<< hp_output.str()
<< "end" << endl
<< hp_output.str() << "end" << endl
<< "end" << endl;
paramsDerivsFile.close();
}
......@@ -293,24 +324,22 @@ StaticModel::writeParamsDerivativesFile(const string &basename) const
<< "#" << endl
<< "function static_params_derivs(y, x, params)" << endl
<< "@inbounds begin" << endl
<< tt_output.str()
<< "rp = zeros(" << equations.size() << ", "
<< symbol_table.param_nbr() << ");" << endl
<< rp_output.str()
<< "gp = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ", "
<< tt_output.str() << "rp = zeros(" << equations.size() << ", "
<< symbol_table.param_nbr() << ");" << endl
<< gp_output.str()
<< "rpp = zeros(" << params_derivatives.at({ 0, 2 }).size() << ",4);" << endl
<< rpp_output.str()
<< "gpp = zeros(" << params_derivatives.at({ 1, 2 }).size() << ",5);" << endl
<< gpp_output.str()
<< "hp = zeros(" << params_derivatives.at({ 2, 1 }).size() << ",5);" << endl
<< hp_output.str()
<< "end" << endl
<< rp_output.str() << "gp = zeros(" << equations.size() << ", "
<< symbol_table.endo_nbr() << ", " << symbol_table.param_nbr() << ");" << endl
<< gp_output.str() << "rpp = zeros(" << params_derivatives.at({0, 2}).size() << ",4);"
<< endl
<< rpp_output.str() << "gpp = zeros(" << params_derivatives.at({1, 2}).size() << ",5);"
<< endl
<< gpp_output.str() << "hp = zeros(" << params_derivatives.at({2, 1}).size() << ",5);"
<< endl
<< hp_output.str() << "end" << endl
<< "return (rp, gp, rpp, gpp, hp)" << endl
<< "end" << endl;
writeToFileIfModified(output, filesystem::path{basename} / "model" / "julia" / "StaticParamsDerivs.jl");
writeToFileIfModified(output, filesystem::path {basename} / "model" / "julia"
/ "StaticParamsDerivs.jl");
}
}
......@@ -321,18 +350,16 @@ StaticModel::writeRamseyMultipliersDerivativesHelper(ostream &output) const
// Write temporary terms (which includes external function stuff)
deriv_node_temp_terms_t tef_terms;
temporary_terms_t unused_tt_copy;
writeTemporaryTerms<output_type>(ramsey_multipliers_derivatives_temporary_terms,
unused_tt_copy,
ramsey_multipliers_derivatives_temporary_terms_idxs,
output, tef_terms);
writeTemporaryTerms<output_type>(ramsey_multipliers_derivatives_temporary_terms, unused_tt_copy,
ramsey_multipliers_derivatives_temporary_terms_idxs, output,
tef_terms);
// Write chain rule derivatives
for (int k {0};
auto &[row_col, d] : ramsey_multipliers_derivatives)
for (int k {0}; auto& [row_col, d] : ramsey_multipliers_derivatives)
{
output << "g1m_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type) << RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=";
d->writeOutput(output, output_type, ramsey_multipliers_derivatives_temporary_terms,
ramsey_multipliers_derivatives_temporary_terms_idxs, tef_terms);
output << ";" << endl;
......
/*
* Copyright © 2018-2023 Dynare Team
* Copyright © 2018-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -21,8 +21,8 @@
#include <cassert>
#include <numeric>
#include "SubModel.hh"
#include "DynamicModel.hh"
#include "SubModel.hh"
TrendComponentModelTable::TrendComponentModelTable(SymbolTable& symbol_table_arg) :
symbol_table {symbol_table_arg}
......@@ -30,8 +30,7 @@ TrendComponentModelTable::TrendComponentModelTable(SymbolTable &symbol_table_arg
}
void
TrendComponentModelTable::addTrendComponentModel(string name_arg,
vector<string> eqtags_arg,
TrendComponentModelTable::addTrendComponentModel(string name_arg, vector<string> eqtags_arg,
vector<string> target_eqtags_arg)
{
if (isExistingTrendComponentModelName(name_arg))
......@@ -45,8 +44,10 @@ TrendComponentModelTable::addTrendComponentModel(string name_arg,
}
void
TrendComponentModelTable::setVals(map<string, vector<int>> eqnums_arg, map<string, vector<int>> target_eqnums_arg,
map<string, vector<int>> lhs_arg, map<string, vector<expr_t>> lhs_expr_t_arg)
TrendComponentModelTable::setVals(map<string, vector<int>> eqnums_arg,
map<string, vector<int>> target_eqnums_arg,
map<string, vector<int>> lhs_arg,
map<string, vector<expr_t>> lhs_expr_t_arg)
{
eqnums = move(eqnums_arg);
target_eqnums = move(target_eqnums_arg);
......@@ -57,7 +58,7 @@ TrendComponentModelTable::setVals(map<string, vector<int>> eqnums_arg, map<strin
{
vector<int> nontrend_vec;
for (auto eq : it.second)
if (find(target_eqnums[it.first].begin(), target_eqnums[it.first].end(), eq) == target_eqnums[it.first].end())
if (ranges::find(target_eqnums[it.first], eq) == target_eqnums[it.first].end())
nontrend_vec.push_back(eq);
nontarget_eqnums[it.first] = nontrend_vec;
}
......@@ -68,11 +69,13 @@ TrendComponentModelTable::setVals(map<string, vector<int>> eqnums_arg, map<strin
vector<int> lhsv = getLhs(name);
vector<int> eqnumsv = getEqNums(name);
for (int nontrend_it : getNonTargetEqNums(name))
nontarget_lhs_vec.push_back(lhsv.at(distance(eqnumsv.begin(), find(eqnumsv.begin(), eqnumsv.end(), nontrend_it))));
nontarget_lhs_vec.push_back(
lhsv.at(ranges::distance(eqnumsv.begin(), ranges::find(eqnumsv, nontrend_it))));
nontarget_lhs[name] = nontarget_lhs_vec;
for (int trend_it : getTargetEqNums(name))
target_lhs_vec.push_back(lhsv.at(distance(eqnumsv.begin(), find(eqnumsv.begin(), eqnumsv.end(), trend_it))));
target_lhs_vec.push_back(
lhsv.at(ranges::distance(eqnumsv.begin(), ranges::find(eqnumsv, trend_it))));
target_lhs[name] = target_lhs_vec;
}
}
......@@ -139,8 +142,8 @@ TrendComponentModelTable::checkModelName(const string &name_arg) const
{
if (!isExistingTrendComponentModelName(name_arg))
{
cerr << name_arg
<< " is not a recognized equation tag of a trend component model equation" << endl;
cerr << name_arg << " is not a recognized equation tag of a trend component model equation"
<< endl;
exit(EXIT_FAILURE);
}
}
......@@ -256,7 +259,8 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
}
ar_ec_output << "function [AR, A0, A0star] = trend_component_ar_a0(model_name, params)" << endl
<< "%function [AR, A0, A0star] = trend_component_ar_a0(model_name, params)" << endl
<< "% File automatically generated by the Dynare preprocessor" << endl << endl;
<< "% File automatically generated by the Dynare preprocessor" << endl
<< endl;
for (const auto& name : names)
{
......@@ -264,41 +268,32 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
<< "M_.trend_component." << name << ".eqtags = {";
for (const auto& it : eqtags.at(name))
output << "'" << it << "'; ";
output << "};" << endl
<< "M_.trend_component." << name << ".eqn = [";
output << "};" << endl << "M_.trend_component." << name << ".eqn = [";
for (auto it : eqnums.at(name))
output << it + 1 << " ";
output << "];" << endl
<< "M_.trend_component." << name << ".targets = [";
output << "];" << endl << "M_.trend_component." << name << ".targets = [";
for (auto it : eqnums.at(name))
if (find(target_eqnums.at(name).begin(), target_eqnums.at(name).end(), it)
== target_eqnums.at(name).end())
if (ranges::find(target_eqnums.at(name), it) == target_eqnums.at(name).end())
output << "false ";
else
output << "true ";
output << "];" << endl
<< "M_.trend_component." << name << ".lhs = [";
output << "];" << endl << "M_.trend_component." << name << ".lhs = [";
for (auto it : lhs.at(name))
output << symbol_table.getTypeSpecificID(it) + 1 << " ";
output << "];" << endl
<< "M_.trend_component." << name << ".max_lag = [";
output << "];" << endl << "M_.trend_component." << name << ".max_lag = [";
for (auto it : max_lags.at(name))
output << it << " ";
output << "];" << endl
<< "M_.trend_component." << name << ".diff = [";
output << "];" << endl << "M_.trend_component." << name << ".diff = [";
for (bool it : diff.at(name))
output << boolalpha << it << " ";
output << "];" << endl
<< "M_.trend_component." << name << ".orig_diff_var = [";
output << "];" << endl << "M_.trend_component." << name << ".orig_diff_var = [";
for (const auto& it : orig_diff_var.at(name))
output << (it ? symbol_table.getTypeSpecificID(*it) + 1 : -1) << " ";
output << "];" << endl
<< "M_.trend_component." << name << ".nonstationary = [";
output << "];" << endl << "M_.trend_component." << name << ".nonstationary = [";
for (size_t i = 0; i < diff.at(name).size(); i++)
output << "true ";
output << "];" << endl;
for (int i{1};
const auto &it : rhs.at(name))
for (int i {1}; const auto& it : rhs.at(name))
{
output << "M_.trend_component." << name << ".rhs.vars_at_eq{" << i << "}.var = [";
for (auto [var, lag] : it)
......@@ -318,14 +313,14 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
vector<string> target_eqtags_vec = target_eqtags.at(name);
output << "M_.trend_component." << name << ".target_eqtags = {";
for (auto it : target_eqtags_vec)
for (const auto& it : target_eqtags_vec)
output << "'" << it << "';";
output << "};" << endl;
vector<string> eqtags_vec = eqtags.at(name);
output << "M_.trend_component." << name << ".target_eqn = [";
for (auto it : target_eqtags_vec)
output << distance(eqtags_vec.begin(), find(eqtags_vec.begin(), eqtags_vec.end(), it)) + 1 << " ";
for (const auto& it : target_eqtags_vec)
output << ranges::distance(eqtags_vec.begin(), ranges::find(eqtags_vec, it)) + 1 << " ";
output << "];" << endl;
vector<int> target_lhs_vec = getTargetLhs(name);
......@@ -333,11 +328,13 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
ar_ec_output << "if strcmp(model_name, '" << name << "')" << endl
<< " % AR" << endl
<< " AR = zeros(" << nontarget_lhs_vec.size() << ", " << nontarget_lhs_vec.size() << ", " << getMaxLag(name) << ");" << endl;
<< " AR = zeros(" << nontarget_lhs_vec.size() << ", "
<< nontarget_lhs_vec.size() << ", " << getMaxLag(name) << ");" << endl;
for (const auto& [key, expr] : AR.at(name))
{
auto [eqn, lag, lhs_symb_id] = key;
int colidx = static_cast<int>(distance(nontarget_lhs_vec.begin(), find(nontarget_lhs_vec.begin(), nontarget_lhs_vec.end(), lhs_symb_id)));
int colidx = static_cast<int>(ranges::distance(
nontarget_lhs_vec.begin(), ranges::find(nontarget_lhs_vec, lhs_symb_id)));
ar_ec_output << " AR(" << eqn + 1 << ", " << colidx + 1 << ", " << lag << ") = ";
expr->writeOutput(ar_ec_output, ExprNodeOutputType::matlabDynamicModel);
ar_ec_output << ";" << endl;
......@@ -345,7 +342,8 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
ar_ec_output << endl
<< " % A0" << endl
<< " A0 = zeros(" << nontarget_lhs_vec.size() << ", " << nontarget_lhs_vec.size() << ");" << endl;
<< " A0 = zeros(" << nontarget_lhs_vec.size() << ", "
<< nontarget_lhs_vec.size() << ");" << endl;
for (const auto& [key, expr] : A0.at(name))
{
auto [eqn, colidx] = key;
......@@ -356,7 +354,8 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
ar_ec_output << endl
<< " % A0star" << endl
<< " A0star = zeros(" << nontarget_lhs_vec.size() << ", " << target_lhs_vec.size() << ");" << endl;
<< " A0star = zeros(" << nontarget_lhs_vec.size() << ", "
<< target_lhs_vec.size() << ");" << endl;
for (const auto& [key, expr] : A0star.at(name))
{
auto [eqn, colidx] = key;
......@@ -365,8 +364,7 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
ar_ec_output << ";" << endl;
}
ar_ec_output << " return" << endl
<< "end" << endl << endl;
ar_ec_output << " return" << endl << "end" << endl << endl;
}
ar_ec_output << "error([model_name ' is not a valid trend_component_model name'])" << endl
<< "end" << endl;
......@@ -376,24 +374,21 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
void
TrendComponentModelTable::writeJsonOutput(ostream& output) const
{
for (bool printed_something{false};
const auto &name : names)
for (bool printed_something {false}; const auto& name : names)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"statementName": "trend_component_model",)"
<< R"("model_name": ")" << name << R"(",)"
<< R"("eqtags": [)";
for (bool printed_something2{false};
const auto &it : eqtags.at(name))
for (bool printed_something2 {false}; const auto& it : eqtags.at(name))
{
if (exchange(printed_something2, true))
output << ", ";
output << R"(")" << it << R"(")";
}
output << R"(], "target_eqtags": [)";
for (bool printed_something2{false};
const auto &it : target_eqtags.at(name))
for (bool printed_something2 {false}; const auto& it : target_eqtags.at(name))
{
if (exchange(printed_something2, true))
output << ", ";
......@@ -403,8 +398,7 @@ TrendComponentModelTable::writeJsonOutput(ostream &output) const
}
}
VarModelTable::VarModelTable(SymbolTable &symbol_table_arg) :
symbol_table{symbol_table_arg}
VarModelTable::VarModelTable(SymbolTable& symbol_table_arg) : symbol_table {symbol_table_arg}
{
}
......@@ -436,32 +430,31 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
exit(EXIT_FAILURE);
}
ar_output << "function [ar, a0, constants] = varmatrices(model_name, params, reducedform)" << endl
<< "% File automatically generated by the Dynare preprocessor" << endl << endl
<< "% File automatically generated by the Dynare preprocessor" << endl
<< endl
<< "if nargin<3" << endl
<< " reducedform = false;" << endl
<< "end" << endl << endl;
<< "end" << endl
<< endl;
for (const auto& name : names)
{
output << "M_.var." << name << ".model_name = '" << name << "';" << endl
<< "M_.var." << name << ".structural = " << boolalpha << structural.at(name) << ";" << endl
<< "M_.var." << name << ".structural = " << boolalpha << structural.at(name) << ";"
<< endl
<< "M_.var." << name << ".eqtags = {";
for (const auto& it : eqtags.at(name))
output << "'" << it << "'; ";
output << "};" << endl
<< "M_.var." << name << ".eqn = [";
output << "};" << endl << "M_.var." << name << ".eqn = [";
for (auto it : eqnums.at(name))
output << it + 1 << " ";
output << "];" << endl
<< "M_.var." << name << ".lhs = [";
output << "];" << endl << "M_.var." << name << ".lhs = [";
for (auto it : lhs.at(name))
output << symbol_table.getTypeSpecificID(it) + 1 << " ";
output << "];" << endl
<< "M_.var." << name << ".max_lag = [";
output << "];" << endl << "M_.var." << name << ".max_lag = [";
for (auto it : max_lags.at(name))
output << it << " ";
output << "];" << endl
<< "M_.var." << name << ".diff = [";
output << "];" << endl << "M_.var." << name << ".diff = [";
for (bool it : diff.at(name))
output << boolalpha << it << " ";
output << "];" << endl
......@@ -470,14 +463,12 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
for (const auto& it : orig_diff_var.at(name))
output << (it ? symbol_table.getTypeSpecificID(*it) + 1 : -1) << " ";
output << "];" << endl;
for (int i{1};
const auto &it : rhs.at(name))
for (int i {1}; const auto& it : rhs.at(name))
{
output << "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.var = [";
for (auto [var, lag] : it)
output << symbol_table.getTypeSpecificID(var) + 1 << " ";
output << "];" << endl
<< "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.lag = [";
output << "];" << endl << "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.lag = [";
for (auto [var, lag] : it)
output << lag << " ";
output << "];" << endl;
......@@ -487,21 +478,23 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
vector<int> lhs = getLhsOrigIds(name);
ar_output << "if strcmp(model_name, '" << name << "')" << endl
<< " ar = zeros(" << lhs.size() << ", " << lhs.size() << ", " << getMaxLag(name) << ");" << endl;
<< " ar = zeros(" << lhs.size() << ", " << lhs.size() << ", " << getMaxLag(name)
<< ");" << endl;
for (const auto& [key, expr] : AR.at(name))
{
auto [eqn, lag, lhs_symb_id] = key;
int colidx = static_cast<int>(distance(lhs.begin(), find(lhs.begin(), lhs.end(), lhs_symb_id)));
int colidx
= static_cast<int>(ranges::distance(lhs.begin(), ranges::find(lhs, lhs_symb_id)));
ar_output << " ar(" << eqn + 1 << "," << colidx + 1 << "," << lag << ") = ";
expr->writeOutput(ar_output, ExprNodeOutputType::matlabDynamicModel);
ar_output << ";" << endl;
}
ar_output << " if nargout>1" << endl
<< " a0 = eye(" << lhs.size() << ");" << endl;
ar_output << " if nargout>1" << endl << " a0 = eye(" << lhs.size() << ");" << endl;
for (const auto& [key, expr] : A0.at(name))
{
auto [eqn, lhs_symb_id] = key;
int colidx = static_cast<int>(distance(lhs.begin(), find(lhs.begin(), lhs.end(), lhs_symb_id)));
int colidx
= static_cast<int>(ranges::distance(lhs.begin(), ranges::find(lhs, lhs_symb_id)));
if (eqn != colidx)
{
ar_output << " a0(" << eqn + 1 << "," << colidx + 1 << ") = ";
......@@ -532,7 +525,8 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
<< " end" << endl
<< " end" << endl
<< " return" << endl
<< "end" << endl << endl;
<< "end" << endl
<< endl;
}
ar_output << "error('%s is not a valid var_model name', model_name)" << endl;
ar_output.close();
......@@ -541,16 +535,14 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
void
VarModelTable::writeJsonOutput(ostream& output) const
{
for (bool printed_something{false};
const auto &name : names)
for (bool printed_something {false}; const auto& name : names)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"statementName": "var_model",)"
<< R"("model_name": ")" << name << R"(",)"
<< R"("eqtags": [)";
for (bool printed_something2{false};
const auto &it : eqtags.at(name))
for (bool printed_something2 {false}; const auto& it : eqtags.at(name))
{
if (exchange(printed_something2, true))
output << ", ";
......@@ -584,8 +576,7 @@ VarModelTable::checkModelName(const string &name_arg) const
{
if (!isExistingVarModelName(name_arg))
{
cerr << name_arg
<< " is not a recognized equation tag of a VAR model equation" << endl;
cerr << name_arg << " is not a recognized equation tag of a VAR model equation" << endl;
exit(EXIT_FAILURE);
}
}
......@@ -600,7 +591,7 @@ void
VarModelTable::setLhs(map<string, vector<int>> lhs_arg)
{
lhs = move(lhs_arg);
for (auto it : lhs)
for (const auto& it : lhs)
{
vector<int> lhsvec;
for (auto ids : it.second)
......@@ -732,14 +723,15 @@ VarModelTable::getLhsExprT(const string &name_arg) const
return lhs_expr_t.at(name_arg);
}
VarExpectationModelTable::VarExpectationModelTable(SymbolTable& symbol_table_arg) :
symbol_table {symbol_table_arg}
{
}
void
VarExpectationModelTable::addVarExpectationModel(string name_arg, expr_t expression_arg, string aux_model_name_arg, string horizon_arg, expr_t discount_arg, int time_shift_arg)
VarExpectationModelTable::addVarExpectationModel(string name_arg, expr_t expression_arg,
string aux_model_name_arg, string horizon_arg,
expr_t discount_arg, int time_shift_arg)
{
if (isExistingVarExpectationModelName(name_arg))
{
......@@ -780,13 +772,14 @@ VarExpectationModelTable::writeOutput(ostream &output) const
auto& vpc = vars_params_constants.at(name);
if (!vpc.size())
{
cerr << "ERROR: VarExpectationModelStatement::writeOutput: matchExpression() has not been called" << endl;
cerr << "ERROR: VarExpectationModelStatement::writeOutput: matchExpression() has not "
"been called"
<< endl;
exit(EXIT_FAILURE);
}
ostringstream vars_list, params_list, constants_list;
for (bool printed_something{false};
const auto &[variable_id, param_id, constant] : vpc)
for (bool printed_something {false}; const auto& [variable_id, param_id, constant] : vpc)
{
if (exchange(printed_something, true))
{
......@@ -805,9 +798,9 @@ VarExpectationModelTable::writeOutput(ostream &output) const
<< mstruct << ".expr.params = [ " << params_list.str() << " ];" << endl
<< mstruct << ".expr.constants = [ " << constants_list.str() << " ];" << endl;
if (auto disc_var = dynamic_cast<const VariableNode *>(discount.at(name));
disc_var)
output << mstruct << ".discount_index = " << symbol_table.getTypeSpecificID(disc_var->symb_id) + 1 << ';' << endl;
if (auto disc_var = dynamic_cast<const VariableNode*>(discount.at(name)); disc_var)
output << mstruct << ".discount_index = " << disc_var->getTypeSpecificID() + 1 << ';'
<< endl;
else
{
output << mstruct << ".discount_value = ";
......@@ -822,14 +815,18 @@ VarExpectationModelTable::writeOutput(ostream &output) const
}
void
VarExpectationModelTable::substituteUnaryOpsInExpression(const lag_equivalence_table_t &nodes, ExprNode::subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs)
VarExpectationModelTable::substituteUnaryOpsInExpression(const lag_equivalence_table_t& nodes,
ExprNode::subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs)
{
for (const auto& name : names)
expression[name] = expression[name]->substituteUnaryOpNodes(nodes, subst_table, neweqs);
}
void
VarExpectationModelTable::substituteDiffNodesInExpression(const lag_equivalence_table_t &nodes, ExprNode::subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs)
VarExpectationModelTable::substituteDiffNodesInExpression(const lag_equivalence_table_t& nodes,
ExprNode::subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs)
{
for (const auto& name : names)
expression[name] = expression[name]->substituteDiff(nodes, subst_table, neweqs);
......@@ -837,7 +834,8 @@ VarExpectationModelTable::substituteDiffNodesInExpression(const lag_equivalence_
void
VarExpectationModelTable::transformPass(ExprNode::subst_table_t& diff_subst_table,
DynamicModel &dynamic_model, const VarModelTable &var_model_table,
DynamicModel& dynamic_model,
const VarModelTable& var_model_table,
const TrendComponentModelTable& trend_component_model_table)
{
map<string, expr_t> var_expectation_subst_table;
......@@ -880,7 +878,8 @@ VarExpectationModelTable::transformPass(ExprNode::subst_table_t &diff_subst_tabl
}
catch (ExprNode::MatchFailureException& e)
{
cerr << "ERROR: expression in var_expectation_model " << name << " is not of the expected form: " << e.message << endl;
cerr << "ERROR: expression in var_expectation_model " << name
<< " is not of the expected form: " << e.message << endl;
exit(EXIT_FAILURE);
}
......@@ -892,25 +891,30 @@ VarExpectationModelTable::transformPass(ExprNode::subst_table_t &diff_subst_tabl
/* If the auxiliary model is a VAR, add a parameter corresponding to
the constant. */
string constant_param_name = "var_expectation_model_" + name + "_constant";
int constant_param_id = symbol_table.addSymbol(constant_param_name, SymbolType::parameter);
int constant_param_id
= symbol_table.addSymbol(constant_param_name, SymbolType::parameter);
aux_param_symb_ids[name].push_back(constant_param_id);
subst_expr = dynamic_model.AddPlus(subst_expr, dynamic_model.AddVariable(constant_param_id));
subst_expr
= dynamic_model.AddPlus(subst_expr, dynamic_model.AddVariable(constant_param_id));
}
for (int lag = 0; lag < max_lag; lag++)
for (auto variable : lhs)
{
string param_name = "var_expectation_model_" + name + '_' + symbol_table.getName(variable) + '_' + to_string(lag);
string param_name = "var_expectation_model_" + name + '_'
+ symbol_table.getName(variable) + '_' + to_string(lag);
int new_param_id = symbol_table.addSymbol(param_name, SymbolType::parameter);
aux_param_symb_ids[name].push_back(new_param_id);
subst_expr = dynamic_model.AddPlus(subst_expr,
dynamic_model.AddTimes(dynamic_model.AddVariable(new_param_id),
subst_expr = dynamic_model.AddPlus(
subst_expr, dynamic_model.AddTimes(
dynamic_model.AddVariable(new_param_id),
dynamic_model.AddVariable(variable, -lag + time_shift[name])));
}
if (var_expectation_subst_table.contains(name))
{
cerr << "ERROR: model name '" << name << "' is used by several var_expectation_model statements" << endl;
cerr << "ERROR: model name '" << name
<< "' is used by several var_expectation_model statements" << endl;
exit(EXIT_FAILURE);
}
var_expectation_subst_table[name] = subst_expr;
......@@ -926,8 +930,7 @@ VarExpectationModelTable::transformPass(ExprNode::subst_table_t &diff_subst_tabl
void
VarExpectationModelTable::writeJsonOutput(ostream& output) const
{
for (bool printed_something{false};
const auto &name : names)
for (bool printed_something {false}; const auto& name : names)
{
if (exchange(printed_something, true))
output << ", ";
......@@ -941,19 +944,17 @@ VarExpectationModelTable::writeJsonOutput(ostream &output) const
<< R"("discount": ")";
discount.at(name)->writeOutput(output);
output << R"(", )"
<< R"("time_shift": )" << time_shift.at(name)
<< R"(})";
<< R"("time_shift": )" << time_shift.at(name) << R"(})";
}
}
PacModelTable::PacModelTable(SymbolTable &symbol_table_arg) :
symbol_table{symbol_table_arg}
PacModelTable::PacModelTable(SymbolTable& symbol_table_arg) : symbol_table {symbol_table_arg}
{
}
void
PacModelTable::addPacModel(string name_arg, string aux_model_name_arg, string discount_arg, expr_t growth_arg, string auxname_arg, PacTargetKind kind_arg)
PacModelTable::addPacModel(string name_arg, string aux_model_name_arg, string discount_arg,
expr_t growth_arg, string auxname_arg, PacTargetKind kind_arg)
{
if (isExistingPacModelName(name_arg))
{
......@@ -990,7 +991,10 @@ PacModelTable::checkPass(ModFileStructure &mod_file_struct)
{
if (target_info.contains(name))
{
cerr << "ERROR: for PAC model '" << name << "', it is not possible to declare a 'growth' option in the 'pac_model' command when there is also a 'pac_target_info' block" << endl;
cerr << "ERROR: for PAC model '" << name
<< "', it is not possible to declare a 'growth' option in the 'pac_model' command "
"when there is also a 'pac_target_info' block"
<< endl;
exit(EXIT_FAILURE);
}
gv->collectVariables(SymbolType::exogenous, mod_file_struct.pac_params);
......@@ -999,7 +1003,10 @@ PacModelTable::checkPass(ModFileStructure &mod_file_struct)
for (auto& [name, auxn] : auxname)
if (!auxn.empty() && target_info.contains(name))
{
cerr << "ERROR: for PAC model '" << name << "', it is not possible to declare an 'auxname' option in the 'pac_model' command when there is also a 'pac_target_info' block" << endl;
cerr << "ERROR: for PAC model '" << name
<< "', it is not possible to declare an 'auxname' option in the 'pac_model' command "
"when there is also a 'pac_target_info' block"
<< endl;
exit(EXIT_FAILURE);
}
......@@ -1008,18 +1015,25 @@ PacModelTable::checkPass(ModFileStructure &mod_file_struct)
{
if (target_info.contains(name))
{
cerr << "ERROR: for PAC model '" << name << "', it is not possible to declare a 'kind' option in the 'pac_model' command when there is also a 'pac_target_info' block" << endl;
cerr << "ERROR: for PAC model '" << name
<< "', it is not possible to declare a 'kind' option in the 'pac_model' command "
"when there is also a 'pac_target_info' block"
<< endl;
exit(EXIT_FAILURE);
}
if (aux_model_name[name].empty())
{
cerr << "ERROR: for PAC model '" << name << "', it is not possible to declare a 'kind' option in the 'pac_model' command since this is a MCE model" << endl;
cerr << "ERROR: for PAC model '" << name
<< "', it is not possible to declare a 'kind' option in the 'pac_model' command "
"since this is a MCE model"
<< endl;
exit(EXIT_FAILURE);
}
}
for (const auto& [name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
for (auto& [expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv,
gv_info] : get<2>(ti))
if (gv)
gv->collectVariables(SymbolType::exogenous, mod_file_struct.pac_params);
......@@ -1028,30 +1042,38 @@ PacModelTable::checkPass(ModFileStructure &mod_file_struct)
auto& [target, auxname_target_nonstationary, components] = ti;
if (!target)
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'target' statement" << endl;
cerr << "ERROR: the block 'pac_target_info(" << name
<< ")' is missing the 'target' statement" << endl;
exit(EXIT_FAILURE);
}
if (auxname_target_nonstationary.empty())
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'auxname_target_nonstationary' statement" << endl;
cerr << "ERROR: the block 'pac_target_info(" << name
<< ")' is missing the 'auxname_target_nonstationary' statement" << endl;
exit(EXIT_FAILURE);
}
int nonstationary_nb = 0;
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
for (auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : components)
{
if (auxname.empty())
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'auxname' statement in some 'component'" << endl;
cerr << "ERROR: the block 'pac_target_info(" << name
<< ")' is missing the 'auxname' statement in some 'component'" << endl;
exit(EXIT_FAILURE);
}
if (kind == PacTargetKind::unspecified)
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'kind' statement in some 'component'" << endl;
cerr << "ERROR: the block 'pac_target_info(" << name
<< ")' is missing the 'kind' statement in some 'component'" << endl;
exit(EXIT_FAILURE);
}
if (kind == PacTargetKind::ll && growth_component)
{
cerr << "ERROR: in the block 'pac_target_info(" << name << ")', a component of 'kind ll' (i.e. stationary) has a 'growth' option. This is not permitted." << endl;
cerr << "ERROR: in the block 'pac_target_info(" << name
<< ")', a component of 'kind ll' (i.e. stationary) has a 'growth' option. This "
"is not permitted."
<< endl;
exit(EXIT_FAILURE);
}
if (kind == PacTargetKind::dd || kind == PacTargetKind::dl)
......@@ -1059,21 +1081,27 @@ PacModelTable::checkPass(ModFileStructure &mod_file_struct)
}
if (!nonstationary_nb)
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' must contain at least one nonstationary component (i.e. of 'kind' equal to either 'dd' or 'dl')." << endl;
cerr << "ERROR: the block 'pac_target_info(" << name
<< ")' must contain at least one nonstationary component (i.e. of 'kind' equal to "
"either 'dd' or 'dl')."
<< endl;
exit(EXIT_FAILURE);
}
}
}
void
PacModelTable::substituteUnaryOpsInGrowth(const lag_equivalence_table_t &nodes, ExprNode::subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs)
PacModelTable::substituteUnaryOpsInGrowth(const lag_equivalence_table_t& nodes,
ExprNode::subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs)
{
for (auto& [name, gv] : growth)
if (gv)
gv = gv->substituteUnaryOpNodes(nodes, subst_table, neweqs);
for (auto& [name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
for (auto& [expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv,
gv_info] : get<2>(ti))
if (gv)
gv = gv->substituteUnaryOpNodes(nodes, subst_table, neweqs);
}
......@@ -1086,20 +1114,24 @@ PacModelTable::findDiffNodesInGrowth(lag_equivalence_table_t &diff_nodes) const
gv->findDiffNodes(diff_nodes);
for (const auto& [name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
for (auto& [expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv,
gv_info] : get<2>(ti))
if (gv)
gv->findDiffNodes(diff_nodes);
}
void
PacModelTable::substituteDiffNodesInGrowth(const lag_equivalence_table_t &diff_nodes, ExprNode::subst_table_t &diff_subst_table, vector<BinaryOpNode *> &neweqs)
PacModelTable::substituteDiffNodesInGrowth(const lag_equivalence_table_t& diff_nodes,
ExprNode::subst_table_t& diff_subst_table,
vector<BinaryOpNode*>& neweqs)
{
for (auto& [name, gv] : growth)
if (gv)
gv = gv->substituteDiff(diff_nodes, diff_subst_table, neweqs);
for (auto& [name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
for (auto& [expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv,
gv_info] : get<2>(ti))
if (gv)
gv = gv->substituteDiff(diff_nodes, diff_subst_table, neweqs);
}
......@@ -1108,8 +1140,8 @@ void
PacModelTable::transformPass(const lag_equivalence_table_t& unary_ops_nodes,
ExprNode::subst_table_t& unary_ops_subst_table,
const lag_equivalence_table_t& diff_nodes,
ExprNode::subst_table_t &diff_subst_table,
DynamicModel &dynamic_model, const VarModelTable &var_model_table,
ExprNode::subst_table_t& diff_subst_table, DynamicModel& dynamic_model,
const VarModelTable& var_model_table,
const TrendComponentModelTable& trend_component_model_table)
{
// model name → expression for pac_expectation
......@@ -1140,30 +1172,40 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
target = target->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: the 'target' expression of 'pac_target_info(" << name << ")' contains a variable with a unary operator that is not present in the model" << endl;
cerr
<< "ERROR: the 'target' expression of 'pac_target_info(" << name
<< ")' contains a variable with a unary operator that is not present in the model"
<< endl;
exit(EXIT_FAILURE);
}
target = target->substituteDiff(diff_nodes, diff_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: the 'target' expression of 'pac_target_info(" << name << ")' contains a diff'd variable that is not present in the model" << endl;
cerr << "ERROR: the 'target' expression of 'pac_target_info(" << name
<< ")' contains a diff'd variable that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
// …and in component expressions
auto& components = get<2>(target_info[name]);
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
for (auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : components)
{
component = component->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table, neweqs);
component = component->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table,
neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: a 'component' expression of 'pac_target_info(" << name << ")' contains a variable with a unary operator that is not present in the model" << endl;
cerr << "ERROR: a 'component' expression of 'pac_target_info(" << name
<< ")' contains a variable with a unary operator that is not present in the "
"model"
<< endl;
exit(EXIT_FAILURE);
}
component = component->substituteDiff(diff_nodes, diff_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: a 'component' expression of 'pac_target_info(" << name << ")' contains a diff'd variable that is not present in the model" << endl;
cerr << "ERROR: a 'component' expression of 'pac_target_info(" << name
<< ")' contains a diff'd variable that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
}
......@@ -1171,12 +1213,14 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
/* Fill the growth_info structure.
Cannot be done in an earlier pass since growth terms can be
transformed by DynamicModel::substituteDiff(). */
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
for (auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : components)
{
if (growth_component)
try
{
growth_component_info = growth_component->matchLinearCombinationOfVariablesPlusConstant();
growth_component_info
= growth_component->matchLinearCombinationOfVariablesPlusConstant();
}
catch (ExprNode::MatchFailureException& e)
{
......@@ -1193,21 +1237,28 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
}
catch (ExprNode::MatchFailureException)
{
cerr << "ERROR: there is no equation whose LHS is equal to the 'target' of 'pac_target_info(" << name << ")'" << endl;
cerr << "ERROR: there is no equation whose LHS is equal to the 'target' of "
"'pac_target_info("
<< name << ")'" << endl;
exit(EXIT_FAILURE);
}
// Substitute unary ops and diffs in that equation, before parsing (see dynare#1837)
target_expr = target_expr->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table, neweqs);
target_expr
= target_expr->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: the equation defining the target of 'pac_target_info(" << name << ")' contains a variable with a unary operator that is not present in the model" << endl;
cerr
<< "ERROR: the equation defining the target of 'pac_target_info(" << name
<< ")' contains a variable with a unary operator that is not present in the model"
<< endl;
exit(EXIT_FAILURE);
}
target_expr = target_expr->substituteDiff(diff_nodes, diff_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: the equation defining the target of 'pac_target_info(" << name << ")' contains a diff'd variable that is not present in the model" << endl;
cerr << "ERROR: the equation defining the target of 'pac_target_info(" << name
<< ")' contains a diff'd variable that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
......@@ -1220,38 +1271,51 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
}
catch (ExprNode::MatchFailureException)
{
cerr << "ERROR: the model equation defining the 'target' of 'pac_target_info(" << name << ")' is not of the right form (should be a linear combination of endogenous variables)" << endl;
cerr << "ERROR: the model equation defining the 'target' of 'pac_target_info(" << name
<< ")' is not of the right form (should be a linear combination of endogenous "
"variables)"
<< endl;
exit(EXIT_FAILURE);
}
// Associate the coefficients of the linear combination with the right components
for (auto [var, coeff] : terms)
if (auto it = find_if(components.begin(), components.end(),
if (auto it = ranges::find_if(
components,
[&](const auto& v) { return get<0>(v) == dynamic_model.AddVariable(var); });
it != components.end())
get<4>(*it) = coeff;
else
{
cerr << "ERROR: the model equation defining the 'target' of 'pac_target_info(" << name << ")' contains a variable (" << symbol_table.getName(var) << ") that is not declared as a 'component'" << endl;
cerr << "ERROR: the model equation defining the 'target' of 'pac_target_info("
<< name << ")' contains a variable (" << symbol_table.getName(var)
<< ") that is not declared as a 'component'" << endl;
exit(EXIT_FAILURE);
}
// Verify that all declared components appear in that equation
for (const auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
for (const auto& [component, growth_component, auxname, kind, coeff,
growth_neutrality_param, h_indices, original_growth_component,
growth_component_info] : components)
if (!coeff)
{
cerr << "ERROR: a 'component' of 'pac_target_info(" << name << ")' does not appear in the model equation defining the 'target'" << endl;
cerr << "ERROR: a 'component' of 'pac_target_info(" << name
<< ")' does not appear in the model equation defining the 'target'" << endl;
exit(EXIT_FAILURE);
}
/* Add the variable and equation defining the stationary part of the
target. Note that it includes the constant. */
expr_t yns = constant;
for (const auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
for (const auto& [component, growth_component, auxname, kind, coeff,
growth_neutrality_param, h_indices, original_growth_component,
growth_component_info] : components)
if (kind != PacTargetKind::ll)
yns = dynamic_model.AddPlus(yns, dynamic_model.AddTimes(coeff, component));
int target_nonstationary_id = symbol_table.addPacTargetNonstationaryAuxiliaryVar(get<1>(target_info[name]), yns);
expr_t neweq = dynamic_model.AddEqual(dynamic_model.AddVariable(target_nonstationary_id), yns);
int target_nonstationary_id
= symbol_table.addPacTargetNonstationaryAuxiliaryVar(get<1>(target_info[name]), yns);
expr_t neweq
= dynamic_model.AddEqual(dynamic_model.AddVariable(target_nonstationary_id), yns);
dynamic_model.addEquation(neweq, nullopt);
dynamic_model.addAuxEquation(neweq);
......@@ -1259,7 +1323,8 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
This needs to be done here, otherwise
DynamicModel::analyzePacEquationStructure() will not be able to
identify the error-correction part */
dynamic_model.substitutePacTargetNonstationary(name, dynamic_model.AddVariable(target_nonstationary_id, -1));
dynamic_model.substitutePacTargetNonstationary(
name, dynamic_model.AddVariable(target_nonstationary_id, -1));
}
// Collect some information about PAC models
......@@ -1280,7 +1345,8 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
max_lag = 0;
else
{
cerr << "Error: aux_model_name not recognized as VAR model or Trend Component model" << endl;
cerr << "Error: aux_model_name not recognized as VAR model or Trend Component model"
<< endl;
exit(EXIT_FAILURE);
}
dynamic_model.analyzePacEquationStructure(name, eq_name, equation_info);
......@@ -1296,7 +1362,10 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
}
catch (SymbolTable::AlreadyDeclaredException)
{
cerr << "The variable/parameter '" << param_name << "' conflicts with the auxiliary parameter that will be generated for the growth neutrality correction of the '" << name << "' PAC model. Please rename that parameter." << endl;
cerr << "The variable/parameter '" << param_name
<< "' conflicts with the auxiliary parameter that will be generated for the "
"growth neutrality correction of the '"
<< name << "' PAC model. Please rename that parameter." << endl;
exit(EXIT_FAILURE);
}
}
......@@ -1304,44 +1373,37 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
// Compute the expressions that will be substituted for the pac_expectation operators
expr_t growth_correction_term = dynamic_model.Zero;
if (growth[name])
growth_correction_term = dynamic_model.AddTimes(growth[name], dynamic_model.AddVariable(growth_neutrality_params[name]));
growth_correction_term = dynamic_model.AddTimes(
growth[name], dynamic_model.AddVariable(growth_neutrality_params[name]));
if (aux_model_name[name].empty())
{
if (target_info.contains(name))
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is not supported in the context of a PAC model with model-consistent expectations (MCE)." << endl;
exit(EXIT_FAILURE);
assert(growth_correction_term == dynamic_model.Zero);
dynamic_model.computePacModelConsistentExpectationSubstitutionWithComponents(
name, symbol_table.getID(discount[name]), pacEquationMaxLag(name),
diff_subst_table, aux_param_symb_ids, get<2>(target_info[name]),
pac_expectation_substitution);
}
else
dynamic_model.computePacModelConsistentExpectationSubstitution(name,
symbol_table.getID(discount[name]),
pacEquationMaxLag(name),
growth_correction_term,
auxname[name],
diff_subst_table,
aux_var_symb_ids,
aux_param_symb_ids,
pac_expectation_substitution);
dynamic_model.computePacModelConsistentExpectationSubstitution(
name, symbol_table.getID(discount[name]), pacEquationMaxLag(name),
growth_correction_term, auxname[name], diff_subst_table, aux_var_symb_ids,
aux_param_symb_ids, pac_expectation_substitution);
}
else
{
if (target_info.contains(name))
{
assert(growth_correction_term == dynamic_model.Zero);
dynamic_model.computePacBackwardExpectationSubstitutionWithComponents(name, lhs[name],
max_lag,
aux_model_type[name],
get<2>(target_info[name]),
dynamic_model.computePacBackwardExpectationSubstitutionWithComponents(
name, lhs[name], max_lag, aux_model_type[name], get<2>(target_info[name]),
pac_expectation_substitution);
}
else
dynamic_model.computePacBackwardExpectationSubstitution(name, lhs[name], max_lag,
aux_model_type[name],
growth_correction_term,
auxname[name],
aux_var_symb_ids,
aux_param_symb_ids,
pac_expectation_substitution);
dynamic_model.computePacBackwardExpectationSubstitution(
name, lhs[name], max_lag, aux_model_type[name], growth_correction_term,
auxname[name], aux_var_symb_ids, aux_param_symb_ids, pac_expectation_substitution);
}
}
......@@ -1357,10 +1419,8 @@ void
PacModelTable::writeOutput(ostream& output) const
{
// Helper to print the “growth_info” structure (linear decomposition of growth)
auto growth_info_helper = [&](const string &fieldname, const growth_info_t &gi)
{
for (int i{1};
auto [growth_symb_id, growth_lag, param_id, constant] : gi)
auto growth_info_helper = [&](const string& fieldname, const growth_info_t& gi) {
for (int i {1}; auto [growth_symb_id, growth_lag, param_id, constant] : gi)
{
string structname = fieldname + "(" + to_string(i++) + ").";
if (growth_symb_id)
......@@ -1377,7 +1437,8 @@ PacModelTable::writeOutput(ostream &output) const
{
// case when this is not the highest lag of the growth variable
int aux_symb_id = symbol_table.searchAuxiliaryVars(*growth_symb_id, growth_lag);
output << structname << var_field << " = " << symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
output << structname << var_field << " = "
<< symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
<< structname << "lag = 0;" << endl;
}
catch (...)
......@@ -1386,14 +1447,17 @@ PacModelTable::writeOutput(ostream &output) const
{
// case when this is the highest lag of the growth variable
int tmp_growth_lag = growth_lag + 1;
int aux_symb_id = symbol_table.searchAuxiliaryVars(*growth_symb_id, tmp_growth_lag);
output << structname << var_field << " = " << symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
int aux_symb_id
= symbol_table.searchAuxiliaryVars(*growth_symb_id, tmp_growth_lag);
output << structname << var_field << " = "
<< symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
<< structname << "lag = -1;" << endl;
}
catch (...)
{
// case when there is no aux var for the variable
output << structname << var_field << " = "<< symbol_table.getTypeSpecificID(*growth_symb_id) + 1 << ";" << endl
output << structname << var_field << " = "
<< symbol_table.getTypeSpecificID(*growth_symb_id) + 1 << ";" << endl
<< structname << "lag = " << growth_lag << ";" << endl;
}
}
......@@ -1402,16 +1466,20 @@ PacModelTable::writeOutput(ostream &output) const
output << structname << "endo_id = 0;" << endl
<< structname << "exo_id = 0;" << endl
<< structname << "lag = 0;" << endl;
output << structname << "param_id = "
<< (param_id ? symbol_table.getTypeSpecificID(*param_id) + 1 : 0) << ";" << endl
output << structname
<< "param_id = " << (param_id ? symbol_table.getTypeSpecificID(*param_id) + 1 : 0)
<< ";" << endl
<< structname << "constant = " << constant << ";" << endl;
}
};
for (const auto& name : names)
{
output << "M_.pac." << name << ".auxiliary_model_name = '" << aux_model_name.at(name) << "';" << endl
<< "M_.pac." << name << ".discount_index = " << symbol_table.getTypeSpecificID(discount.at(name)) + 1 << ";" << endl;
output << "M_.pac." << name << ".auxiliary_model_name = '" << aux_model_name.at(name) << "';"
<< endl
<< "M_.pac." << name
<< ".discount_index = " << symbol_table.getTypeSpecificID(discount.at(name)) + 1 << ";"
<< endl;
if (growth.at(name))
{
......@@ -1425,7 +1493,8 @@ PacModelTable::writeOutput(ostream &output) const
// Write the auxiliary parameter IDs created for the pac_expectation operator
for (auto& [name, ids] : aux_param_symb_ids)
{
output << "M_.pac." << name << "." << (aux_model_name.at(name).empty() ? "mce.alpha" : "h_param_indices") << " = [";
output << "M_.pac." << name << "."
<< (aux_model_name.at(name).empty() ? "mce.alpha" : "h_param_indices") << " = [";
for (auto id : ids)
output << symbol_table.getTypeSpecificID(id) + 1 << " ";
output << "];" << endl;
......@@ -1433,7 +1502,7 @@ PacModelTable::writeOutput(ostream &output) const
// Write the auxiliary variable IDs created for the pac_expectation operator
for (auto& [name, id] : aux_var_symb_ids)
output << "M_.pac." << name << "." << (aux_model_name.at(name).empty() ? "mce.z1" : "aux_id")
output << "M_.pac." << name << "." << (aux_model_name.at(name).empty() ? "mce.z" : "aux_id")
<< " = " << symbol_table.getTypeSpecificID(id) + 1 << ";" << endl;
// Write PAC equation name info
......@@ -1454,29 +1523,31 @@ PacModelTable::writeOutput(ostream &output) const
for (auto& [name, val] : equation_info)
{
auto &[lhs_pac_var, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants, additive_vars_params_and_constants, optim_additive_vars_params_and_constants] = val;
output << "M_.pac." << name << ".lhs_var = "
<< symbol_table.getTypeSpecificID(lhs_pac_var.first) + 1 << ";" << endl;
auto& [lhs_pac_var, optim_share_index, ar_params_and_vars, ec_params_and_vars,
non_optim_vars_params_and_constants, additive_vars_params_and_constants,
optim_additive_vars_params_and_constants]
= val;
output << "M_.pac." << name
<< ".lhs_var = " << symbol_table.getTypeSpecificID(lhs_pac_var.first) + 1 << ";"
<< endl;
if (optim_share_index)
output << "M_.pac." << name << ".share_of_optimizing_agents_index = "
<< symbol_table.getTypeSpecificID(*optim_share_index) + 1 << ";" << endl;
output << "M_.pac." << name << ".ec.params = "
<< symbol_table.getTypeSpecificID(ec_params_and_vars.first) + 1 << ";" << endl
output << "M_.pac." << name
<< ".ec.params = " << symbol_table.getTypeSpecificID(ec_params_and_vars.first) + 1
<< ";" << endl
<< "M_.pac." << name << ".ec.vars = [";
for (auto& it : ec_params_and_vars.second)
output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
output << "];" << endl
<< "M_.pac." << name << ".ec.istarget = [";
output << "];" << endl << "M_.pac." << name << ".ec.istarget = [";
for (auto& it : ec_params_and_vars.second)
output << boolalpha << get<1>(it) << " ";
output << "];" << endl
<< "M_.pac." << name << ".ec.scale = [";
output << "];" << endl << "M_.pac." << name << ".ec.scale = [";
for (auto& it : ec_params_and_vars.second)
output << get<2>(it) << " ";
output << "];" << endl
<< "M_.pac." << name << ".ec.isendo = [";
output << "];" << endl << "M_.pac." << name << ".ec.isendo = [";
for (auto& it : ec_params_and_vars.second)
switch (symbol_table.getType(get<0>(it)))
{
......@@ -1490,16 +1561,13 @@ PacModelTable::writeOutput(ostream &output) const
cerr << "expecting endogenous or exogenous" << endl;
exit(EXIT_FAILURE);
}
output << "];" << endl
<< "M_.pac." << name << ".ar.params = [";
output << "];" << endl << "M_.pac." << name << ".ar.params = [";
for (auto& [pid, vid, vlag] : ar_params_and_vars)
output << (pid ? symbol_table.getTypeSpecificID(*pid) + 1 : -1) << " ";
output << "];" << endl
<< "M_.pac." << name << ".ar.vars = [";
output << "];" << endl << "M_.pac." << name << ".ar.vars = [";
for (auto& [pid, vid, vlag] : ar_params_and_vars)
output << (vid ? symbol_table.getTypeSpecificID(*vid) + 1 : -1) << " ";
output << "];" << endl
<< "M_.pac." << name << ".ar.lags = [";
output << "];" << endl << "M_.pac." << name << ".ar.lags = [";
for (auto& [pid, vid, vlag] : ar_params_and_vars)
output << vlag << " ";
output << "];" << endl
......@@ -1512,12 +1580,10 @@ PacModelTable::writeOutput(ostream &output) const
output << symbol_table.getTypeSpecificID(*get<2>(it)) + 1 << " ";
else
output << "NaN ";
output << "];" << endl
<< "M_.pac." << name << ".non_optimizing_behaviour.vars = [";
output << "];" << endl << "M_.pac." << name << ".non_optimizing_behaviour.vars = [";
for (auto& it : non_optim_vars_params_and_constants)
output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
output << "];" << endl
<< "M_.pac." << name << ".non_optimizing_behaviour.isendo = [";
output << "];" << endl << "M_.pac." << name << ".non_optimizing_behaviour.isendo = [";
for (auto& it : non_optim_vars_params_and_constants)
switch (symbol_table.getType(get<0>(it)))
{
......@@ -1531,8 +1597,7 @@ PacModelTable::writeOutput(ostream &output) const
cerr << "expecting endogenous or exogenous" << endl;
exit(EXIT_FAILURE);
}
output << "];" << endl
<< "M_.pac." << name << ".non_optimizing_behaviour.lags = [";
output << "];" << endl << "M_.pac." << name << ".non_optimizing_behaviour.lags = [";
for (auto& it : non_optim_vars_params_and_constants)
output << get<1>(it) << " ";
output << "];" << endl
......@@ -1549,12 +1614,10 @@ PacModelTable::writeOutput(ostream &output) const
output << symbol_table.getTypeSpecificID(*get<2>(it)) + 1 << " ";
else
output << "NaN ";
output << "];" << endl
<< "M_.pac." << name << ".additive.vars = [";
output << "];" << endl << "M_.pac." << name << ".additive.vars = [";
for (auto& it : additive_vars_params_and_constants)
output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
output << "];" << endl
<< "M_.pac." << name << ".additive.isendo = [";
output << "];" << endl << "M_.pac." << name << ".additive.isendo = [";
for (auto& it : additive_vars_params_and_constants)
switch (symbol_table.getType(get<0>(it)))
{
......@@ -1568,12 +1631,10 @@ PacModelTable::writeOutput(ostream &output) const
cerr << "expecting endogenous or exogenous" << endl;
exit(EXIT_FAILURE);
}
output << "];" << endl
<< "M_.pac." << name << ".additive.lags = [";
output << "];" << endl << "M_.pac." << name << ".additive.lags = [";
for (auto& it : additive_vars_params_and_constants)
output << get<1>(it) << " ";
output << "];" << endl
<< "M_.pac." << name << ".additive.scaling_factor = [";
output << "];" << endl << "M_.pac." << name << ".additive.scaling_factor = [";
for (auto& it : additive_vars_params_and_constants)
output << get<3>(it) << " ";
output << "];" << endl;
......@@ -1586,12 +1647,10 @@ PacModelTable::writeOutput(ostream &output) const
output << symbol_table.getTypeSpecificID(*get<2>(it)) + 1 << " ";
else
output << "NaN ";
output << "];" << endl
<< "M_.pac." << name << ".optim_additive.vars = [";
output << "];" << endl << "M_.pac." << name << ".optim_additive.vars = [";
for (auto& it : optim_additive_vars_params_and_constants)
output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
output << "];" << endl
<< "M_.pac." << name << ".optim_additive.isendo = [";
output << "];" << endl << "M_.pac." << name << ".optim_additive.isendo = [";
for (auto& it : optim_additive_vars_params_and_constants)
switch (symbol_table.getType(get<0>(it)))
{
......@@ -1605,12 +1664,10 @@ PacModelTable::writeOutput(ostream &output) const
cerr << "expecting endogenous or exogenous" << endl;
exit(EXIT_FAILURE);
}
output << "];" << endl
<< "M_.pac." << name << ".optim_additive.lags = [";
output << "];" << endl << "M_.pac." << name << ".optim_additive.lags = [";
for (auto& it : optim_additive_vars_params_and_constants)
output << get<1>(it) << " ";
output << "];" << endl
<< "M_.pac." << name << ".optim_additive.scaling_factor = [";
output << "];" << endl << "M_.pac." << name << ".optim_additive.scaling_factor = [";
for (auto& it : optim_additive_vars_params_and_constants)
output << get<3>(it) << " ";
output << "];" << endl;
......@@ -1619,22 +1676,26 @@ PacModelTable::writeOutput(ostream &output) const
for (auto& [name, val] : target_info)
for (int component_idx {1};
auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : get<2>(val))
auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
string fieldname = "M_.pac." + name + ".components(" + to_string(component_idx) + ")";
output << fieldname << ".aux_id = " << symbol_table.getTypeSpecificID(auxname) + 1 << ";" << endl
<< fieldname << ".endo_var = " << symbol_table.getTypeSpecificID(dynamic_cast<VariableNode *>(component)->symb_id) + 1 << ";" << endl
output << fieldname << ".aux_id = " << symbol_table.getTypeSpecificID(auxname) + 1 << ";"
<< endl
<< fieldname
<< ".endo_var = " << dynamic_cast<VariableNode*>(component)->getTypeSpecificID() + 1
<< ";" << endl
<< fieldname << ".kind = '" << kindToString(kind) << "';" << endl
<< fieldname << ".h_param_indices = [";
for (int id : h_indices)
output << symbol_table.getTypeSpecificID(id) + 1 << " ";
output << "];" << endl
<< fieldname << ".coeff_str = '";
output << "];" << endl << fieldname << ".coeff_str = '";
coeff->writeJsonOutput(output, {}, {}, true);
output << "';" << endl;
if (growth_component)
{
output << fieldname << ".growth_neutrality_param_index = " << symbol_table.getTypeSpecificID(growth_neutrality_param) + 1 << ";" << endl
output << fieldname << ".growth_neutrality_param_index = "
<< symbol_table.getTypeSpecificID(growth_neutrality_param) + 1 << ";" << endl
<< fieldname << ".growth_str = '";
original_growth_component->writeJsonOutput(output, {}, {}, true);
output << "';" << endl;
......@@ -1642,13 +1703,27 @@ PacModelTable::writeOutput(ostream &output) const
}
component_idx++;
}
for (auto& [name, val] : target_info)
if (aux_model_name.at(name).empty())
{
string pac_model_name = "M_.pac." + name + ".mce.";
output << pac_model_name << "z = NaN(" << get<2>(val).size() << ",1);" << endl;
for (int component_idx {1};
auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
output << pac_model_name << "z(" << component_idx
<< ") = " << symbol_table.getTypeSpecificID(auxname) + 1 << ";" << endl;
component_idx++;
}
}
}
void
PacModelTable::writeJsonOutput(ostream& output) const
{
for (bool printed_something{false};
const auto &name : names)
for (bool printed_something {false}; const auto& name : names)
{
/* The calling method has already added a comma, so don’t output one for
the first statement */
......@@ -1672,16 +1747,15 @@ PacModelTable::writeJsonOutput(ostream &output) const
output << R"(, {"statementName": "pac_target_info", "model_name": ")" << name
<< R"(", "target": ")";
get<0>(val)->writeJsonOutput(output, {}, {}, true);
output << R"(", "auxname_target_nonstationary": ")" << get<1>(val)
<< R"(", "components": [)";
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : get<2>(val))
output << R"(", "auxname_target_nonstationary": ")" << get<1>(val) << R"(", "components": [)";
for (auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
if (component != get<0>(get<2>(val).front()))
output << ", ";
output << R"({"component": ")";
component->writeJsonOutput(output, {}, {}, true);
output << R"(", "auxname": ")" << auxname
<< R"(", "kind": ")" << kindToString(kind);
output << R"(", "auxname": ")" << auxname << R"(", "kind": ")" << kindToString(kind);
if (growth_component)
{
output << R"(", "growth_str": ")";
......@@ -1755,16 +1829,15 @@ PacModelTable::writeTargetCoefficientsFile(const string &basename) const
output << " if strcmp(model_name, '" << model_name << "')" << endl
<< " coeffs = NaN(" << get<2>(val).size() << ",1);" << endl;
for (int i {1};
auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : get<2>(val))
auto& [component, growth_component, auxname, kind, coeff, growth_neutrality_param,
h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
output << " coeffs(" << i++ << ") = ";
coeff->writeOutput(output, ExprNodeOutputType::matlabDynamicModel);
output << ";" << endl;
}
output << " return" << endl
<< " end" << endl;
output << " return" << endl << " end" << endl;
}
output << " error([ 'Unknown PAC model: ' model_name ])" << endl
<< "end" << endl;
output << " error([ 'Unknown PAC model: ' model_name ])" << endl << "end" << endl;
output.close();
}
/*
* Copyright © 2018-2022 Dynare Team
* Copyright © 2018-2023 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,19 +17,19 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SUBMODEL_HH
#define _SUBMODEL_HH
#ifndef SUB_MODEL_HH
#define SUB_MODEL_HH
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <map>
#include <optional>
#include <set>
#include <vector>
#include "ExprNode.hh"
#include "SymbolTable.hh"
#include "SymbolList.hh"
#include "Statement.hh"
#include "SymbolList.hh"
#include "SymbolTable.hh"
// DynamicModel.hh can’t be included here, otherwise it would be a circular dependency
class DynamicModel;
......@@ -46,7 +46,8 @@ private:
SymbolTable& symbol_table;
set<string> names;
map<string, vector<string>> eqtags, target_eqtags;
map<string, vector<int>> eqnums, target_eqnums, nontarget_eqnums, max_lags, lhs, target_lhs, nontarget_lhs;
map<string, vector<int>> eqnums, target_eqnums, nontarget_eqnums, max_lags, lhs, target_lhs,
nontarget_lhs;
map<string, vector<optional<int>>> orig_diff_var;
map<string, vector<set<pair<int, int>>>> rhs;
map<string, vector<bool>> diff;
......@@ -63,29 +64,28 @@ public:
void addTrendComponentModel(string name_arg, vector<string> eqtags_arg,
vector<string> target_eqtags_arg);
inline bool isExistingTrendComponentModelName(const string &name_arg) const;
inline bool empty() const;
const map<string, vector<string>> &getEqTags() const;
const vector<string> &getEqTags(const string &name_arg) const;
const map<string, vector<string>> &getTargetEqTags() const;
const map<string, vector<int>> &getEqNums() const;
const map<string, vector<int>> &getTargetEqNums() const;
const vector<int> &getTargetEqNums(const string &name_arg) const;
const vector<int> &getEqNums(const string &name_arg) const;
const vector<int> &getMaxLags(const string &name_arg) const;
int getMaxLag(const string &name_arg) const;
const vector<int> &getLhs(const string &name_arg) const;
const vector<expr_t> &getLhsExprT(const string &name_arg) const;
const vector<bool> &getDiff(const string &name_arg) const;
const map<string, vector<int>> &getNonTargetEqNums() const;
const vector<int> &getNonTargetEqNums(const string &name_arg) const;
const vector<int> &getNonTargetLhs(const string &name_arg) const;
const vector<int> &getTargetLhs(const string &name_arg) const;
[[nodiscard]] inline bool isExistingTrendComponentModelName(const string& name_arg) const;
[[nodiscard]] inline bool empty() const;
[[nodiscard]] const map<string, vector<string>>& getEqTags() const;
[[nodiscard]] const vector<string>& getEqTags(const string& name_arg) const;
[[nodiscard]] const map<string, vector<string>>& getTargetEqTags() const;
[[nodiscard]] const map<string, vector<int>>& getEqNums() const;
[[nodiscard]] const map<string, vector<int>>& getTargetEqNums() const;
[[nodiscard]] const vector<int>& getTargetEqNums(const string& name_arg) const;
[[nodiscard]] const vector<int>& getEqNums(const string& name_arg) const;
[[nodiscard]] const vector<int>& getMaxLags(const string& name_arg) const;
[[nodiscard]] int getMaxLag(const string& name_arg) const;
[[nodiscard]] const vector<int>& getLhs(const string& name_arg) const;
[[nodiscard]] const vector<expr_t>& getLhsExprT(const string& name_arg) const;
[[nodiscard]] const vector<bool>& getDiff(const string& name_arg) const;
[[nodiscard]] const map<string, vector<int>>& getNonTargetEqNums() const;
[[nodiscard]] const vector<int>& getNonTargetEqNums(const string& name_arg) const;
[[nodiscard]] const vector<int>& getNonTargetLhs(const string& name_arg) const;
[[nodiscard]] const vector<int>& getTargetLhs(const string& name_arg) const;
void setVals(map<string, vector<int>> eqnums_arg, map<string, vector<int>> target_eqnums_arg,
map<string, vector<int>> lhs_arg,
map<string, vector<expr_t>> lhs_expr_t_arg);
map<string, vector<int>> lhs_arg, map<string, vector<expr_t>> lhs_expr_t_arg);
void setRhs(map<string, vector<set<pair<int, int>>>> rhs_arg);
void setMaxLags(map<string, vector<int>> max_lags_arg);
void setDiff(map<string, vector<bool>> diff_arg);
......@@ -127,10 +127,12 @@ private:
map<string, vector<string>> eqtags;
map<string, vector<int>> eqnums, max_lags, lhs, lhs_orig_symb_ids;
map<string, vector<optional<int>>> orig_diff_var;
map<string, vector<set<pair<int, int>>>> rhs; // name -> for each equation: set of pairs (var, lag)
map<string, vector<set<pair<int, int>>>>
rhs; // name -> for each equation: set of pairs (var, lag)
map<string, vector<bool>> diff;
map<string, vector<expr_t>> lhs_expr_t;
map<string, map<tuple<int, int, int>, expr_t>> AR; // name -> (eqn, lag, lhs_symb_id) -> param_expr_t
map<string, map<tuple<int, int, int>, expr_t>>
AR; // name -> (eqn, lag, lhs_symb_id) -> param_expr_t
/* The A0 matrix is mainly for structural VARs. For reduced-form VARs, it
will be equal to the identity matrix. Also note that A0 in the structural
VAR context is not the same thing as in the trend-component model
......@@ -143,21 +145,21 @@ public:
//! Add a VAR model
void addVarModel(string name, bool structural_arg, vector<string> eqtags);
inline bool isExistingVarModelName(const string &name_arg) const;
inline bool empty() const;
const map<string, bool> &getStructural() const;
const map<string, vector<string>> &getEqTags() const;
const vector<string> &getEqTags(const string &name_arg) const;
const map<string, vector<int>> &getEqNums() const;
const vector<bool> &getDiff(const string &name_arg) const;
const vector<int> &getEqNums(const string &name_arg) const;
const vector<int> &getMaxLags(const string &name_arg) const;
int getMaxLag(const string &name_arg) const;
const vector<int> &getLhs(const string &name_arg) const;
const vector<int> &getLhsOrigIds(const string &name_arg) const;
const vector<set<pair<int, int>>> &getRhs(const string &name_arg) const;
const vector<expr_t> &getLhsExprT(const string &name_arg) const;
[[nodiscard]] inline bool isExistingVarModelName(const string& name_arg) const;
[[nodiscard]] inline bool empty() const;
[[nodiscard]] const map<string, bool>& getStructural() const;
[[nodiscard]] const map<string, vector<string>>& getEqTags() const;
[[nodiscard]] const vector<string>& getEqTags(const string& name_arg) const;
[[nodiscard]] const map<string, vector<int>>& getEqNums() const;
[[nodiscard]] const vector<bool>& getDiff(const string& name_arg) const;
[[nodiscard]] const vector<int>& getEqNums(const string& name_arg) const;
[[nodiscard]] const vector<int>& getMaxLags(const string& name_arg) const;
[[nodiscard]] int getMaxLag(const string& name_arg) const;
[[nodiscard]] const vector<int>& getLhs(const string& name_arg) const;
[[nodiscard]] const vector<int>& getLhsOrigIds(const string& name_arg) const;
[[nodiscard]] const vector<set<pair<int, int>>>& getRhs(const string& name_arg) const;
[[nodiscard]] const vector<expr_t>& getLhsExprT(const string& name_arg) const;
void setEqNums(map<string, vector<int>> eqnums_arg);
void setLhs(map<string, vector<int>> lhs_arg);
......@@ -206,17 +208,22 @@ private:
map<string, vector<int>> aux_param_symb_ids;
// Decomposition of the expression
map<string, vector<tuple<int, optional<int>, double>>> vars_params_constants;
public:
explicit VarExpectationModelTable(SymbolTable& symbol_table_arg);
void addVarExpectationModel(string name_arg, expr_t expression_arg, string aux_model_name_arg,
string horizon_arg, expr_t discount_arg, int time_shift_arg);
bool isExistingVarExpectationModelName(const string &name_arg) const;
bool empty() const;
void substituteUnaryOpsInExpression(const lag_equivalence_table_t &nodes, ExprNode::subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs);
[[nodiscard]] bool isExistingVarExpectationModelName(const string& name_arg) const;
[[nodiscard]] bool empty() const;
void substituteUnaryOpsInExpression(const lag_equivalence_table_t& nodes,
ExprNode::subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs);
// Called by DynamicModel::substituteDiff()
void substituteDiffNodesInExpression(const lag_equivalence_table_t &diff_nodes, ExprNode::subst_table_t &diff_subst_table, vector<BinaryOpNode *> &neweqs);
void transformPass(ExprNode::subst_table_t &diff_subst_table,
DynamicModel &dynamic_model, const VarModelTable &var_model_table,
void substituteDiffNodesInExpression(const lag_equivalence_table_t& diff_nodes,
ExprNode::subst_table_t& diff_subst_table,
vector<BinaryOpNode*>& neweqs);
void transformPass(ExprNode::subst_table_t& diff_subst_table, DynamicModel& dynamic_model,
const VarModelTable& var_model_table,
const TrendComponentModelTable& trend_component_model_table);
void writeOutput(ostream& output) const;
void writeJsonOutput(ostream& output) const;
......@@ -280,10 +287,18 @@ private:
public:
/* Stores info about PAC equations
pac_model_name →
(lhs, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants, additive_vars_params_and_constants, optim_additive_vars_params_and_constants)
(lhs, optim_share_index, ar_params_and_vars, ec_params_and_vars,
non_optim_vars_params_and_constants, additive_vars_params_and_constants,
optim_additive_vars_params_and_constants)
*/
using equation_info_t = map<string,
tuple<pair<int, int>, optional<int>, vector<tuple<optional<int>, optional<int>, int>>, pair<int, vector<tuple<int, bool, int>>>, vector<tuple<int, int, optional<int>, double>>, vector<tuple<int, int, optional<int>, double>>, vector<tuple<int, int, optional<int>, double>>>>;
using equation_info_t
= map<string,
tuple<pair<int, int>, optional<int>, vector<tuple<optional<int>, optional<int>, int>>,
pair<int, vector<tuple<int, bool, int>>>,
vector<tuple<int, int, optional<int>, double>>,
vector<tuple<int, int, optional<int>, double>>,
vector<tuple<int, int, optional<int>, double>>>>;
private:
equation_info_t equation_info;
......@@ -291,34 +306,40 @@ public:
/* (component variable/expr, growth, auxname, kind, coeff. in the linear
combination, growth_param ID (unused if growth is nullptr), vector of h parameters,
original_growth, growth_info) */
using target_component_t = tuple<expr_t, expr_t, string, PacTargetKind, expr_t, int, vector<int>, expr_t, growth_info_t>;
using target_component_t = tuple<expr_t, expr_t, string, PacTargetKind, expr_t, int, vector<int>,
expr_t, growth_info_t>;
private:
// pac_model_name → (target variable/expr, auxname_target_nonstationary, target components)
map<string, tuple<expr_t, string, vector<target_component_t>>> target_info;
int pacEquationMaxLag(const string &name_arg) const;
[[nodiscard]] int pacEquationMaxLag(const string& name_arg) const;
// Return a text representation of a kind (but fails on “unspecified” kind value)
static string kindToString(PacTargetKind kind);
public:
explicit PacModelTable(SymbolTable& symbol_table_arg);
void addPacModel(string name_arg, string aux_model_name_arg, string discount_arg, expr_t growth_arg, string auxname_arg, PacTargetKind kind_arg);
bool isExistingPacModelName(const string &name_arg) const;
bool empty() const;
void addPacModel(string name_arg, string aux_model_name_arg, string discount_arg,
expr_t growth_arg, string auxname_arg, PacTargetKind kind_arg);
[[nodiscard]] bool isExistingPacModelName(const string& name_arg) const;
[[nodiscard]] bool empty() const;
void checkPass(ModFileStructure& mod_file_struct);
// Called by DynamicModel::substituteUnaryOps()
void substituteUnaryOpsInGrowth(const lag_equivalence_table_t &nodes, ExprNode::subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs);
void substituteUnaryOpsInGrowth(const lag_equivalence_table_t& nodes,
ExprNode::subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs);
void findDiffNodesInGrowth(lag_equivalence_table_t& diff_nodes) const;
// Called by DynamicModel::substituteDiff()
void substituteDiffNodesInGrowth(const lag_equivalence_table_t &diff_nodes, ExprNode::subst_table_t &diff_subst_table, vector<BinaryOpNode *> &neweqs);
void substituteDiffNodesInGrowth(const lag_equivalence_table_t& diff_nodes,
ExprNode::subst_table_t& diff_subst_table,
vector<BinaryOpNode*>& neweqs);
// Must be called after substituteDiffNodesInGrowth() and substituteUnaryOpsInGrowth()
void transformPass(const lag_equivalence_table_t& unary_ops_nodes,
ExprNode::subst_table_t& unary_ops_subst_table,
const lag_equivalence_table_t& diff_nodes,
ExprNode::subst_table_t &diff_subst_table,
DynamicModel &dynamic_model, const VarModelTable &var_model_table,
ExprNode::subst_table_t& diff_subst_table, DynamicModel& dynamic_model,
const VarModelTable& var_model_table,
const TrendComponentModelTable& trend_component_model_table);
void writeOutput(ostream& output) const;
void writeJsonOutput(ostream& output) const;
......@@ -330,5 +351,4 @@ public:
void writeTargetCoefficientsFile(const string& basename) const;
};
#endif
/*
* Copyright © 2003-2022 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -21,8 +21,7 @@
#include "SymbolList.hh"
SymbolList::SymbolList(vector<string> symbols_arg) :
symbols{move(symbols_arg)}
SymbolList::SymbolList(vector<string> symbols_arg) : symbols {move(symbols_arg)}
{
}
......@@ -48,7 +47,8 @@ SymbolList::checkPass(WarningConsolidation &warnings, const vector<SymbolType> &
{
if (regex_search(symbol, m, re))
{
warnings << "WARNING: symbol_list variable " << symbol << " has not yet been declared. "
warnings
<< "WARNING: symbol_list variable " << symbol << " has not yet been declared. "
<< "This is being ignored because the variable name corresponds to a possible "
<< "auxiliary variable name." << endl;
return;
......@@ -57,7 +57,7 @@ SymbolList::checkPass(WarningConsolidation &warnings, const vector<SymbolType> &
throw SymbolListException {"Variable " + symbol + " was not declared."};
}
if (none_of(types.begin(), types.end(),
if (ranges::none_of(types,
[&](SymbolType type) { return symbol_table.getType(symbol) == type; }))
{
string valid_types;
......@@ -103,6 +103,15 @@ SymbolList::checkPass(WarningConsolidation &warnings, const vector<SymbolType> &
case SymbolType::excludedVariable:
valid_types += "excludedVariable, ";
break;
case SymbolType::heterogeneousEndogenous:
valid_types += "heterogeneousEndogenous, ";
break;
case SymbolType::heterogeneousExogenous:
valid_types += "heterogeneousExogenous, ";
break;
case SymbolType::heterogeneousParameter:
valid_types += "heterogeneousParameter, ";
break;
}
valid_types = valid_types.erase(valid_types.size() - 2, 2);
throw SymbolListException {"Variable " + symbol + " is not one of {" + valid_types + "}"};
......@@ -114,8 +123,7 @@ void
SymbolList::writeOutput(const string& varname, ostream& output) const
{
output << varname << " = {";
for (bool printed_something{false};
const auto &name : symbols)
for (bool printed_something {false}; const auto& name : symbols)
{
if (exchange(printed_something, true))
output << ";";
......@@ -128,8 +136,7 @@ void
SymbolList::writeJsonOutput(ostream& output) const
{
output << R"("symbol_list": [)";
for (bool printed_something{false};
const auto &name : symbols)
for (bool printed_something {false}; const auto& name : symbols)
{
if (exchange(printed_something, true))
output << ",";
......@@ -153,6 +160,7 @@ SymbolList::removeDuplicates(const string &dynare_command, WarningConsolidation
unique_symbols.push_back(it);
else
warnings << "WARNING: In " << dynare_command << ": " << it
<< " found more than once in symbol list. Removing all but first occurrence." << endl;
<< " found more than once in symbol list. Removing all but first occurrence."
<< endl;
symbols = unique_symbols;
}
/*
* Copyright © 2003-2022 Dynare Team
* Copyright © 2003-2023 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,16 +17,16 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SYMBOL_LIST_HH
#define _SYMBOL_LIST_HH
#ifndef SYMBOL_LIST_HH
#define SYMBOL_LIST_HH
#include <algorithm>
#include <ostream>
#include <string>
#include <vector>
#include <ostream>
#include <algorithm>
#include "WarningConsolidation.hh"
#include "SymbolTable.hh"
#include "WarningConsolidation.hh"
using namespace std;
......@@ -36,6 +36,7 @@ class SymbolList
{
private:
vector<string> symbols;
public:
SymbolList() = default;
// This constructor is deliberately not marked explicit, to allow implicit conversion
......@@ -48,7 +49,8 @@ public:
//! Remove duplicate symbols
void removeDuplicates(const string& dynare_command, WarningConsolidation& warnings);
//! Check symbols to ensure variables have been declared and are endogenous
void checkPass(WarningConsolidation &warnings, const vector<SymbolType> &types, const SymbolTable &symbol_table) const noexcept(false);
void checkPass(WarningConsolidation& warnings, const vector<SymbolType>& types,
const SymbolTable& symbol_table) const noexcept(false);
//! Output content in Matlab format
/*! Creates a string array for Matlab, stored in variable "varname" */
void writeOutput(const string& varname, ostream& output) const;
......@@ -57,13 +59,13 @@ public:
//! Write JSON output
void writeJsonOutput(ostream& output) const;
//! Is Empty
bool
[[nodiscard]] bool
empty() const
{
return symbols.empty();
};
}
//! Return the list of symbols
vector<string> getSymbols() const;
[[nodiscard]] vector<string> getSymbols() const;
};
#endif
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -18,9 +18,9 @@
*/
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cassert>
#include <iostream>
#include <sstream>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#include <boost/algorithm/string/replace.hpp>
......@@ -30,7 +30,9 @@
#include "SymbolTable.hh"
int
SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_name, const vector<pair<string, string>> &partition_value) noexcept(false)
SymbolTable::addSymbol(const string& name, SymbolType type, const string& tex_name,
const vector<pair<string, string>>& partition_value,
const optional<int>& heterogeneity_dimension) noexcept(false)
{
if (frozen)
throw FrozenException();
......@@ -77,13 +79,20 @@ SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_na
pmv[it.first] = it.second;
partition_value_map[id] = pmv;
}
assert(!isHeterogeneous(type)
|| (heterogeneity_dimension.has_value() && *heterogeneity_dimension >= 0
&& *heterogeneity_dimension < heterogeneity_table.size()));
if (isHeterogeneous(type))
heterogeneity_dimensions.emplace(id, *heterogeneity_dimension);
return id;
}
int
SymbolTable::addSymbol(const string& name, SymbolType type) noexcept(false)
{
return addSymbol(name, type, "", {});
return addSymbol(name, type, "", {}, {});
}
void
......@@ -94,6 +103,10 @@ SymbolTable::freeze() noexcept(false)
frozen = true;
het_endo_ids.resize(heterogeneity_table.size());
het_exo_ids.resize(heterogeneity_table.size());
het_param_ids.resize(heterogeneity_table.size());
for (int i = 0; i < static_cast<int>(symbol_table.size()); i++)
{
int tsi;
......@@ -115,6 +128,18 @@ SymbolTable::freeze() noexcept(false)
tsi = param_ids.size();
param_ids.push_back(i);
break;
case SymbolType::heterogeneousEndogenous:
tsi = het_endo_ids.at(heterogeneity_dimensions.at(i)).size();
het_endo_ids.at(heterogeneity_dimensions.at(i)).push_back(i);
break;
case SymbolType::heterogeneousExogenous:
tsi = het_exo_ids.at(heterogeneity_dimensions.at(i)).size();
het_exo_ids.at(heterogeneity_dimensions.at(i)).push_back(i);
break;
case SymbolType::heterogeneousParameter:
tsi = het_param_ids.at(heterogeneity_dimensions.at(i)).size();
het_param_ids.at(heterogeneity_dimensions.at(i)).push_back(i);
break;
default:
continue;
}
......@@ -130,12 +155,18 @@ SymbolTable::unfreeze()
exo_ids.clear();
exo_det_ids.clear();
param_ids.clear();
het_endo_ids.clear();
het_exo_ids.clear();
het_param_ids.clear();
type_specific_ids.clear();
}
void
SymbolTable::changeType(int id, SymbolType newtype) noexcept(false)
{
// FIXME: implement switch to heterogeneous variable; dimension will have to be provided
assert(!isHeterogeneous(newtype));
if (frozen)
throw FrozenException();
......@@ -145,7 +176,8 @@ SymbolTable::changeType(int id, SymbolType newtype) noexcept(false)
}
int
SymbolTable::getID(SymbolType type, int tsid) const noexcept(false)
SymbolTable::getID(SymbolType type, int tsid, const optional<int>& heterogeneity_dimension) const
noexcept(false)
{
if (!frozen)
throw NotYetFrozenException();
......@@ -154,26 +186,44 @@ SymbolTable::getID(SymbolType type, int tsid) const noexcept(false)
{
case SymbolType::endogenous:
if (tsid < 0 || tsid >= static_cast<int>(endo_ids.size()))
throw UnknownTypeSpecificIDException{tsid, type};
throw UnknownTypeSpecificIDException {tsid, type, {}};
else
return endo_ids[tsid];
case SymbolType::exogenous:
if (tsid < 0 || tsid >= static_cast<int>(exo_ids.size()))
throw UnknownTypeSpecificIDException{tsid, type};
throw UnknownTypeSpecificIDException {tsid, type, {}};
else
return exo_ids[tsid];
case SymbolType::exogenousDet:
if (tsid < 0 || tsid >= static_cast<int>(exo_det_ids.size()))
throw UnknownTypeSpecificIDException{tsid, type};
throw UnknownTypeSpecificIDException {tsid, type, {}};
else
return exo_det_ids[tsid];
case SymbolType::parameter:
if (tsid < 0 || tsid >= static_cast<int>(param_ids.size()))
throw UnknownTypeSpecificIDException{tsid, type};
throw UnknownTypeSpecificIDException {tsid, type, {}};
else
return param_ids[tsid];
case SymbolType::heterogeneousEndogenous:
assert(heterogeneity_dimension.has_value());
if (tsid < 0 || tsid >= static_cast<int>(het_endo_ids.at(*heterogeneity_dimension).size()))
throw UnknownTypeSpecificIDException {tsid, type, *heterogeneity_dimension};
else
return het_endo_ids.at(*heterogeneity_dimension).at(tsid);
case SymbolType::heterogeneousExogenous:
assert(heterogeneity_dimension.has_value());
if (tsid < 0 || tsid >= static_cast<int>(het_exo_ids.at(*heterogeneity_dimension).size()))
throw UnknownTypeSpecificIDException {tsid, type, *heterogeneity_dimension};
else
return het_exo_ids.at(*heterogeneity_dimension).at(tsid);
case SymbolType::heterogeneousParameter:
assert(heterogeneity_dimension.has_value());
if (tsid < 0 || tsid >= static_cast<int>(het_param_ids.at(*heterogeneity_dimension).size()))
throw UnknownTypeSpecificIDException {tsid, type, *heterogeneity_dimension};
else
return het_param_ids.at(*heterogeneity_dimension).at(tsid);
default:
throw UnknownTypeSpecificIDException{tsid, type};
throw UnknownTypeSpecificIDException {tsid, type, {}};
}
}
......@@ -201,8 +251,10 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.exo_names_long = cell(" << exo_nbr() << ",1);" << endl;
for (int id = 0; id < exo_nbr(); id++)
output << "M_.exo_names(" << id + 1 << ") = {'" << getName(exo_ids[id]) << "'};" << endl
<< "M_.exo_names_tex(" << id+1 << ") = {'" << getTeXName(exo_ids[id]) << "'};" << endl
<< "M_.exo_names_long(" << id+1 << ") = {'" << getLongName(exo_ids[id]) << "'};" << endl;
<< "M_.exo_names_tex(" << id + 1 << ") = {'" << getTeXName(exo_ids[id]) << "'};"
<< endl
<< "M_.exo_names_long(" << id + 1 << ") = {'" << getLongName(exo_ids[id]) << "'};"
<< endl;
for (auto& partition : getPartitionsForType(SymbolType::exogenous))
if (partition.first != "long_name")
{
......@@ -210,8 +262,7 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
for (int id = 0; id < exo_nbr(); id++)
{
output << "'";
if (auto it1 = partition.second.find(exo_ids[id]);
it1 != partition.second.end())
if (auto it1 = partition.second.find(exo_ids[id]); it1 != partition.second.end())
output << it1->second;
output << "' ";
}
......@@ -235,9 +286,12 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.exo_det_names_tex = cell(" << exo_det_nbr() << ",1);" << endl;
output << "M_.exo_det_names_long = cell(" << exo_det_nbr() << ",1);" << endl;
for (int id = 0; id < exo_det_nbr(); id++)
output << "M_.exo_det_names(" << id+1 << ") = {'" << getName(exo_det_ids[id]) << "'};" << endl
<< "M_.exo_det_names_tex(" << id+1 << ") = {'" << getTeXName(exo_det_ids[id]) << "'};" << endl
<< "M_.exo_det_names_long(" << id+1 << ") = {'" << getLongName(exo_det_ids[id]) << "'};" << endl;
output << "M_.exo_det_names(" << id + 1 << ") = {'" << getName(exo_det_ids[id]) << "'};"
<< endl
<< "M_.exo_det_names_tex(" << id + 1 << ") = {'" << getTeXName(exo_det_ids[id])
<< "'};" << endl
<< "M_.exo_det_names_long(" << id + 1 << ") = {'" << getLongName(exo_det_ids[id])
<< "'};" << endl;
output << "M_.exo_det_partitions = struct();" << endl;
for (auto& partition : getPartitionsForType(SymbolType::exogenousDet))
if (partition.first != "long_name")
......@@ -262,8 +316,10 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.endo_names_long = cell(" << endo_nbr() << ",1);" << endl;
for (int id = 0; id < endo_nbr(); id++)
output << "M_.endo_names(" << id + 1 << ") = {'" << getName(endo_ids[id]) << "'};" << endl
<< "M_.endo_names_tex(" << id+1 << ") = {'" << getTeXName(endo_ids[id]) << "'};" << endl
<< "M_.endo_names_long(" << id+1 << ") = {'" << getLongName(endo_ids[id]) << "'};" << endl;
<< "M_.endo_names_tex(" << id + 1 << ") = {'" << getTeXName(endo_ids[id]) << "'};"
<< endl
<< "M_.endo_names_long(" << id + 1 << ") = {'" << getLongName(endo_ids[id]) << "'};"
<< endl;
output << "M_.endo_partitions = struct();" << endl;
for (auto& partition : getPartitionsForType(SymbolType::endogenous))
if (partition.first != "long_name")
......@@ -272,8 +328,7 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
for (int id = 0; id < endo_nbr(); id++)
{
output << "'";
if (auto it1 = partition.second.find(endo_ids[id]);
it1 != partition.second.end())
if (auto it1 = partition.second.find(endo_ids[id]); it1 != partition.second.end())
output << it1->second;
output << "' ";
}
......@@ -288,9 +343,12 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.param_names_long = cell(" << param_nbr() << ",1);" << endl;
for (int id = 0; id < param_nbr(); id++)
{
output << "M_.param_names(" << id+1 << ") = {'" << getName(param_ids[id]) << "'};" << endl
<< "M_.param_names_tex(" << id+1 << ") = {'" << getTeXName(param_ids[id]) << "'};" << endl
<< "M_.param_names_long(" << id+1 << ") = {'" << getLongName(param_ids[id]) << "'};" << endl;
output << "M_.param_names(" << id + 1 << ") = {'" << getName(param_ids[id]) << "'};"
<< endl
<< "M_.param_names_tex(" << id + 1 << ") = {'" << getTeXName(param_ids[id])
<< "'};" << endl
<< "M_.param_names_long(" << id + 1 << ") = {'" << getLongName(param_ids[id])
<< "'};" << endl;
if (getName(param_ids[id]) == "dsge_prior_weight")
output << "options_.dsge_var = 1;" << endl;
}
......@@ -302,8 +360,7 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
for (int id = 0; id < param_nbr(); id++)
{
output << "'";
if (auto it1 = partition.second.find(param_ids[id]);
it1 != partition.second.end())
if (auto it1 = partition.second.find(param_ids[id]); it1 != partition.second.end())
output << it1->second;
output << "' ";
}
......@@ -329,8 +386,10 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
else
for (int i = 0; i < static_cast<int>(aux_vars.size()); i++)
{
output << "M_.aux_vars(" << i+1 << ").endo_index = " << getTypeSpecificID(aux_vars[i].symb_id)+1 << ";" << endl
<< "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].get_type_id() << ";" << endl;
output << "M_.aux_vars(" << i + 1
<< ").endo_index = " << getTypeSpecificID(aux_vars[i].symb_id) + 1 << ";" << endl
<< "M_.aux_vars(" << i + 1 << ").type = " << aux_vars[i].get_type_id() << ";"
<< endl;
switch (aux_vars[i].type)
{
case AuxVarType::endoLead:
......@@ -338,6 +397,8 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
case AuxVarType::expectation:
case AuxVarType::pacExpectation:
case AuxVarType::pacTargetNonstationary:
case AuxVarType::aggregationOp:
case AuxVarType::heterogeneousMultiplier:
break;
case AuxVarType::endoLag:
case AuxVarType::exoLag:
......@@ -345,24 +406,32 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
case AuxVarType::diffLag:
case AuxVarType::diffLead:
case AuxVarType::diffForward:
output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].orig_symb_id.value())+1 << ";" << endl
<< "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].orig_lead_lag.value() << ";" << endl;
output << "M_.aux_vars(" << i + 1
<< ").orig_index = " << getTypeSpecificID(aux_vars[i].orig_symb_id.value()) + 1
<< ";" << endl
<< "M_.aux_vars(" << i + 1
<< ").orig_lead_lag = " << aux_vars[i].orig_lead_lag.value() << ";" << endl;
break;
case AuxVarType::unaryOp:
output << "M_.aux_vars(" << i+1 << ").unary_op = '" << aux_vars[i].unary_op << "';" << endl;
output << "M_.aux_vars(" << i + 1 << ").unary_op = '" << aux_vars[i].unary_op << "';"
<< endl;
[[fallthrough]];
case AuxVarType::diff:
if (aux_vars[i].orig_symb_id)
output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(*aux_vars[i].orig_symb_id)+1 << ";" << endl
<< "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].orig_lead_lag.value() << ";" << endl;
output << "M_.aux_vars(" << i + 1
<< ").orig_index = " << getTypeSpecificID(*aux_vars[i].orig_symb_id) + 1 << ";"
<< endl
<< "M_.aux_vars(" << i + 1
<< ").orig_lead_lag = " << aux_vars[i].orig_lead_lag.value() << ";" << endl;
break;
case AuxVarType::multiplier:
output << "M_.aux_vars(" << i+1 << ").eq_nbr = " << aux_vars[i].equation_number_for_multiplier + 1 << ";" << endl;
output << "M_.aux_vars(" << i + 1
<< ").eq_nbr = " << aux_vars[i].equation_number_for_multiplier + 1 << ";"
<< endl;
break;
}
if (expr_t orig_expr = aux_vars[i].expr_node;
orig_expr)
if (expr_t orig_expr = aux_vars[i].expr_node; orig_expr)
{
output << "M_.aux_vars(" << i + 1 << ").orig_expr = '";
orig_expr->writeJsonOutput(output, {}, {});
......@@ -381,8 +450,7 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
if (observedVariablesNbr() > 0)
{
output << "options_.varobs = cell(" << observedVariablesNbr() << ", 1);" << endl;
for (int ic{1};
int it : varobs)
for (int ic {1}; int it : varobs)
output << "options_.varobs(" << ic++ << ") = {'" << getName(it) << "'};" << endl;
output << "options_.varobs_id = [ ";
......@@ -394,8 +462,7 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
if (observedExogenousVariablesNbr() > 0)
{
output << "options_.varexobs = cell(1);" << endl;
for (int ic{1};
int it : varexobs)
for (int ic {1}; int it : varexobs)
output << "options_.varexobs(" << ic++ << ") = {'" << getName(it) << "'};" << endl;
output << "options_.varexobs_id = [ ";
......@@ -403,6 +470,54 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << getTypeSpecificID(varexob) + 1 << " ";
output << " ];" << endl;
}
// Heterogeneous symbols
// FIXME: the following helper could be used to simplify non-heterogenous variables
auto print_symb_names = [this, &output](const string& field, const auto& symb_ids) {
auto helper = [this, &output, &symb_ids](auto nameMethod) {
for (bool first_printed {false}; int symb_id : symb_ids)
{
if (exchange(first_printed, true))
output << "; ";
output << "'" << (this->*nameMethod)(symb_id) << "'";
}
};
output << field << " = {";
helper(&SymbolTable::getName);
output << "};" << endl << field << "_tex = {";
helper(&SymbolTable::getTeXName);
output << "};" << endl << field << "_long = {";
helper(&SymbolTable::getLongName);
output << "};" << endl;
};
for (int het_dim {0}; het_dim < heterogeneity_table.size(); het_dim++)
{
const string basefield {"M_.heterogeneity(" + to_string(het_dim + 1) + ")."};
output << basefield << "endo_nbr = " << het_endo_nbr(het_dim) << ";" << endl;
print_symb_names(basefield + "endo_names", het_endo_ids.at(het_dim));
output << basefield << "orig_endo_nbr = " << het_orig_endo_nbr(het_dim) << ";" << endl;
output << basefield << "exo_nbr = " << het_exo_nbr(het_dim) << ";" << endl;
print_symb_names(basefield + "exo_names", het_exo_ids.at(het_dim));
output << basefield << "param_nbr = " << het_param_nbr(het_dim) << ";" << endl;
print_symb_names(basefield + "param_names", het_param_ids.at(het_dim));
const vector<AuxVarInfo>& hav = het_aux_vars[het_dim];
if (hav.size() == 0)
output << basefield << "aux_vars = [];";
else
for (int i = 0; i < static_cast<int>(hav.size()); i++)
{
output << basefield << "aux_vars(" << i + 1
<< ").endo_index = " << getTypeSpecificID(hav[i].symb_id) + 1 << ";" << endl
<< basefield << "aux_vars(" << i + 1 << ").type = " << hav[i].get_type_id()
<< ";" << basefield << "aux_vars(" << i + 1
<< ").eq_nbr = " << hav[i].equation_number_for_multiplier + 1 << ";" << endl;
}
}
}
int
......@@ -416,19 +531,23 @@ SymbolTable::addLeadAuxiliaryVarInternal(bool endo, int index, expr_t expr_arg)
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, (endo ? AuxVarType::endoLead : AuxVarType::exoLead), 0, 0, 0, 0, expr_arg, "");
aux_vars.emplace_back(symb_id, (endo ? AuxVarType::endoLead : AuxVarType::exoLead), 0, 0, 0, 0,
expr_arg, "");
return symb_id;
}
int
SymbolTable::addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
SymbolTable::addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{
string varname{(endo ? "AUX_ENDO_LAG_" : "AUX_EXO_LAG_") + to_string(orig_symb_id) + "_" + to_string(-orig_lead_lag)};
string varname {(endo ? "AUX_ENDO_LAG_" : "AUX_EXO_LAG_") + to_string(orig_symb_id) + "_"
+ to_string(-orig_lead_lag)};
int symb_id;
try
{
......@@ -436,11 +555,13 @@ SymbolTable::addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_le
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, (endo ? AuxVarType::endoLag : AuxVarType::exoLag), orig_symb_id, orig_lead_lag, 0, 0, expr_arg, "");
aux_vars.emplace_back(symb_id, (endo ? AuxVarType::endoLag : AuxVarType::exoLag), orig_symb_id,
orig_lead_lag, 0, 0, expr_arg, "");
return symb_id;
}
......@@ -452,7 +573,8 @@ SymbolTable::addEndoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
}
int
SymbolTable::addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
SymbolTable::addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{
return addLagAuxiliaryVarInternal(true, orig_symb_id, orig_lead_lag, expr_arg);
}
......@@ -464,13 +586,15 @@ SymbolTable::addExoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
}
int
SymbolTable::addExoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
SymbolTable::addExoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{
return addLagAuxiliaryVarInternal(false, orig_symb_id, orig_lead_lag, expr_arg);
}
int
SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, expr_t expr_arg) noexcept(false)
SymbolTable::addExpectationAuxiliaryVar(int information_set, int index,
expr_t expr_arg) noexcept(false)
{
string varname {"AUX_EXPECT_"s + (information_set < 0 ? "LAG" : "LEAD") + "_"
+ to_string(abs(information_set)) + "_" + to_string(index)};
......@@ -481,7 +605,8 @@ SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, expr_t e
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
......@@ -491,7 +616,8 @@ SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, expr_t e
}
int
SymbolTable::addLogTransformAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
SymbolTable::addLogTransformAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{
string varname = "LOG_" + getName(orig_symb_id);
int symb_id;
......@@ -501,17 +627,21 @@ SymbolTable::addLogTransformAuxiliaryVar(int orig_symb_id, int orig_lead_lag, ex
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", it conflicts with the auxiliary variable created for representing the log of " << getName(orig_symb_id) << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", it conflicts with the auxiliary variable created for representing the log of "
<< getName(orig_symb_id) << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, AuxVarType::logTransform, orig_symb_id, orig_lead_lag, 0, 0, expr_arg, "");
aux_vars.emplace_back(symb_id, AuxVarType::logTransform, orig_symb_id, orig_lead_lag, 0, 0,
expr_arg, "");
return symb_id;
}
int
SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) noexcept(false)
SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id,
int orig_lag) noexcept(false)
{
string varname {"AUX_DIFF_LAG_" + to_string(index)};
int symb_id;
......@@ -521,7 +651,8 @@ SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
......@@ -531,7 +662,8 @@ SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id
}
int
SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lead) noexcept(false)
SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id,
int orig_lead) noexcept(false)
{
string varname {"AUX_DIFF_LEAD_" + to_string(index)};
int symb_id;
......@@ -541,7 +673,8 @@ SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_i
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
......@@ -551,7 +684,8 @@ SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_i
}
int
SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, optional<int> orig_symb_id, optional<int> orig_lag) noexcept(false)
SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, const optional<int>& orig_symb_id,
const optional<int>& orig_lag) noexcept(false)
{
string varname {"AUX_DIFF_" + to_string(index)};
int symb_id;
......@@ -561,17 +695,20 @@ SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, optional<int> orig_
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, AuxVarType::diff, move(orig_symb_id), move(orig_lag), 0, 0, expr_arg, "");
aux_vars.emplace_back(symb_id, AuxVarType::diff, orig_symb_id, orig_lag, 0, 0, expr_arg, "");
return symb_id;
}
int
SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op, optional<int> orig_symb_id, optional<int> orig_lag) noexcept(false)
SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op,
const optional<int>& orig_symb_id,
const optional<int>& orig_lag) noexcept(false)
{
string varname {"AUX_UOP_" + to_string(index)};
int symb_id;
......@@ -581,12 +718,35 @@ SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op,
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, AuxVarType::unaryOp, move(orig_symb_id), move(orig_lag), 0, 0, expr_arg, unary_op);
aux_vars.emplace_back(symb_id, AuxVarType::unaryOp, orig_symb_id, orig_lag, 0, 0, expr_arg,
move(unary_op));
return symb_id;
}
int
SymbolTable::addHeterogeneousMultiplierAuxiliaryVar(int het_dim, int index,
const string& varname) noexcept(false)
{
int symb_id;
try
{
symb_id = addSymbol(varname, SymbolType::heterogeneousEndogenous, "", {}, het_dim);
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
het_aux_vars[het_dim].emplace_back(symb_id, AuxVarType::heterogeneousMultiplier, 0, 0, index, 0,
nullptr, "");
return symb_id;
}
......@@ -601,7 +761,8 @@ SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false)
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
......@@ -610,7 +771,8 @@ SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false)
}
int
SymbolTable::addDiffForwardAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
SymbolTable::addDiffForwardAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{
string varname {"AUX_DIFF_FWRD_" + to_string(orig_symb_id + 1)};
int symb_id;
......@@ -620,11 +782,13 @@ SymbolTable::addDiffForwardAuxiliaryVar(int orig_symb_id, int orig_lead_lag, exp
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: you should rename your variable called " << varname << ", this name is internally used by Dynare" << endl;
cerr << "ERROR: you should rename your variable called " << varname
<< ", this name is internally used by Dynare" << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, AuxVarType::diffForward, orig_symb_id, orig_lead_lag, 0, 0, expr_arg, "");
aux_vars.emplace_back(symb_id, AuxVarType::diffForward, orig_symb_id, orig_lead_lag, 0, 0,
expr_arg, "");
return symb_id;
}
......@@ -638,7 +802,10 @@ SymbolTable::addPacExpectationAuxiliaryVar(const string &name, expr_t expr_arg)
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: the variable/parameter '" << name << "' conflicts with a variable that will be generated for a 'pac_expectation' expression. Please rename it." << endl;
cerr << "ERROR: the variable/parameter '" << name
<< "' conflicts with a variable that will be generated for a 'pac_expectation' "
"expression. Please rename it."
<< endl;
exit(EXIT_FAILURE);
}
......@@ -656,7 +823,10 @@ SymbolTable::addPacTargetNonstationaryAuxiliaryVar(const string &name, expr_t ex
}
catch (AlreadyDeclaredException& e)
{
cerr << "ERROR: the variable/parameter '" << name << "' conflicts with a variable that will be generated for a 'pac_target_nonstationary' expression. Please rename it." << endl;
cerr << "ERROR: the variable/parameter '" << name
<< "' conflicts with a variable that will be generated for a 'pac_target_nonstationary' "
"expression. Please rename it."
<< endl;
exit(EXIT_FAILURE);
}
......@@ -664,6 +834,28 @@ SymbolTable::addPacTargetNonstationaryAuxiliaryVar(const string &name, expr_t ex
return symb_id;
}
int
SymbolTable::addAggregationOpAuxiliaryVar(const string& name, expr_t expr_arg)
{
int symb_id {[&] {
try
{
return addSymbol(name, SymbolType::endogenous);
}
catch (AlreadyDeclaredException&)
{
cerr << "ERROR: the variable/parameter '" << name
<< "' conflicts with a variable that will be generated for an aggregation operator. "
"Please rename it."
<< endl;
exit(EXIT_FAILURE);
}
}()};
aux_vars.emplace_back(symb_id, AuxVarType::aggregationOp, 0, 0, 0, 0, expr_arg, "");
return symb_id;
}
int
SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false)
{
......@@ -678,19 +870,17 @@ int
SymbolTable::getOrigSymbIdForAuxVar(int aux_var_symb_id_arg) const noexcept(false)
{
for (const auto& aux_var : aux_vars)
if ((aux_var.type == AuxVarType::endoLag
|| aux_var.type == AuxVarType::exoLag
|| aux_var.type == AuxVarType::diff
|| aux_var.type == AuxVarType::diffLag
|| aux_var.type == AuxVarType::diffLead
|| aux_var.type == AuxVarType::diffForward
if ((aux_var.type == AuxVarType::endoLag || aux_var.type == AuxVarType::exoLag
|| aux_var.type == AuxVarType::diff || aux_var.type == AuxVarType::diffLag
|| aux_var.type == AuxVarType::diffLead || aux_var.type == AuxVarType::diffForward
|| aux_var.type == AuxVarType::unaryOp)
&& aux_var.symb_id == aux_var_symb_id_arg)
{
if (optional<int> r = aux_var.orig_symb_id; r)
return *r;
else
throw UnknownSymbolIDException{aux_var_symb_id_arg}; // Some diff and unaryOp auxvars have orig_symb_id unset
throw UnknownSymbolIDException {
aux_var_symb_id_arg}; // Some diff and unaryOp auxvars have orig_symb_id unset
}
throw UnknownSymbolIDException {aux_var_symb_id_arg};
}
......@@ -764,13 +954,13 @@ SymbolTable::observedVariablesNbr() const
bool
SymbolTable::isObservedVariable(int symb_id) const
{
return find(varobs.begin(), varobs.end(), symb_id) != varobs.end();
return ranges::find(varobs, symb_id) != varobs.end();
}
int
SymbolTable::getObservedVariableIndex(int symb_id) const
{
auto it = find(varobs.begin(), varobs.end(), symb_id);
auto it = ranges::find(varobs, symb_id);
assert(it != varobs.end());
return static_cast<int>(it - varobs.begin());
}
......@@ -779,7 +969,7 @@ void
SymbolTable::addObservedExogenousVariable(int symb_id) noexcept(false)
{
validateSymbID(symb_id);
assert(getType(symb_id) != SymbolType::endogenous);
assert(getType(symb_id) == SymbolType::exogenous);
varexobs.push_back(symb_id);
}
......@@ -792,13 +982,13 @@ SymbolTable::observedExogenousVariablesNbr() const
bool
SymbolTable::isObservedExogenousVariable(int symb_id) const
{
return find(varexobs.begin(), varexobs.end(), symb_id) != varexobs.end();
return ranges::find(varexobs, symb_id) != varexobs.end();
}
int
SymbolTable::getObservedExogenousVariableIndex(int symb_id) const
{
auto it = find(varexobs.begin(), varexobs.end(), symb_id);
auto it = ranges::find(varexobs, symb_id);
assert(it != varexobs.end());
return static_cast<int>(it - varexobs.begin());
}
......@@ -847,17 +1037,17 @@ SymbolTable::getEndogenous() const
bool
SymbolTable::isAuxiliaryVariable(int symb_id) const
{
return any_of(aux_vars.begin(), aux_vars.end(), [=](const auto &av) { return av.symb_id == symb_id; });
return ranges::any_of(aux_vars, [=](const auto& av) { return av.symb_id == symb_id; });
}
bool
SymbolTable::isDiffAuxiliaryVariable(int symb_id) const
{
return any_of(aux_vars.begin(), aux_vars.end(),
[=](const auto &av) { return av.symb_id == symb_id
&& (av.type == AuxVarType::diff
|| av.type == AuxVarType::diffLag
|| av.type == AuxVarType::diffLead); });
return ranges::any_of(aux_vars, [=](const auto& av) {
return av.symb_id == symb_id
&& (av.type == AuxVarType::diff || av.type == AuxVarType::diffLag
|| av.type == AuxVarType::diffLead);
});
}
set<int>
......@@ -946,6 +1136,8 @@ SymbolTable::writeJsonOutput(ostream &output) const
case AuxVarType::expectation:
case AuxVarType::pacExpectation:
case AuxVarType::pacTargetNonstationary:
case AuxVarType::aggregationOp:
case AuxVarType::heterogeneousMultiplier:
break;
case AuxVarType::endoLag:
case AuxVarType::exoLag:
......@@ -953,7 +1145,8 @@ SymbolTable::writeJsonOutput(ostream &output) const
case AuxVarType::diffLag:
case AuxVarType::diffLead:
case AuxVarType::diffForward:
output << R"(, "orig_index": )" << getTypeSpecificID(aux_vars[i].orig_symb_id.value())+1
output << R"(, "orig_index": )"
<< getTypeSpecificID(aux_vars[i].orig_symb_id.value()) + 1
<< R"(, "orig_lead_lag": )" << aux_vars[i].orig_lead_lag.value();
break;
case AuxVarType::unaryOp:
......@@ -969,8 +1162,7 @@ SymbolTable::writeJsonOutput(ostream &output) const
break;
}
if (expr_t orig_expr = aux_vars[i].expr_node;
orig_expr)
if (expr_t orig_expr = aux_vars[i].expr_node; orig_expr)
{
output << R"(, "orig_expr": ")";
orig_expr->writeJsonOutput(output, {}, {});
......@@ -980,6 +1172,25 @@ SymbolTable::writeJsonOutput(ostream &output) const
}
output << "]" << endl;
}
if (!heterogeneity_table.empty())
{
output << R"(, "heterogeneous_symbols": [)";
for (int i {0}; i < heterogeneity_table.size(); i++)
{
if (i != 0)
output << ", ";
output << R"({ "dimension": ")" << heterogeneity_table.getName(i)
<< R"(", "endogenous": )";
writeJsonVarVector(output, het_endo_ids.at(i));
output << R"(, "exogenous": )";
writeJsonVarVector(output, het_exo_ids.at(i));
output << R"(, "parameters": )";
writeJsonVarVector(output, het_param_ids.at(i));
output << "}";
}
output << "]" << endl;
}
}
void
......@@ -992,9 +1203,10 @@ SymbolTable::writeJsonVarVector(ostream &output, const vector<int> &varvec) cons
output << ", ";
output << "{"
<< R"("name":")" << getName(varvec[i]) << R"(", )"
<< R"("texName":")" << boost::replace_all_copy(getTeXName(varvec[i]), R"(\)", R"(\\)") << R"(", )"
<< R"("longName":")" << boost::replace_all_copy(getLongName(varvec[i]), R"(\)", R"(\\)") << R"("})"
<< endl;
<< R"("texName":")" << boost::replace_all_copy(getTeXName(varvec[i]), R"(\)", R"(\\)")
<< R"(", )"
<< R"("longName":")"
<< boost::replace_all_copy(getLongName(varvec[i]), R"(\)", R"(\\)") << R"("})" << endl;
}
output << "]" << endl;
}
......@@ -1038,3 +1250,14 @@ SymbolTable::getLagrangeMultipliers() const
r.insert(aux_var.symb_id);
return r;
}
int
SymbolTable::getHeterogeneityDimension(int symb_id) const
{
validateSymbID(symb_id);
auto it = heterogeneity_dimensions.find(symb_id);
if (it != heterogeneity_dimensions.end())
return it->second;
else
throw NonHeteregeneousSymbolException {symb_id};
}
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,24 +17,23 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SYMBOLTABLE_HH
#define _SYMBOLTABLE_HH
#ifndef SYMBOL_TABLE_HH
#define SYMBOL_TABLE_HH
#include <map>
#include <optional>
#include <ostream>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <set>
#include <ostream>
#include <optional>
#include "CommonEnums.hh"
#include "ExprNode.hh"
#include "HeterogeneityTable.hh"
using namespace std;
using expr_t = class ExprNode *;
//! Types of auxiliary variables
enum class AuxVarType
{
......@@ -50,10 +49,16 @@ enum class AuxVarType
logTransform = 7, //!< Log-transformation of a variable declared with “var(log)”
diff = 8, //!< Variable for Diff operator
diffLag = 9, //!< Variable for timing between Diff operators (lag)
unaryOp = 10, //!< Variable for allowing the undiff operator to work when diff was taken of unary op, eg diff(log(x))
unaryOp = 10, //!< Variable for allowing the undiff operator to work when diff was taken of unary
//!< op, eg diff(log(x))
diffLead = 11, //!< Variable for timing between Diff operators (lead)
pacExpectation = 12, //!< Variable created for the substitution of the pac_expectation operator
pacTargetNonstationary = 13 //!< Variable created for the substitution of the pac_target_nonstationary operator
pacTargetNonstationary
= 13, //!< Variable created for the substitution of the pac_target_nonstationary operator
aggregationOp
= 14, // Substitute for an aggregation operator in a heterogeneous setup, such as SUM()
heterogeneousMultiplier = 15 /* Multiplier for bound conditions of complementarity conditions in
the heterogeneous equations */
};
//! Information on some auxiliary variables
......@@ -65,8 +70,8 @@ struct AuxVarInfo
the definition of this auxvar.
Used by endoLag, exoLag, diffForward, logTransform, diff,
diffLag, diffLead and unaryOp.
For diff and unaryOp, if the argument expression is more complex
than than a simple variable, this value is unset
For diff and unaryOp, if the argument expression is more
complex than than a simple variable, this value is unset
(hence the need for std::optional). */
const optional<int> orig_lead_lag; /* Lead/lag of the (only) endo as it appears on the RHS of the
definition of this auxvar. Only set if orig_symb_id is set
......@@ -82,7 +87,7 @@ struct AuxVarInfo
const expr_t expr_node; // Auxiliary variable definition
const string unary_op; // Used with AuxUnaryOp
int
[[nodiscard]] int
get_type_id() const
{
return static_cast<int>(type);
......@@ -106,6 +111,8 @@ struct AuxVarInfo
class SymbolTable
{
private:
HeterogeneityTable& heterogeneity_table;
//! Has method freeze() been called?
bool frozen {false};
......@@ -123,6 +130,8 @@ private:
map<int, map<string, string>> partition_value_map;
//! Maps IDs to types
vector<SymbolType> type_table;
// Maps IDs of heterogenous symbols to heterogeneity dimension IDs
map<int, int> heterogeneity_dimensions;
//! Maps symbol IDs to type specific IDs
map<int, int> type_specific_ids;
......@@ -135,9 +144,22 @@ private:
vector<int> exo_det_ids;
//! Maps type specific IDs of parameters to symbol IDs
vector<int> param_ids;
/* Maps type specific IDs of heterogeneous endogenous to symbol IDs (outer vector is for
heterogeneity dimensions) */
vector<vector<int>> het_endo_ids;
/* Maps type specific IDs of heterogeneous exogenous to symbol IDs (outer vector is for
heterogeneity dimensions) */
vector<vector<int>> het_exo_ids;
/* Maps type specific IDs of heterogeneous parameters to symbol IDs (outer vector is for
heterogeneity dimensions) */
vector<vector<int>> het_param_ids;
//! Information about auxiliary variables
vector<AuxVarInfo> aux_vars;
//! Information about heterogeneous auxiliary variables
vector<vector<AuxVarInfo>> het_aux_vars;
//! Stores the predetermined variables (by symbol IDs)
set<int> predetermined_variables;
......@@ -168,6 +190,7 @@ public:
{
const int tsid;
const SymbolType type;
const optional<int> heterogeneity_dimension;
};
/* Thrown when requesting the type specific ID of a symbol which doesn’t
have one */
......@@ -195,30 +218,44 @@ public:
class SearchFailedException
{
public:
int orig_symb_id, orig_lead_lag, symb_id;
SearchFailedException(int orig_symb_id_arg, int orig_lead_lag_arg) : orig_symb_id{orig_symb_id_arg},
orig_lead_lag{orig_lead_lag_arg}
int orig_symb_id, orig_lead_lag;
SearchFailedException(int orig_symb_id_arg, int orig_lead_lag_arg) :
orig_symb_id {orig_symb_id_arg}, orig_lead_lag {orig_lead_lag_arg}
{
}
explicit SearchFailedException(int symb_id_arg) : symb_id{symb_id_arg}
};
// Thrown by getHeterogeneityDimension() on non-heterogeneous symbols
struct NonHeteregeneousSymbolException
{
}
const int id;
};
private:
//! Factorized code for adding aux lag variables
int addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag, expr_t arg) noexcept(false);
int addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag,
expr_t arg) noexcept(false);
//! Factorized code for adding aux lead variables
int addLeadAuxiliaryVarInternal(bool endo, int index, expr_t arg) noexcept(false);
//! Factorized code for Json writing
void writeJsonVarVector(ostream& output, const vector<int>& varvec) const;
//! Factorized code for asserting that 0 <= symb_id <= symbol_table.size()
inline void validateSymbID(int symb_id) const noexcept(false);
public:
SymbolTable(HeterogeneityTable& heterogeneity_table_arg) :
heterogeneity_table {heterogeneity_table_arg}
{
}
//! Add a symbol
/*! Returns the symbol ID */
int addSymbol(const string &name, SymbolType type, const string &tex_name, const vector<pair<string, string>> &partition_value) noexcept(false);
//! Add a symbol without its TeX name (will be equal to its name)
/* Returns the symbol ID.
heterogeneity_dimension must be defined if this is a heterogeneous symbol (otherwise it is
ignored) */
int addSymbol(const string& name, SymbolType type, const string& tex_name,
const vector<pair<string, string>>& partition_value,
const optional<int>& heterogeneity_dimension) noexcept(false);
//! Add a (non-heterogenous) symbol without its TeX name (will be equal to its name)
/*! Returns the symbol ID */
int addSymbol(const string& name, SymbolType type) noexcept(false);
//! Adds an auxiliary variable for endogenous with lead >= 2
......@@ -228,9 +265,9 @@ public:
int addEndoLeadAuxiliaryVar(int index, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for endogenous with lag >= 2
/*!
\param[in] orig_symb_id symbol ID of the endogenous declared by the user that this new variable will represent
\param[in] orig_lead_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lead_lag)
\return the symbol ID of the new symbol */
\param[in] orig_symb_id symbol ID of the endogenous declared by the user that this new variable
will represent \param[in] orig_lead_lag lag value such that this new variable will be equivalent
to orig_symb_id(orig_lead_lag) \return the symbol ID of the new symbol */
int addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for endogenous with lead >= 1
/*!
......@@ -239,9 +276,9 @@ public:
int addExoLeadAuxiliaryVar(int index, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for exogenous with lag >= 1
/*!
\param[in] orig_symb_id symbol ID of the exogenous declared by the user that this new variable will represent
\param[in] orig_lead_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lead_lag)
\return the symbol ID of the new symbol */
\param[in] orig_symb_id symbol ID of the exogenous declared by the user that this new variable
will represent \param[in] orig_lead_lag lag value such that this new variable will be equivalent
to orig_symb_id(orig_lead_lag) \return the symbol ID of the new symbol */
int addExoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for the expectation operator
/*!
......@@ -250,6 +287,14 @@ public:
\return the symbol ID of the new symbol
*/
int addExpectationAuxiliaryVar(int information_set, int index, expr_t arg) noexcept(false);
/* Adds an auxiliary variable for the bound-specific multiplier of the MCPs and returns its
symbolID.
– het_dim is the heterogeneity dimension of the model
– index is the equation's index
– varname is the multiplier name
*/
int addHeterogeneousMultiplierAuxiliaryVar(int het_dim, int index,
const string& varname) noexcept(false);
//! Adds an auxiliary variable for the multiplier for the FOCs of the Ramsey Problem
/*!
\param[in] index Used to construct the variable name
......@@ -262,7 +307,8 @@ public:
– orig_lead_lag is typically 0
– expr_arg is typically log(orig_symb_id)
*/
int addLogTransformAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false);
int addLogTransformAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false);
//! Adds an auxiliary variable for the (time) differentiate of a forward var
/*!
\param[in] orig_symb_id The symb_id of the forward variable
......@@ -275,14 +321,14 @@ public:
\return the symbol ID of the auxiliary variable
Throws an exception if match not found.
*/
int searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false);
[[nodiscard]] int searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false);
/* Searches aux_vars for the aux var represented by aux_var_symb_id and
returns its associated orig_symb_id.
Throws an UnknownSymbolIDException if there is no orig_symb_id associated to
this auxvar (either because it’s of the wrong type, or because there is
no such orig var for this specific auxvar, in case of complex expressions
in diff or unaryOp). */
int getOrigSymbIdForAuxVar(int aux_var_symb_id_arg) const noexcept(false);
[[nodiscard]] int getOrigSymbIdForAuxVar(int aux_var_symb_id_arg) const noexcept(false);
/* Unrolls a chain of diffLag or diffLead aux vars until it founds a (regular) diff aux
var. In other words:
- if the arg is a (regu) diff aux var, returns the arg
......@@ -294,45 +340,58 @@ public:
output argument is equal to the 2nd input argument, shifted by as many
lead/lags were encountered in the chain (a diffLag decreases it, a
diffLead increases it). */
pair<int, int> unrollDiffLeadLagChain(int symb_id, int lag) const noexcept(false);
[[nodiscard]] pair<int, int> unrollDiffLeadLagChain(int symb_id, int lag) const noexcept(false);
//! Adds an auxiliary variable when the diff operator is encountered
int addDiffAuxiliaryVar(int index, expr_t expr_arg, optional<int> orig_symb_id = nullopt, optional<int> orig_lag = nullopt) noexcept(false);
int addDiffAuxiliaryVar(int index, expr_t expr_arg, const optional<int>& orig_symb_id = nullopt,
const optional<int>& orig_lag = nullopt) noexcept(false);
//! Takes care of timing between diff statements
int addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) noexcept(false);
int addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id,
int orig_lag) noexcept(false);
//! Takes care of timing between diff statements
int addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lead) noexcept(false);
int addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id,
int orig_lead) noexcept(false);
//! An Auxiliary variable for a unary op
int addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op, optional<int> orig_symb_id = nullopt, optional<int> orig_lag = nullopt) noexcept(false);
int addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op,
const optional<int>& orig_symb_id = nullopt,
const optional<int>& orig_lag = nullopt) noexcept(false);
//! An auxiliary variable for a pac_expectation operator
int addPacExpectationAuxiliaryVar(const string& name, expr_t expr_arg);
//! An auxiliary variable for a pac_target_nonstationary operator
int addPacTargetNonstationaryAuxiliaryVar(const string& name, expr_t expr_arg);
// An auxiliary variable for an aggregation operator (e.g. SUM(yh) where yh is heterogeneous)
int addAggregationOpAuxiliaryVar(const string& name, expr_t expr_arg);
//! Set the size of het_aux_vars
inline void resizeHetAuxVars();
//! Returns the number of auxiliary variables
int
[[nodiscard]] int
AuxVarsSize() const
{
return aux_vars.size();
};
}
//! Tests if symbol already exists
inline bool exists(const string &name) const;
[[nodiscard]] inline bool exists(const string& name) const;
//! Get symbol name (by ID)
inline string getName(int id) const noexcept(false);
[[nodiscard]] inline string getName(int id) const noexcept(false);
//! Get TeX name
inline string getTeXName(int id) const noexcept(false);
[[nodiscard]] inline string getTeXName(int id) const noexcept(false);
//! Get long name
inline string getLongName(int id) const noexcept(false);
//! Returns true if the partition name is the first encountered for the type of variable represented by id
bool isFirstOfPartitionForType(int id) const noexcept(false);
[[nodiscard]] inline string getLongName(int id) const noexcept(false);
//! Returns true if the partition name is the first encountered for the type of variable
//! represented by id
[[nodiscard]] bool isFirstOfPartitionForType(int id) const noexcept(false);
//! Returns a list of partitions and symbols that belong to that partition
map<string, map<int, string>> getPartitionsForType(SymbolType st) const noexcept(false);
[[nodiscard]] map<string, map<int, string>> getPartitionsForType(SymbolType st) const
noexcept(false);
//! Get type (by ID)
inline SymbolType getType(int id) const noexcept(false);
[[nodiscard]] inline SymbolType getType(int id) const noexcept(false);
//! Get type (by name)
inline SymbolType getType(const string &name) const noexcept(false);
[[nodiscard]] inline SymbolType getType(const string& name) const noexcept(false);
//! Get ID (by name)
inline int getID(const string &name) const noexcept(false);
[[nodiscard]] inline int getID(const string& name) const noexcept(false);
//! Get ID (by type specific ID)
int getID(SymbolType type, int tsid) const noexcept(false);
[[nodiscard]] int getID(SymbolType type, int tsid,
const optional<int>& heterogeneity_dimension = nullopt) const
noexcept(false);
//! Freeze symbol table
void freeze() noexcept(false);
//! unreeze symbol table
......@@ -341,21 +400,30 @@ public:
//! Change the type of a symbol
void changeType(int id, SymbolType newtype) noexcept(false);
//! Get type specific ID (by symbol ID)
inline int getTypeSpecificID(int id) const noexcept(false);
[[nodiscard]] inline int getTypeSpecificID(int id) const noexcept(false);
//! Get type specific ID (by symbol name)
inline int getTypeSpecificID(const string &name) const noexcept(false);
[[nodiscard]] inline int getTypeSpecificID(const string& name) const noexcept(false);
//! Get number of endogenous variables
inline int endo_nbr() const noexcept(false);
[[nodiscard]] inline int endo_nbr() const noexcept(false);
//! Get number of exogenous variables
inline int exo_nbr() const noexcept(false);
[[nodiscard]] inline int exo_nbr() const noexcept(false);
//! Get number of exogenous deterministic variables
inline int exo_det_nbr() const noexcept(false);
[[nodiscard]] inline int exo_det_nbr() const noexcept(false);
//! Get number of parameters
inline int param_nbr() const noexcept(false);
[[nodiscard]] inline int param_nbr() const noexcept(false);
//! Get number of heterogeneous endogenous variables along a given dimension
[[nodiscard]] inline int het_endo_nbr(int het_dim) const noexcept(false);
//! Get number of user-declared heterogeneous endogenous variables (without
//! the auxiliary variables)
[[nodiscard]] inline int het_orig_endo_nbr(int het_dim) const noexcept(false);
//! Get number of heterogeneous exogenous variables along a given dimension
[[nodiscard]] inline int het_exo_nbr(int het_dim) const noexcept(false);
//! Get number of heterogeneous parameters along a given dimension
[[nodiscard]] inline int het_param_nbr(int het_dim) const noexcept(false);
//! Returns the greatest symbol ID (the smallest is zero)
inline int maxID();
[[nodiscard]] inline int maxID() const;
//! Get number of user-declared endogenous variables (without the auxiliary variables)
inline int orig_endo_nbr() const noexcept(false);
[[nodiscard]] inline int orig_endo_nbr() const noexcept(false);
//! Write output of this class
void writeOutput(ostream& output) const noexcept(false);
//! Write JSON Output
......@@ -365,54 +433,59 @@ public:
//! Mark an endogenous as having been declared with “var(log)”
void markWithLogTransform(int symb_id) noexcept(false);
//! Test if a given symbol is a predetermined variable
bool isPredetermined(int symb_id) const noexcept(false);
[[nodiscard]] bool isPredetermined(int symb_id) const noexcept(false);
//! Return the number of predetermined variables
int predeterminedNbr() const;
[[nodiscard]] int predeterminedNbr() const;
//! Add an observed variable
void addObservedVariable(int symb_id) noexcept(false);
//! Return the number of observed variables
int observedVariablesNbr() const;
[[nodiscard]] int observedVariablesNbr() const;
//! Is a given symbol in the set of observed variables
bool isObservedVariable(int symb_id) const;
[[nodiscard]] bool isObservedVariable(int symb_id) const;
//! Return the index of a given observed variable in the vector of all observed variables
int getObservedVariableIndex(int symb_id) const;
[[nodiscard]] int getObservedVariableIndex(int symb_id) const;
//! Add an observed exogenous variable
void addObservedExogenousVariable(int symb_id) noexcept(false);
//! Return the number of observed exogenous variables
int observedExogenousVariablesNbr() const;
[[nodiscard]] int observedExogenousVariablesNbr() const;
//! Is a given symbol in the set of observed exogenous variables
bool isObservedExogenousVariable(int symb_id) const;
//! Return the index of a given observed exogenous variable in the vector of all observed variables
int getObservedExogenousVariableIndex(int symb_id) const;
vector <int> getTrendVarIds() const;
[[nodiscard]] bool isObservedExogenousVariable(int symb_id) const;
//! Return the index of a given observed exogenous variable in the vector of all observed
//! variables
[[nodiscard]] int getObservedExogenousVariableIndex(int symb_id) const;
[[nodiscard]] vector<int> getTrendVarIds() const;
//! Get list of exogenous variables
set <int> getExogenous() const;
[[nodiscard]] set<int> getExogenous() const;
//! Get list of exogenous variables
set <int> getObservedExogenous() const;
[[nodiscard]] set<int> getObservedExogenous() const;
//! Get list of endogenous variables
set <int> getEndogenous() const;
[[nodiscard]] set<int> getEndogenous() const;
//! Is a given symbol an auxiliary variable
bool isAuxiliaryVariable(int symb_id) const;
[[nodiscard]] bool isAuxiliaryVariable(int symb_id) const;
//! Is a given symbol a diff, diff lead, or diff lag auxiliary variable
bool isDiffAuxiliaryVariable(int symb_id) const;
[[nodiscard]] bool isDiffAuxiliaryVariable(int symb_id) const;
//! Get list of endogenous variables without aux vars
set <int> getOrigEndogenous() const;
[[nodiscard]] set<int> getOrigEndogenous() const;
//! Returns the original symbol corresponding to this variable
/* If symb_id has no original variable, returns symb_id. Otherwise,
repeatedly call getOrigSymbIDForAuxVar() until an original variable is
found. Note that the result may be an auxiliary variable if the latter has
no original variable (e.g. aux var for lead, Lagrange Multiplier or diff
associated to a complex expression). */
int getUltimateOrigSymbID(int symb_id) const;
//! If this is a Lagrange multiplier, return its associated equation number; otherwise return nullopt
optional<int> getEquationNumberForMultiplier(int symb_id) const;
[[nodiscard]] int getUltimateOrigSymbID(int symb_id) const;
//! If this is a Lagrange multiplier, return its associated equation number; otherwise return
//! nullopt
[[nodiscard]] optional<int> getEquationNumberForMultiplier(int symb_id) const;
/* Return all the information about a given auxiliary variable. Throws
UnknownSymbolIDException if it is not an aux var */
const AuxVarInfo &getAuxVarInfo(int symb_id) const;
[[nodiscard]] const AuxVarInfo& getAuxVarInfo(int symb_id) const;
// Returns the set of all endogenous declared with “var(log)”
const set<int> &getVariablesWithLogTransform() const;
[[nodiscard]] const set<int>& getVariablesWithLogTransform() const;
// Returns all Lagrange multipliers
set<int> getLagrangeMultipliers() const;
[[nodiscard]] set<int> getLagrangeMultipliers() const;
/* Get heterogeneity dimension of a given symbol. Throws NonHeterogeneousSymbolException
if there is no such dimension. */
[[nodiscard]] int getHeterogeneityDimension(int symb_id) const;
};
inline void
......@@ -422,6 +495,12 @@ SymbolTable::validateSymbID(int symb_id) const noexcept(false)
throw UnknownSymbolIDException {symb_id};
}
inline void
SymbolTable::resizeHetAuxVars()
{
het_aux_vars.resize(heterogeneity_table.size());
}
inline bool
SymbolTable::exists(const string& name) const
{
......@@ -465,8 +544,7 @@ SymbolTable::getType(const string &name) const noexcept(false)
inline int
SymbolTable::getID(const string& name) const noexcept(false)
{
if (auto iter = symbol_table.find(name);
iter != symbol_table.end())
if (auto iter = symbol_table.find(name); iter != symbol_table.end())
return iter->second;
else
throw UnknownSymbolNameException {name};
......@@ -480,8 +558,7 @@ SymbolTable::getTypeSpecificID(int id) const noexcept(false)
validateSymbID(id);
if (auto it = type_specific_ids.find(id);
it != type_specific_ids.end())
if (auto it = type_specific_ids.find(id); it != type_specific_ids.end())
return it->second;
else
throw NoTypeSpecificIDException {id};
......@@ -530,7 +607,43 @@ SymbolTable::param_nbr() const noexcept(false)
}
inline int
SymbolTable::maxID()
SymbolTable::het_endo_nbr(int het_dim) const noexcept(false)
{
if (!frozen)
throw NotYetFrozenException();
return het_endo_ids.at(het_dim).size();
}
inline int
SymbolTable::het_orig_endo_nbr(int het_dim) const noexcept(false)
{
if (!frozen)
throw NotYetFrozenException();
return het_endo_ids.at(het_dim).size() - het_aux_vars.at(het_dim).size();
}
inline int
SymbolTable::het_exo_nbr(int het_dim) const noexcept(false)
{
if (!frozen)
throw NotYetFrozenException();
return het_exo_ids.at(het_dim).size();
}
inline int
SymbolTable::het_param_nbr(int het_dim) const noexcept(false)
{
if (!frozen)
throw NotYetFrozenException();
return het_param_ids.at(het_dim).size();
}
inline int
SymbolTable::maxID() const
{
return symbol_table.size() - 1;
}
......
......@@ -17,8 +17,8 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <algorithm>
#include <iostream>
#include "VariableDependencyGraph.hh"
......@@ -29,6 +29,7 @@
#include <boost/graph/strong_components.hpp>
#include <boost/graph/topological_sort.hpp>
#pragma GCC diagnostic pop
#include <ranges>
using namespace boost;
......@@ -59,16 +60,17 @@ VariableDependencyGraph::eliminate(vertex_descriptor vertex_to_eliminate)
{
if (in_degree(vertex_to_eliminate, *this) > 0 && out_degree(vertex_to_eliminate, *this) > 0)
for (auto [it_in, in_end] = in_edges(vertex_to_eliminate, *this); it_in != in_end; ++it_in)
for (auto [it_out, out_end] = out_edges(vertex_to_eliminate, *this); it_out != out_end; ++it_out)
if (auto [ed, exist] = edge(source(*it_in, *this), target(*it_out, *this), *this);
!exist)
for (auto [it_out, out_end] = out_edges(vertex_to_eliminate, *this); it_out != out_end;
++it_out)
if (auto [ed, exist] = edge(source(*it_in, *this), target(*it_out, *this), *this); !exist)
add_edge(source(*it_in, *this), target(*it_out, *this), *this);
suppress(vertex_to_eliminate);
}
bool
VariableDependencyGraph::hasCycleDFS(vertex_descriptor u, color_t &color, vector<int> &circuit_stack) const
VariableDependencyGraph::hasCycleDFS(vertex_descriptor u, color_t& color,
vector<int>& circuit_stack) const
{
auto v_index = get(vertex_index, *this);
color[u] = gray_color;
......@@ -199,7 +201,8 @@ VariableDependencyGraph::eliminationOfVerticesWithOneOrLessIndegreeOrOutdegree()
if (in_degree_n <= 1 || out_degree_n <= 1)
{
not_a_loop = true;
if (in_degree_n >= 1 && out_degree_n >= 1) // Do not eliminate a vertex if it loops on itself!
if (in_degree_n >= 1
&& out_degree_n >= 1) // Do not eliminate a vertex if it loops on itself!
for (auto [it_in, in_end] = in_edges(*it, *this); it_in != in_end; ++it_in)
if (source(*it_in, *this) == target(*it_in, *this))
not_a_loop = false;
......@@ -285,8 +288,10 @@ VariableDependencyGraph::minimalSetOfFeedbackVertices() const
while (something_has_been_done && num_vertices(G) > 0)
{
something_has_been_done = G.eliminationOfVerticesWithOneOrLessIndegreeOrOutdegree();
something_has_been_done = G.eliminationOfVerticesBelongingToAClique() || something_has_been_done;
something_has_been_done = G.suppressionOfVerticesWithLoop(feed_back_vertices) || something_has_been_done;
something_has_been_done
= G.eliminationOfVerticesBelongingToAClique() || something_has_been_done;
something_has_been_done
= G.suppressionOfVerticesWithLoop(feed_back_vertices) || something_has_been_done;
}
if (!G.hasCycle())
......@@ -321,8 +326,8 @@ VariableDependencyGraph::reorderRecursiveVariables(const set<int> &feedback_vert
auto v_index = get(vertex_index, G);
// Suppress feedback vertices, in decreasing order
for (auto it = feedback_vertices.rbegin(); it != feedback_vertices.rend(); ++it)
G.suppress(*it);
for (int feedback_vertex : ranges::reverse_view(feedback_vertices))
G.suppress(feedback_vertex);
bool something_has_been_done = true;
while (something_has_been_done)
......@@ -362,7 +367,8 @@ VariableDependencyGraph::sortedStronglyConnectedComponents() const
auto v_index = get(vertex_index, *this);
// Compute SCCs and create mapping from vertices to unordered SCCs
int num_scc = strong_components(static_cast<base>(*this), make_iterator_property_map(vertex2scc.begin(), v_index));
int num_scc = strong_components(static_cast<base>(*this),
make_iterator_property_map(vertex2scc.begin(), v_index));
// Create directed acyclic graph (DAG) associated to the SCCs
adjacency_list<vecS, vecS, directedS> dag(num_scc);
......
/*
* Copyright © 2009-2020 Dynare Team
* Copyright © 2009-2023 Dynare Team
*
* This file is part of Dynare.
*
......@@ -17,8 +17,8 @@
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _VARIABLEDEPENDENCYGRAPH_HH
#define _VARIABLEDEPENDENCYGRAPH_HH
#ifndef VARIABLE_DEPENDENCY_GRAPH_HH
#define VARIABLE_DEPENDENCY_GRAPH_HH
#include <map>
#include <vector>
......@@ -30,20 +30,25 @@
using namespace std;
using VertexProperty_t = boost::property<boost::vertex_index_t, int,
boost::property<boost::vertex_index1_t, int,
using VertexProperty_t = boost::property<
boost::vertex_index_t, int,
boost::property<
boost::vertex_index1_t, int,
boost::property<boost::vertex_degree_t, int,
boost::property<boost::vertex_in_degree_t, int,
boost::property<boost::vertex_out_degree_t, int>>>>>;
/* Class used to store a graph representing dependencies between variables.
Used in the block decomposition. */
class VariableDependencyGraph
: public boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, VertexProperty_t>
class VariableDependencyGraph :
public boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS,
VertexProperty_t>
{
public:
using color_t = map<boost::graph_traits<VariableDependencyGraph>::vertex_descriptor, boost::default_color_type>;
using base = boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, VertexProperty_t>;
using color_t = map<boost::graph_traits<VariableDependencyGraph>::vertex_descriptor,
boost::default_color_type>;
using base
= boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, VertexProperty_t>;
VariableDependencyGraph(int n);
//! Extracts a subgraph
......@@ -54,19 +59,21 @@ public:
The property vertex_index1 of the subgraph contains indices of the original
graph.
*/
VariableDependencyGraph extractSubgraph(const vector<int> &select_index) const;
[[nodiscard]] VariableDependencyGraph extractSubgraph(const vector<int>& select_index) const;
//! Return the feedback set
set<int> minimalSetOfFeedbackVertices() const;
[[nodiscard]] set<int> minimalSetOfFeedbackVertices() const;
//! Reorder the recursive variables
/*! They appear first in a quasi triangular form and they are followed by the feedback variables */
vector<int> reorderRecursiveVariables(const set<int> &feedback_vertices) const;
/*! They appear first in a quasi triangular form and they are followed by the feedback variables
*/
[[nodiscard]] vector<int> reorderRecursiveVariables(const set<int>& feedback_vertices) const;
/* Computes the strongly connected components (SCCs) of the graph, and sort them
topologically.
Returns the number of SCCs, and a mapping of vertex indices to sorted SCC
indices. */
pair<int, vector<int>> sortedStronglyConnectedComponents() const;
[[nodiscard]] pair<int, vector<int>> sortedStronglyConnectedComponents() const;
// Print on stdout a description of the graph
void print() const;
private:
// Remove a vertex (including all edges to and from it); takes a vertex descriptor
void suppress(vertex_descriptor vertex_to_eliminate);
......@@ -79,7 +86,7 @@ private:
// Internal helper for hasCycle()
bool hasCycleDFS(vertex_descriptor u, color_t& color, vector<int>& circuit_stack) const;
// Determine whether the graph has a cycle
bool hasCycle() const;
[[nodiscard]] bool hasCycle() const;
bool vertexBelongsToAClique(vertex_descriptor vertex) const;
bool eliminationOfVerticesWithOneOrLessIndegreeOrOutdegree();
bool eliminationOfVerticesBelongingToAClique();
......@@ -87,4 +94,4 @@ private:
bool suppressionOfVerticesWithLoop(set<int>& feed_back_vertices);
};
#endif // _VARIABLEDEPENDENCYGRAPH_HH
#endif