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

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
Show changes
/* /*
* Copyright © 2018-2019 Dynare Team * Copyright © 2018-2023 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,20 +14,25 @@ ...@@ -14,20 +14,25 @@
* GNU General Public License for more details.SS * GNU General Public License for more details.SS
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _SUBMODEL_HH #ifndef SUB_MODEL_HH
#define _SUBMODEL_HH #define SUB_MODEL_HH
#include <set> #include <iostream>
#include <map> #include <map>
#include <optional>
#include <set>
#include <vector> #include <vector>
#include <iostream>
#include "ExprNode.hh" #include "ExprNode.hh"
#include "SymbolTable.hh" #include "Statement.hh"
#include "SymbolList.hh" #include "SymbolList.hh"
#include "SymbolTable.hh"
// DynamicModel.hh can’t be included here, otherwise it would be a circular dependency
class DynamicModel;
using namespace std; using namespace std;
...@@ -41,13 +46,17 @@ private: ...@@ -41,13 +46,17 @@ private:
SymbolTable& symbol_table; SymbolTable& symbol_table;
set<string> names; set<string> names;
map<string, vector<string>> eqtags, target_eqtags; map<string, vector<string>> eqtags, target_eqtags;
map<string, vector<int>> eqnums, target_eqnums, nontarget_eqnums, max_lags, lhs, target_lhs, nontarget_lhs, orig_diff_var; 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<set<pair<int, int>>>> rhs;
map<string, vector<bool>> diff; map<string, vector<bool>> diff;
map<string, vector<expr_t>> lhs_expr_t; map<string, vector<expr_t>> lhs_expr_t;
map<string, vector<int>> target_vars; map<string, vector<optional<int>>> target_vars;
map<string, map<tuple<int, int, int>, expr_t>> AR; // AR: name -> (eqn, lag, lhs_symb_id) -> expr_t map<string, map<tuple<int, int, int>, expr_t>> AR; // name -> (eqn, lag, lhs_symb_id) -> expr_t
map<string, map<tuple<int, int, int>, expr_t>> A0, A0star; // EC: name -> (eqn, lag, col) -> expr_t /* Note that A0 in the trend-component model context is not the same thing as
in the structural VAR context. */
map<string, map<tuple<int, int>, expr_t>> A0, A0star; // name -> (eqn, col) -> expr_t
public: public:
explicit TrendComponentModelTable(SymbolTable& symbol_table_arg); explicit TrendComponentModelTable(SymbolTable& symbol_table_arg);
...@@ -55,38 +64,36 @@ public: ...@@ -55,38 +64,36 @@ public:
void addTrendComponentModel(string name_arg, vector<string> eqtags_arg, void addTrendComponentModel(string name_arg, vector<string> eqtags_arg,
vector<string> target_eqtags_arg); vector<string> target_eqtags_arg);
inline bool isExistingTrendComponentModelName(const string &name_arg) const; [[nodiscard]] inline bool isExistingTrendComponentModelName(const string& name_arg) const;
inline bool empty() const; [[nodiscard]] inline bool empty() const;
map<string, vector<string>> getEqTags() const; [[nodiscard]] const map<string, vector<string>>& getEqTags() const;
vector<string> getEqTags(const string &name_arg) const; [[nodiscard]] const vector<string>& getEqTags(const string& name_arg) const;
map<string, vector<string>> getTargetEqTags() const; [[nodiscard]] const map<string, vector<string>>& getTargetEqTags() const;
map<string, vector<int>> getEqNums() const; [[nodiscard]] const map<string, vector<int>>& getEqNums() const;
map<string, vector<int>> getTargetEqNums() const; [[nodiscard]] const map<string, vector<int>>& getTargetEqNums() const;
vector<int> getTargetEqNums(const string &name_arg) const; [[nodiscard]] const vector<int>& getTargetEqNums(const string& name_arg) const;
vector<int> getEqNums(const string &name_arg) const; [[nodiscard]] const vector<int>& getEqNums(const string& name_arg) const;
vector<int> getMaxLags(const string &name_arg) const; [[nodiscard]] const vector<int>& getMaxLags(const string& name_arg) const;
int getMaxLag(const string &name_arg) const; [[nodiscard]] int getMaxLag(const string& name_arg) const;
vector<int> getLhs(const string &name_arg) const; [[nodiscard]] const vector<int>& getLhs(const string& name_arg) const;
vector<expr_t> getLhsExprT(const string &name_arg) const; [[nodiscard]] const vector<expr_t>& getLhsExprT(const string& name_arg) const;
vector<bool> getDiff(const string &name_arg) const; [[nodiscard]] const vector<bool>& getDiff(const string& name_arg) const;
vector<int> getOrigDiffVar(const string &name_arg) const; [[nodiscard]] const map<string, vector<int>>& getNonTargetEqNums() const;
map<string, vector<int>> getNonTargetEqNums() const; [[nodiscard]] const vector<int>& getNonTargetEqNums(const string& name_arg) const;
vector<int> getNonTargetEqNums(const string &name_arg) const; [[nodiscard]] const vector<int>& getNonTargetLhs(const string& name_arg) const;
vector<int> getNonTargetLhs(const string &name_arg) const; [[nodiscard]] const vector<int>& getTargetLhs(const string& name_arg) const;
vector<int> getTargetLhs(const string &name_arg) const;
void setVals(map<string, vector<int>> eqnums_arg, map<string, vector<int>> target_eqnums_arg, void setVals(map<string, vector<int>> eqnums_arg, map<string, vector<int>> target_eqnums_arg,
map<string, vector<int>> lhs_arg, map<string, vector<int>> lhs_arg, map<string, vector<expr_t>> lhs_expr_t_arg);
map<string, vector<expr_t>> lhs_expr_t_arg);
void setRhs(map<string, vector<set<pair<int, int>>>> rhs_arg); void setRhs(map<string, vector<set<pair<int, int>>>> rhs_arg);
void setMaxLags(map<string, vector<int>> max_lags_arg); void setMaxLags(map<string, vector<int>> max_lags_arg);
void setDiff(map<string, vector<bool>> diff_arg); void setDiff(map<string, vector<bool>> diff_arg);
void setOrigDiffVar(map<string, vector<int>> orig_diff_var_arg); void setOrigDiffVar(map<string, vector<optional<int>>> orig_diff_var_arg);
void setTargetVar(map<string, vector<int>> target_vars_arg); void setTargetVar(map<string, vector<optional<int>>> target_vars_arg);
void setAR(map<string, map<tuple<int, int, int>, expr_t>> AR_arg); void setAR(map<string, map<tuple<int, int, int>, expr_t>> AR_arg);
void setA0(map<string, map<tuple<int, int, int>, expr_t>> A0_arg, void setA0(map<string, map<tuple<int, int>, expr_t>> A0_arg,
map<string, map<tuple<int, int, int>, expr_t>> A0star_arg); map<string, map<tuple<int, int>, expr_t>> A0star_arg);
//! Write output of this class //! Write output of this class
void writeOutput(const string& basename, ostream& output) const; void writeOutput(const string& basename, ostream& output) const;
...@@ -102,7 +109,7 @@ private: ...@@ -102,7 +109,7 @@ private:
inline bool inline bool
TrendComponentModelTable::isExistingTrendComponentModelName(const string& name_arg) const TrendComponentModelTable::isExistingTrendComponentModelName(const string& name_arg) const
{ {
return names.find(name_arg) != names.end(); return names.contains(name_arg);
} }
inline bool inline bool
...@@ -116,35 +123,43 @@ class VarModelTable ...@@ -116,35 +123,43 @@ class VarModelTable
private: private:
SymbolTable& symbol_table; SymbolTable& symbol_table;
set<string> names; set<string> names;
map<string, pair<SymbolList, int>> symbol_list_and_order; map<string, bool> structural; // Whether VARs are structural or reduced-form
map<string, vector<string>> eqtags; map<string, vector<string>> eqtags;
map<string, vector<int>> eqnums, max_lags, lhs, lhs_orig_symb_ids, orig_diff_var; map<string, vector<int>> eqnums, max_lags, lhs, lhs_orig_symb_ids;
map<string, vector<set<pair<int, int>>>> rhs; 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<bool>> diff; map<string, vector<bool>> diff;
map<string, vector<expr_t>> lhs_expr_t; map<string, vector<expr_t>> lhs_expr_t;
map<string, map<tuple<int, int, int>, expr_t>> AR; // 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
context. */
map<string, map<tuple<int, int>, expr_t>> A0; // name -> (eqn, lhs_symb_id) -> param_expr_t
map<string, map<int, expr_t>> constants; // name -> eqn -> constant
public: public:
explicit VarModelTable(SymbolTable& symbol_table_arg); explicit VarModelTable(SymbolTable& symbol_table_arg);
//! Add a VAR model //! Add a VAR model
void addVarModel(string name, vector<string> eqtags, void addVarModel(string name, bool structural_arg, vector<string> eqtags);
pair<SymbolList, int> symbol_list_and_order_arg);
[[nodiscard]] inline bool isExistingVarModelName(const string& name_arg) const;
inline bool isExistingVarModelName(const string &name_arg) const; [[nodiscard]] inline bool empty() const;
inline bool empty() const;
[[nodiscard]] const map<string, bool>& getStructural() const;
map<string, vector<string>> getEqTags() const; [[nodiscard]] const map<string, vector<string>>& getEqTags() const;
vector<string> getEqTags(const string &name_arg) const; [[nodiscard]] const vector<string>& getEqTags(const string& name_arg) const;
map<string, vector<int>> getEqNums() const; [[nodiscard]] const map<string, vector<int>>& getEqNums() const;
vector<bool> getDiff(const string &name_arg) const; [[nodiscard]] const vector<bool>& getDiff(const string& name_arg) const;
vector<int> getEqNums(const string &name_arg) const; [[nodiscard]] const vector<int>& getEqNums(const string& name_arg) const;
vector<int> getMaxLags(const string &name_arg) const; [[nodiscard]] const vector<int>& getMaxLags(const string& name_arg) const;
int getMaxLag(const string &name_arg) const; [[nodiscard]] int getMaxLag(const string& name_arg) const;
vector<int> getLhs(const string &name_arg) const; [[nodiscard]] const vector<int>& getLhs(const string& name_arg) const;
vector<int> getLhsOrigIds(const string &name_arg) const; [[nodiscard]] const vector<int>& getLhsOrigIds(const string& name_arg) const;
map<string, pair<SymbolList, int>> getSymbolListAndOrder() const; [[nodiscard]] const vector<set<pair<int, int>>>& getRhs(const string& name_arg) const;
vector<set<pair<int, int>>> getRhs(const string &name_arg) const; [[nodiscard]] const vector<expr_t>& getLhsExprT(const string& name_arg) const;
vector<expr_t> getLhsExprT(const string &name_arg) const;
void setEqNums(map<string, vector<int>> eqnums_arg); void setEqNums(map<string, vector<int>> eqnums_arg);
void setLhs(map<string, vector<int>> lhs_arg); void setLhs(map<string, vector<int>> lhs_arg);
...@@ -152,8 +167,10 @@ public: ...@@ -152,8 +167,10 @@ public:
void setLhsExprT(map<string, vector<expr_t>> lhs_expr_t_arg); void setLhsExprT(map<string, vector<expr_t>> lhs_expr_t_arg);
void setDiff(map<string, vector<bool>> diff_arg); void setDiff(map<string, vector<bool>> diff_arg);
void setMaxLags(map<string, vector<int>> max_lags_arg); void setMaxLags(map<string, vector<int>> max_lags_arg);
void setOrigDiffVar(map<string, vector<int>> orig_diff_var_arg); void setOrigDiffVar(map<string, vector<optional<int>>> orig_diff_var_arg);
void setAR(map<string, map<tuple<int, int, int>, expr_t>> AR_arg); void setAR(map<string, map<tuple<int, int, int>, expr_t>> AR_arg);
void setA0(map<string, map<tuple<int, int>, expr_t>> A0_arg);
void setConstants(map<string, map<int, expr_t>> constants_arg);
//! Write output of this class //! Write output of this class
void writeOutput(const string& basename, ostream& output) const; void writeOutput(const string& basename, ostream& output) const;
...@@ -168,7 +185,7 @@ private: ...@@ -168,7 +185,7 @@ private:
inline bool inline bool
VarModelTable::isExistingVarModelName(const string& name_arg) const VarModelTable::isExistingVarModelName(const string& name_arg) const
{ {
return names.find(name_arg) != names.end(); return names.contains(name_arg);
} }
inline bool inline bool
...@@ -177,4 +194,161 @@ VarModelTable::empty() const ...@@ -177,4 +194,161 @@ VarModelTable::empty() const
return names.empty(); return names.empty();
} }
class VarExpectationModelTable
{
private:
SymbolTable& symbol_table;
set<string> names;
map<string, expr_t> expression;
map<string, string> aux_model_name;
map<string, string> horizon;
map<string, expr_t> discount;
map<string, int> time_shift;
// For each model, list of generated auxiliary param ids, in variable-major order
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);
[[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,
const TrendComponentModelTable& trend_component_model_table);
void writeOutput(ostream& output) const;
void writeJsonOutput(ostream& output) const;
};
class PacModelTable
{
private:
SymbolTable& symbol_table;
set<string> names;
map<string, string> aux_model_name;
map<string, string> discount;
/* The growth expressions belong to the main dynamic_model from the ModFile
instance. The growth expression is necessarily nullptr for a model with a
pac_target_info block. */
map<string, expr_t> growth, original_growth;
/* Information about the structure of growth expressions (which must be a
linear combination of variables, possibly with additional constants).
Each tuple represents a term: (endo_id, lag, param_id, constant) */
using growth_info_t = vector<tuple<optional<int>, int, optional<int>, double>>;
map<string, growth_info_t> growth_info;
// The “auxname” option of pac_model (empty if not passed)
map<string, string> auxname;
// The “kind” option of pac_model (“undefined” if not passed)
map<string, PacTargetKind> kind;
/* Stores the name of the PAC equation associated to the model.
pac_model_name → eq_name */
map<string, string> eq_name;
/* Stores symb_ids for auxiliary endogenous created for the expression
substituted to the pac_expectation operator:
- in the backward case, this auxiliary contains exactly the
pac_expectation value
- in the MCE case, this auxiliary represents Z₁ (i.e. without the growth
correction term)
Note that this structure is not used in the presence of the
pac_target_info block.
pac_model_name → symb_id */
map<string, int> aux_var_symb_ids;
/* Stores symb_ids for auxiliary parameters created for the expression
substituted to the pac_expectation operator (excluding the growth
neutrality correction):
- in the backward case, contains the “h” parameters
- in the MCE case, contains the “α” parameters
Note that this structure is not used in the presence of the
pac_target_info block.
pac_model_name → symb_ids */
map<string, vector<int>> aux_param_symb_ids;
/* Stores indices for growth neutrality parameters
pac_model_name → growth_neutrality_param_index.
This map is not used for PAC models with a pac_target_info block. */
map<string, int> growth_neutrality_params;
// Stores LHS vars (only for backward PAC models)
map<string, vector<int>> lhs;
// Stores auxiliary model type (only for backward PAC models)
map<string, string> aux_model_type;
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)
*/
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;
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>;
private:
// pac_model_name → (target variable/expr, auxname_target_nonstationary, target components)
map<string, tuple<expr_t, string, vector<target_component_t>>> target_info;
[[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);
[[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 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);
// 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,
const TrendComponentModelTable& trend_component_model_table);
void writeOutput(ostream& output) const;
void writeJsonOutput(ostream& output) const;
void setTargetExpr(const string& name_arg, expr_t target);
void setTargetAuxnameNonstationary(const string& name_arg, string auxname);
/* Only the first four elements of the tuple are expected to be set by the
caller. The other ones will be filled by this class. */
void addTargetComponent(const string& name_arg, target_component_t component);
void writeTargetCoefficientsFile(const string& basename) const;
};
#endif #endif
/* /*
* Copyright © 2003-2019 Dynare Team * Copyright © 2003-2024 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,37 +14,41 @@ ...@@ -14,37 +14,41 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <regex> #include <regex>
#include "SymbolList.hh" #include "SymbolList.hh"
void SymbolList::SymbolList(vector<string> symbols_arg) : symbols {move(symbols_arg)}
SymbolList::setSymbolTable(const SymbolTable &symbol_table_arg)
{ {
symbol_table = &symbol_table_arg;
} }
void void
SymbolList::addSymbol(const string &symbol) SymbolList::checkPass(WarningConsolidation& warnings, const vector<SymbolType>& types,
const SymbolTable& symbol_table) const noexcept(false)
{ {
symbols.push_back(symbol); if (types.empty())
} return;
void
SymbolList::checkPass(WarningConsolidation &warnings) const noexcept(false)
{
smatch m; smatch m;
regex re("^(AUX_EXPECT_|AUX_ENDO_|MULT_)"); string regex_str = "AUX_EXPECT_|MULT_";
for (auto type : types)
if (type == SymbolType::endogenous)
{
regex_str += "|AUX_ENDO_|LOG_";
break;
}
regex re("^(" + regex_str + ")");
for (const auto& symbol : symbols) for (const auto& symbol : symbols)
{ {
if (!symbol_table->exists(symbol)) if (!symbol_table.exists(symbol))
{ {
if (regex_search(symbol, m, re)) 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 " << "This is being ignored because the variable name corresponds to a possible "
<< "auxiliary variable name." << endl; << "auxiliary variable name." << endl;
return; return;
...@@ -53,8 +57,65 @@ SymbolList::checkPass(WarningConsolidation &warnings) const noexcept(false) ...@@ -53,8 +57,65 @@ SymbolList::checkPass(WarningConsolidation &warnings) const noexcept(false)
throw SymbolListException {"Variable " + symbol + " was not declared."}; throw SymbolListException {"Variable " + symbol + " was not declared."};
} }
if (symbol_table->getType(symbol) != SymbolType::endogenous) if (ranges::none_of(types,
throw SymbolListException{"Variable " + symbol + " is not endogenous."}; [&](SymbolType type) { return symbol_table.getType(symbol) == type; }))
{
string valid_types;
for (auto type : types)
switch (type)
{
case SymbolType::endogenous:
valid_types += "endogenous, ";
break;
case SymbolType::exogenous:
valid_types += "exogenous, ";
break;
case SymbolType::epilogue:
valid_types += "epilogue, ";
break;
case SymbolType::parameter:
valid_types += "parameter, ";
break;
case SymbolType::exogenousDet:
valid_types += "exogenousDet, ";
break;
case SymbolType::trend:
valid_types += "trend, ";
break;
case SymbolType::logTrend:
valid_types += "logTrend, ";
break;
case SymbolType::modFileLocalVariable:
valid_types += "modFileLocalVariable, ";
break;
case SymbolType::modelLocalVariable:
valid_types += "modelLocalVariable, ";
break;
case SymbolType::externalFunction:
valid_types += "externalFunction, ";
break;
case SymbolType::statementDeclaredVariable:
valid_types += "statementDeclaredVariable, ";
break;
case SymbolType::unusedEndogenous:
valid_types += "unusedEndogenous, ";
break;
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 + "}"};
}
} }
} }
...@@ -62,11 +123,11 @@ void ...@@ -62,11 +123,11 @@ void
SymbolList::writeOutput(const string& varname, ostream& output) const SymbolList::writeOutput(const string& varname, ostream& output) const
{ {
output << varname << " = {"; output << varname << " = {";
for (auto it = symbols.begin(); it != symbols.end(); ++it) for (bool printed_something {false}; const auto& name : symbols)
{ {
if (it != symbols.begin()) if (exchange(printed_something, true))
output << ";"; output << ";";
output << "'" << *it << "'"; output << "'" << name << "'";
} }
output << "};" << endl; output << "};" << endl;
} }
...@@ -75,27 +136,15 @@ void ...@@ -75,27 +136,15 @@ void
SymbolList::writeJsonOutput(ostream& output) const SymbolList::writeJsonOutput(ostream& output) const
{ {
output << R"("symbol_list": [)"; output << R"("symbol_list": [)";
for (auto it = symbols.begin(); it != symbols.end(); ++it) for (bool printed_something {false}; const auto& name : symbols)
{ {
if (it != symbols.begin()) if (exchange(printed_something, true))
output << ","; output << ",";
output << R"(")" << *it << R"(")"; output << R"(")" << name << R"(")";
} }
output << "]"; output << "]";
} }
void
SymbolList::clear()
{
symbols.clear();
}
int
SymbolList::getSize() const
{
return symbols.size();
}
vector<string> vector<string>
SymbolList::getSymbols() const SymbolList::getSymbols() const
{ {
...@@ -111,6 +160,7 @@ SymbolList::removeDuplicates(const string &dynare_command, WarningConsolidation ...@@ -111,6 +160,7 @@ SymbolList::removeDuplicates(const string &dynare_command, WarningConsolidation
unique_symbols.push_back(it); unique_symbols.push_back(it);
else else
warnings << "WARNING: In " << dynare_command << ": " << it warnings << "WARNING: In " << dynare_command << ": " << it
<< " found more than once in symbol list. Removing all but first occurence." << endl; << " found more than once in symbol list. Removing all but first occurrence."
<< endl;
symbols = unique_symbols; symbols = unique_symbols;
} }
/* /*
* Copyright © 2003-2019 Dynare Team * Copyright © 2003-2023 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,19 +14,19 @@ ...@@ -14,19 +14,19 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _SYMBOL_LIST_HH #ifndef SYMBOL_LIST_HH
#define _SYMBOL_LIST_HH #define SYMBOL_LIST_HH
#include <algorithm>
#include <ostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <ostream>
#include <algorithm>
#include "WarningConsolidation.hh"
#include "SymbolTable.hh" #include "SymbolTable.hh"
#include "WarningConsolidation.hh"
using namespace std; using namespace std;
...@@ -35,26 +35,22 @@ using namespace std; ...@@ -35,26 +35,22 @@ using namespace std;
class SymbolList class SymbolList
{ {
private: private:
//! Internal container for symbol list
vector<string> symbols; vector<string> symbols;
const SymbolTable *symbol_table;
public: public:
class SymbolListException SymbolList() = default;
// This constructor is deliberately not marked explicit, to allow implicit conversion
SymbolList(vector<string> symbols_arg);
struct SymbolListException
{ {
public:
const string message; const string message;
SymbolListException(string message_arg) : message{move(message_arg)}
{
};
}; };
//! Set symbol table pointer //! Remove duplicate symbols
void setSymbolTable(const SymbolTable &symbol_table_arg);
//! Adds a symbol to the list
void addSymbol(const string &symbol);
//! Removed duplicate symbols
void removeDuplicates(const string& dynare_command, WarningConsolidation& warnings); void removeDuplicates(const string& dynare_command, WarningConsolidation& warnings);
//! Check symbols to ensure variables have been declared and are endogenous //! Check symbols to ensure variables have been declared and are endogenous
void checkPass(WarningConsolidation &warnings) const noexcept(false); void checkPass(WarningConsolidation& warnings, const vector<SymbolType>& types,
const SymbolTable& symbol_table) const noexcept(false);
//! Output content in Matlab format //! Output content in Matlab format
/*! Creates a string array for Matlab, stored in variable "varname" */ /*! Creates a string array for Matlab, stored in variable "varname" */
void writeOutput(const string& varname, ostream& output) const; void writeOutput(const string& varname, ostream& output) const;
...@@ -62,24 +58,14 @@ public: ...@@ -62,24 +58,14 @@ public:
void write(ostream& output) const; void write(ostream& output) const;
//! Write JSON output //! Write JSON output
void writeJsonOutput(ostream& output) const; void writeJsonOutput(ostream& output) const;
//! Clears all content
void clear();
//! Get a copy of the string vector
vector<string>
get_symbols() const
{
return symbols;
};
//! Is Empty //! Is Empty
int [[nodiscard]] bool
empty() const empty() const
{ {
return symbols.empty(); return symbols.empty();
}; }
//! Return the number of Symbols contained in the list
int getSize() const;
//! Return the list of symbols //! Return the list of symbols
vector<string> getSymbols() const; [[nodiscard]] vector<string> getSymbols() const;
}; };
#endif #endif
/* /*
* Copyright © 2003-2019 Dynare Team * Copyright © 2003-2024 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <algorithm> #include <algorithm>
#include <sstream>
#include <iostream>
#include <cassert> #include <cassert>
#include <iostream>
#include <sstream>
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wold-style-cast"
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
...@@ -29,22 +29,10 @@ ...@@ -29,22 +29,10 @@
#include "SymbolTable.hh" #include "SymbolTable.hh"
AuxVarInfo::AuxVarInfo(int symb_id_arg, AuxVarType type_arg, int orig_symb_id_arg, int orig_lead_lag_arg,
int equation_number_for_multiplier_arg, int information_set_arg,
expr_t expr_node_arg, string unary_op_arg) :
symb_id{symb_id_arg},
type{type_arg},
orig_symb_id{orig_symb_id_arg},
orig_lead_lag{orig_lead_lag_arg},
equation_number_for_multiplier{equation_number_for_multiplier_arg},
information_set{information_set_arg},
expr_node{expr_node_arg},
unary_op{move(unary_op_arg)}
{
}
int 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) if (frozen)
throw FrozenException(); throw FrozenException();
...@@ -52,9 +40,9 @@ SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_na ...@@ -52,9 +40,9 @@ SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_na
if (exists(name)) if (exists(name))
{ {
if (type_table[getID(name)] == type) if (type_table[getID(name)] == type)
throw AlreadyDeclaredException(name, true); throw AlreadyDeclaredException {name, true};
else else
throw AlreadyDeclaredException(name, false); throw AlreadyDeclaredException {name, false};
} }
string final_tex_name = tex_name; string final_tex_name = tex_name;
...@@ -91,13 +79,20 @@ SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_na ...@@ -91,13 +79,20 @@ SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_na
pmv[it.first] = it.second; pmv[it.first] = it.second;
partition_value_map[id] = pmv; 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; return id;
} }
int int
SymbolTable::addSymbol(const string& name, SymbolType type) noexcept(false) SymbolTable::addSymbol(const string& name, SymbolType type) noexcept(false)
{ {
return addSymbol(name, type, "", {}); return addSymbol(name, type, "", {}, {});
} }
void void
...@@ -108,6 +103,10 @@ SymbolTable::freeze() noexcept(false) ...@@ -108,6 +103,10 @@ SymbolTable::freeze() noexcept(false)
frozen = true; 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++) for (int i = 0; i < static_cast<int>(symbol_table.size()); i++)
{ {
int tsi; int tsi;
...@@ -129,11 +128,22 @@ SymbolTable::freeze() noexcept(false) ...@@ -129,11 +128,22 @@ SymbolTable::freeze() noexcept(false)
tsi = param_ids.size(); tsi = param_ids.size();
param_ids.push_back(i); param_ids.push_back(i);
break; break;
default: case SymbolType::heterogeneousEndogenous:
tsi = -1; 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; break;
default:
continue;
} }
type_specific_ids.push_back(tsi); type_specific_ids[i] = tsi;
} }
} }
...@@ -145,12 +155,18 @@ SymbolTable::unfreeze() ...@@ -145,12 +155,18 @@ SymbolTable::unfreeze()
exo_ids.clear(); exo_ids.clear();
exo_det_ids.clear(); exo_det_ids.clear();
param_ids.clear(); param_ids.clear();
het_endo_ids.clear();
het_exo_ids.clear();
het_param_ids.clear();
type_specific_ids.clear(); type_specific_ids.clear();
} }
void void
SymbolTable::changeType(int id, SymbolType newtype) noexcept(false) 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) if (frozen)
throw FrozenException(); throw FrozenException();
...@@ -160,7 +176,8 @@ SymbolTable::changeType(int id, SymbolType newtype) noexcept(false) ...@@ -160,7 +176,8 @@ SymbolTable::changeType(int id, SymbolType newtype) noexcept(false)
} }
int 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) if (!frozen)
throw NotYetFrozenException(); throw NotYetFrozenException();
...@@ -169,26 +186,44 @@ SymbolTable::getID(SymbolType type, int tsid) const noexcept(false) ...@@ -169,26 +186,44 @@ SymbolTable::getID(SymbolType type, int tsid) const noexcept(false)
{ {
case SymbolType::endogenous: case SymbolType::endogenous:
if (tsid < 0 || tsid >= static_cast<int>(endo_ids.size())) if (tsid < 0 || tsid >= static_cast<int>(endo_ids.size()))
throw UnknownTypeSpecificIDException(tsid, type); throw UnknownTypeSpecificIDException {tsid, type, {}};
else else
return endo_ids[tsid]; return endo_ids[tsid];
case SymbolType::exogenous: case SymbolType::exogenous:
if (tsid < 0 || tsid >= static_cast<int>(exo_ids.size())) if (tsid < 0 || tsid >= static_cast<int>(exo_ids.size()))
throw UnknownTypeSpecificIDException(tsid, type); throw UnknownTypeSpecificIDException {tsid, type, {}};
else else
return exo_ids[tsid]; return exo_ids[tsid];
case SymbolType::exogenousDet: case SymbolType::exogenousDet:
if (tsid < 0 || tsid >= static_cast<int>(exo_det_ids.size())) if (tsid < 0 || tsid >= static_cast<int>(exo_det_ids.size()))
throw UnknownTypeSpecificIDException(tsid, type); throw UnknownTypeSpecificIDException {tsid, type, {}};
else else
return exo_det_ids[tsid]; return exo_det_ids[tsid];
case SymbolType::parameter: case SymbolType::parameter:
if (tsid < 0 || tsid >= static_cast<int>(param_ids.size())) if (tsid < 0 || tsid >= static_cast<int>(param_ids.size()))
throw UnknownTypeSpecificIDException(tsid, type); throw UnknownTypeSpecificIDException {tsid, type, {}};
else else
return param_ids[tsid]; 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: default:
throw UnknownTypeSpecificIDException(tsid, type); throw UnknownTypeSpecificIDException {tsid, type, {}};
} }
} }
...@@ -199,11 +234,7 @@ SymbolTable::getPartitionsForType(SymbolType st) const noexcept(false) ...@@ -199,11 +234,7 @@ SymbolTable::getPartitionsForType(SymbolType st) const noexcept(false)
for (const auto& it : partition_value_map) for (const auto& it : partition_value_map)
if (getType(it.first) == st) if (getType(it.first) == st)
for (const auto& it1 : it.second) for (const auto& it1 : it.second)
{
if (partitions.find(it1.first) == partitions.end())
partitions[it1.first] = {};
partitions[it1.first][it.first] = it1.second; partitions[it1.first][it.first] = it1.second;
}
return partitions; return partitions;
} }
...@@ -220,18 +251,18 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -220,18 +251,18 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.exo_names_long = cell(" << exo_nbr() << ",1);" << endl; output << "M_.exo_names_long = cell(" << exo_nbr() << ",1);" << endl;
for (int id = 0; id < exo_nbr(); id++) for (int id = 0; id < exo_nbr(); id++)
output << "M_.exo_names(" << id + 1 << ") = {'" << getName(exo_ids[id]) << "'};" << endl 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_tex(" << id + 1 << ") = {'" << getTeXName(exo_ids[id]) << "'};"
<< "M_.exo_names_long(" << id+1 << ") = {'" << getLongName(exo_ids[id]) << "'};" << endl; << endl
map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::exogenous); << "M_.exo_names_long(" << id + 1 << ") = {'" << getLongName(exo_ids[id]) << "'};"
for (auto &partition : partitions) << endl;
for (auto& partition : getPartitionsForType(SymbolType::exogenous))
if (partition.first != "long_name") if (partition.first != "long_name")
{ {
output << "M_.exo_partitions." << partition.first << " = { "; output << "M_.exo_partitions." << partition.first << " = { ";
for (int id = 0; id < exo_nbr(); id++) for (int id = 0; id < exo_nbr(); id++)
{ {
output << "'"; output << "'";
if (auto it1 = partition.second.find(exo_ids[id]); if (auto it1 = partition.second.find(exo_ids[id]); it1 != partition.second.end())
it1 != partition.second.end())
output << it1->second; output << it1->second;
output << "' "; output << "' ";
} }
...@@ -255,12 +286,14 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -255,12 +286,14 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.exo_det_names_tex = cell(" << exo_det_nbr() << ",1);" << endl; output << "M_.exo_det_names_tex = cell(" << exo_det_nbr() << ",1);" << endl;
output << "M_.exo_det_names_long = 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++) for (int id = 0; id < exo_det_nbr(); id++)
output << "M_.exo_det_names(" << id+1 << ") = {'" << getName(exo_det_ids[id]) << "'};" << endl output << "M_.exo_det_names(" << id + 1 << ") = {'" << getName(exo_det_ids[id]) << "'};"
<< "M_.exo_det_names_tex(" << id+1 << ") = {'" << getTeXName(exo_det_ids[id]) << "'};" << endl << endl
<< "M_.exo_det_names_long(" << id+1 << ") = {'" << getLongName(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; output << "M_.exo_det_partitions = struct();" << endl;
map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::exogenousDet); for (auto& partition : getPartitionsForType(SymbolType::exogenousDet))
for (auto &partition : partitions)
if (partition.first != "long_name") if (partition.first != "long_name")
{ {
output << "M_.exo_det_partitions." << partition.first << " = { "; output << "M_.exo_det_partitions." << partition.first << " = { ";
...@@ -283,19 +316,19 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -283,19 +316,19 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.endo_names_long = cell(" << endo_nbr() << ",1);" << endl; output << "M_.endo_names_long = cell(" << endo_nbr() << ",1);" << endl;
for (int id = 0; id < endo_nbr(); id++) for (int id = 0; id < endo_nbr(); id++)
output << "M_.endo_names(" << id + 1 << ") = {'" << getName(endo_ids[id]) << "'};" << endl 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_tex(" << id + 1 << ") = {'" << getTeXName(endo_ids[id]) << "'};"
<< "M_.endo_names_long(" << id+1 << ") = {'" << getLongName(endo_ids[id]) << "'};" << endl; << endl
<< "M_.endo_names_long(" << id + 1 << ") = {'" << getLongName(endo_ids[id]) << "'};"
<< endl;
output << "M_.endo_partitions = struct();" << endl; output << "M_.endo_partitions = struct();" << endl;
map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::endogenous); for (auto& partition : getPartitionsForType(SymbolType::endogenous))
for (auto &partition : partitions)
if (partition.first != "long_name") if (partition.first != "long_name")
{ {
output << "M_.endo_partitions." << partition.first << " = { "; output << "M_.endo_partitions." << partition.first << " = { ";
for (int id = 0; id < endo_nbr(); id++) for (int id = 0; id < endo_nbr(); id++)
{ {
output << "'"; output << "'";
if (auto it1 = partition.second.find(endo_ids[id]); if (auto it1 = partition.second.find(endo_ids[id]); it1 != partition.second.end())
it1 != partition.second.end())
output << it1->second; output << it1->second;
output << "' "; output << "' ";
} }
...@@ -310,23 +343,24 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -310,23 +343,24 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
output << "M_.param_names_long = cell(" << param_nbr() << ",1);" << endl; output << "M_.param_names_long = cell(" << param_nbr() << ",1);" << endl;
for (int id = 0; id < param_nbr(); id++) for (int id = 0; id < param_nbr(); id++)
{ {
output << "M_.param_names(" << id+1 << ") = {'" << getName(param_ids[id]) << "'};" << endl output << "M_.param_names(" << id + 1 << ") = {'" << getName(param_ids[id]) << "'};"
<< "M_.param_names_tex(" << id+1 << ") = {'" << getTeXName(param_ids[id]) << "'};" << endl << endl
<< "M_.param_names_long(" << id+1 << ") = {'" << getLongName(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") if (getName(param_ids[id]) == "dsge_prior_weight")
output << "options_.dsge_var = 1;" << endl; output << "options_.dsge_var = 1;" << endl;
} }
output << "M_.param_partitions = struct();" << endl; output << "M_.param_partitions = struct();" << endl;
map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::parameter); for (auto& partition : getPartitionsForType(SymbolType::parameter))
for (auto &partition : partitions)
if (partition.first != "long_name") if (partition.first != "long_name")
{ {
output << "M_.param_partitions." << partition.first << " = { "; output << "M_.param_partitions." << partition.first << " = { ";
for (int id = 0; id < param_nbr(); id++) for (int id = 0; id < param_nbr(); id++)
{ {
output << "'"; output << "'";
if (auto it1 = partition.second.find(param_ids[id]); if (auto it1 = partition.second.find(param_ids[id]); it1 != partition.second.end())
it1 != partition.second.end())
output << it1->second; output << it1->second;
output << "' "; output << "' ";
} }
...@@ -352,44 +386,52 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -352,44 +386,52 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
else else
for (int i = 0; i < static_cast<int>(aux_vars.size()); i++) for (int i = 0; i < static_cast<int>(aux_vars.size()); i++)
{ {
output << "M_.aux_vars(" << i+1 << ").endo_index = " << getTypeSpecificID(aux_vars[i].get_symb_id())+1 << ";" << endl output << "M_.aux_vars(" << i + 1
<< "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].get_type_id() << ";" << endl; << ").endo_index = " << getTypeSpecificID(aux_vars[i].symb_id) + 1 << ";" << endl
switch (aux_vars[i].get_type()) << "M_.aux_vars(" << i + 1 << ").type = " << aux_vars[i].get_type_id() << ";"
<< endl;
switch (aux_vars[i].type)
{ {
case AuxVarType::endoLead: case AuxVarType::endoLead:
case AuxVarType::exoLead: case AuxVarType::exoLead:
case AuxVarType::expectation:
case AuxVarType::pacExpectation:
case AuxVarType::pacTargetNonstationary:
case AuxVarType::aggregationOp:
case AuxVarType::heterogeneousMultiplier:
break; break;
case AuxVarType::endoLag: case AuxVarType::endoLag:
case AuxVarType::exoLag: case AuxVarType::exoLag:
case AuxVarType::varModel: case AuxVarType::logTransform:
output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl case AuxVarType::diffLag:
<< "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; 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;
break; break;
case AuxVarType::unaryOp: case AuxVarType::unaryOp:
if (aux_vars[i].get_orig_symb_id() >= 0) output << "M_.aux_vars(" << i + 1 << ").unary_op = '" << aux_vars[i].unary_op << "';"
output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl << endl;
<< "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; [[fallthrough]];
output << "M_.aux_vars(" << i+1 << ").unary_op = '" << aux_vars[i].get_unary_op() << "';" << endl; 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;
break; break;
case AuxVarType::multiplier: case AuxVarType::multiplier:
output << "M_.aux_vars(" << i+1 << ").eq_nbr = " << aux_vars[i].get_equation_number_for_multiplier() + 1 << ";" << endl; output << "M_.aux_vars(" << i + 1
break; << ").eq_nbr = " << aux_vars[i].equation_number_for_multiplier + 1 << ";"
case AuxVarType::diffForward: << endl;
output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl;
break;
case AuxVarType::expectation:
break;
case AuxVarType::diff:
case AuxVarType::diffLag:
case AuxVarType::diffLead:
if (aux_vars[i].get_orig_symb_id() >= 0)
output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl
<< "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl;
break; break;
} }
if (expr_t orig_expr = aux_vars[i].get_expr_node(); if (expr_t orig_expr = aux_vars[i].expr_node; orig_expr)
orig_expr)
{ {
output << "M_.aux_vars(" << i + 1 << ").orig_expr = '"; output << "M_.aux_vars(" << i + 1 << ").orig_expr = '";
orig_expr->writeJsonOutput(output, {}, {}); orig_expr->writeJsonOutput(output, {}, {});
...@@ -407,10 +449,9 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -407,10 +449,9 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
if (observedVariablesNbr() > 0) if (observedVariablesNbr() > 0)
{ {
int ic = 1;
output << "options_.varobs = cell(" << observedVariablesNbr() << ", 1);" << endl; output << "options_.varobs = cell(" << observedVariablesNbr() << ", 1);" << endl;
for (auto it = varobs.begin(); it != varobs.end(); ++it, ic++) for (int ic {1}; int it : varobs)
output << "options_.varobs(" << ic << ") = {'" << getName(*it) << "'};" << endl; output << "options_.varobs(" << ic++ << ") = {'" << getName(it) << "'};" << endl;
output << "options_.varobs_id = [ "; output << "options_.varobs_id = [ ";
for (int varob : varobs) for (int varob : varobs)
...@@ -420,65 +461,107 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false) ...@@ -420,65 +461,107 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
if (observedExogenousVariablesNbr() > 0) if (observedExogenousVariablesNbr() > 0)
{ {
int ic = 1;
output << "options_.varexobs = cell(1);" << endl; output << "options_.varexobs = cell(1);" << endl;
for (auto it = varexobs.begin(); it != varexobs.end(); ++it, ic++) for (int ic {1}; int it : varexobs)
output << "options_.varexobs(" << ic << ") = {'" << getName(*it) << "'};" << endl; output << "options_.varexobs(" << ic++ << ") = {'" << getName(it) << "'};" << endl;
output << "options_.varexobs_id = [ "; output << "options_.varexobs_id = [ ";
for (int varexob : varexobs) for (int varexob : varexobs)
output << getTypeSpecificID(varexob) + 1 << " "; output << getTypeSpecificID(varexob) + 1 << " ";
output << " ];" << endl; 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 int
SymbolTable::addLeadAuxiliaryVarInternal(bool endo, int index, expr_t expr_arg) noexcept(false) SymbolTable::addLeadAuxiliaryVarInternal(bool endo, int index, expr_t expr_arg) noexcept(false)
{ {
ostringstream varname; string varname {(endo ? "AUX_ENDO_LEAD_" : "AUX_EXO_LEAD_") + to_string(index)};
if (endo)
varname << "AUX_ENDO_LEAD_";
else
varname << "AUX_EXO_LEAD_";
varname << index;
int symb_id; int symb_id;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); 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; return symb_id;
} }
int 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)
{ {
ostringstream varname; string varname {(endo ? "AUX_ENDO_LAG_" : "AUX_EXO_LAG_") + to_string(orig_symb_id) + "_"
if (endo) + to_string(-orig_lead_lag)};
varname << "AUX_ENDO_LAG_";
else
varname << "AUX_EXO_LAG_";
varname << orig_symb_id << "_" << -orig_lead_lag;
int symb_id; int symb_id;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); 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; return symb_id;
} }
...@@ -490,7 +573,8 @@ SymbolTable::addEndoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false) ...@@ -490,7 +573,8 @@ SymbolTable::addEndoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
} }
int 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); return addLagAuxiliaryVarInternal(true, orig_symb_id, orig_lead_lag, expr_arg);
} }
...@@ -502,27 +586,27 @@ SymbolTable::addExoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false) ...@@ -502,27 +586,27 @@ SymbolTable::addExoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
} }
int 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); return addLagAuxiliaryVarInternal(false, orig_symb_id, orig_lead_lag, expr_arg);
} }
int 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)
{ {
ostringstream varname; string varname {"AUX_EXPECT_"s + (information_set < 0 ? "LAG" : "LEAD") + "_"
+ to_string(abs(information_set)) + "_" + to_string(index)};
int symb_id; int symb_id;
varname << "AUX_EXPECT_" << (information_set < 0 ? "LAG" : "LEAD") << "_"
<< abs(information_set) << "_" << index;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
...@@ -532,20 +616,43 @@ SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, expr_t e ...@@ -532,20 +616,43 @@ SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, expr_t e
} }
int int
SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) noexcept(false) SymbolTable::addLogTransformAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{ {
ostringstream varname; string varname = "LOG_" + getName(orig_symb_id);
int symb_id; int symb_id;
try
{
symb_id = addSymbol(varname, SymbolType::endogenous);
}
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;
exit(EXIT_FAILURE);
}
varname << "AUX_DIFF_LAG_" << index; 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)
{
string varname {"AUX_DIFF_LAG_" + to_string(index)};
int symb_id;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
...@@ -555,20 +662,19 @@ SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id ...@@ -555,20 +662,19 @@ SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id
} }
int 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)
{ {
ostringstream varname; string varname {"AUX_DIFF_LEAD_" + to_string(index)};
int symb_id; int symb_id;
varname << "AUX_DIFF_LEAD_" << index;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
...@@ -578,20 +684,19 @@ SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_i ...@@ -578,20 +684,19 @@ SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_i
} }
int int
SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, 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)
{ {
ostringstream varname; string varname {"AUX_DIFF_" + to_string(index)};
int symb_id; int symb_id;
varname << "AUX_DIFF_" << index;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
...@@ -601,69 +706,63 @@ SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, i ...@@ -601,69 +706,63 @@ SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, i
} }
int int
SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg) noexcept(false) SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op,
{ const optional<int>& orig_symb_id,
return addDiffAuxiliaryVar(index, expr_arg, -1, 0); const optional<int>& orig_lag) noexcept(false)
}
int
SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op, int orig_symb_id, int orig_lag) noexcept(false)
{ {
ostringstream varname; string varname {"AUX_UOP_" + to_string(index)};
int symb_id; int symb_id;
varname << "AUX_UOP_" << index;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
aux_vars.emplace_back(symb_id, AuxVarType::unaryOp, orig_symb_id, 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; return symb_id;
} }
int int
SymbolTable::addVarModelEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false) SymbolTable::addHeterogeneousMultiplierAuxiliaryVar(int het_dim, int index,
const string& varname) noexcept(false)
{ {
int symb_id; int symb_id;
ostringstream varname;
varname << "AUX_VARMODEL_" << orig_symb_id << "_" << -orig_lead_lag;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::heterogeneousEndogenous, "", {}, het_dim);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
aux_vars.emplace_back(symb_id, AuxVarType::varModel, orig_symb_id, orig_lead_lag, 0, 0, expr_arg, ""); het_aux_vars[het_dim].emplace_back(symb_id, AuxVarType::heterogeneousMultiplier, 0, 0, index, 0,
nullptr, "");
return symb_id; return symb_id;
} }
int int
SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false) SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false)
{ {
ostringstream varname; string varname {"MULT_" + to_string(index + 1)};
int symb_id; int symb_id;
varname << "MULT_" << index+1;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(varname, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", 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); exit(EXIT_FAILURE);
} }
...@@ -672,86 +771,131 @@ SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false) ...@@ -672,86 +771,131 @@ SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false)
} }
int int
SymbolTable::addDiffForwardAuxiliaryVar(int orig_symb_id, expr_t expr_arg) noexcept(false) SymbolTable::addDiffForwardAuxiliaryVar(int orig_symb_id, int orig_lead_lag,
expr_t expr_arg) noexcept(false)
{ {
ostringstream varname; string varname {"AUX_DIFF_FWRD_" + to_string(orig_symb_id + 1)};
int symb_id; int symb_id;
varname << "AUX_DIFF_FWRD_" << orig_symb_id+1; try
{
symb_id = addSymbol(varname, SymbolType::endogenous);
}
catch (AlreadyDeclaredException& e)
{
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, "");
return symb_id;
}
int
SymbolTable::addPacExpectationAuxiliaryVar(const string& name, expr_t expr_arg)
{
int symb_id;
try try
{ {
symb_id = addSymbol(varname.str(), SymbolType::endogenous); symb_id = addSymbol(name, SymbolType::endogenous);
} }
catch (AlreadyDeclaredException& e) catch (AlreadyDeclaredException& e)
{ {
cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << 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); exit(EXIT_FAILURE);
} }
aux_vars.emplace_back(symb_id, AuxVarType::diffForward, orig_symb_id, 0, 0, 0, expr_arg, ""); aux_vars.emplace_back(symb_id, AuxVarType::pacExpectation, 0, 0, 0, 0, expr_arg, "");
return symb_id; return symb_id;
} }
int int
SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false) SymbolTable::addPacTargetNonstationaryAuxiliaryVar(const string& name, expr_t expr_arg)
{ {
for (const auto &aux_var : aux_vars) int symb_id;
if ((aux_var.get_type() == AuxVarType::endoLag || aux_var.get_type() == AuxVarType::exoLag) try
&& aux_var.get_orig_symb_id() == orig_symb_id && aux_var.get_orig_lead_lag() == orig_lead_lag) {
return aux_var.get_symb_id(); symb_id = addSymbol(name, SymbolType::endogenous);
throw SearchFailedException(orig_symb_id, orig_lead_lag); }
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;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, AuxVarType::pacTargetNonstationary, 0, 0, 0, 0, expr_arg, "");
return symb_id;
} }
int int
SymbolTable::getOrigSymbIdForAuxVar(int aux_var_symb_id) const noexcept(false) SymbolTable::addAggregationOpAuxiliaryVar(const string& name, expr_t expr_arg)
{ {
for (const auto &aux_var : aux_vars) int symb_id {[&] {
if ((aux_var.get_type() == AuxVarType::endoLag try
|| aux_var.get_type() == AuxVarType::exoLag {
|| aux_var.get_type() == AuxVarType::diff return addSymbol(name, SymbolType::endogenous);
|| aux_var.get_type() == AuxVarType::diffLag }
|| aux_var.get_type() == AuxVarType::diffLead) catch (AlreadyDeclaredException&)
&& aux_var.get_symb_id() == aux_var_symb_id) {
return aux_var.get_orig_symb_id(); cerr << "ERROR: the variable/parameter '" << name
throw UnknownSymbolIDException(aux_var_symb_id); << "' 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 int
SymbolTable::getOrigLeadLagForDiffAuxVar(int diff_aux_var_symb_id) const noexcept(false) SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false)
{ {
int lag = 0;
for (const auto& aux_var : aux_vars) for (const auto& aux_var : aux_vars)
if ((aux_var.get_type() == AuxVarType::diffLag || aux_var.get_type() == AuxVarType::diffLead) if ((aux_var.type == AuxVarType::endoLag || aux_var.type == AuxVarType::exoLag)
&& aux_var.get_symb_id() == diff_aux_var_symb_id) && aux_var.orig_symb_id == orig_symb_id && aux_var.orig_lead_lag == orig_lead_lag)
lag += 1 + getOrigLeadLagForDiffAuxVar(aux_var.get_orig_symb_id()); return aux_var.symb_id;
return lag; throw SearchFailedException {orig_symb_id, orig_lead_lag};
} }
int int
SymbolTable::getOrigSymbIdForDiffAuxVar(int diff_aux_var_symb_id) const noexcept(false) SymbolTable::getOrigSymbIdForAuxVar(int aux_var_symb_id_arg) const noexcept(false)
{ {
int orig_symb_id = -1;
for (const auto& aux_var : aux_vars) for (const auto& aux_var : aux_vars)
if (aux_var.get_symb_id() == diff_aux_var_symb_id) if ((aux_var.type == AuxVarType::endoLag || aux_var.type == AuxVarType::exoLag
if (aux_var.get_type() == AuxVarType::diff) || aux_var.type == AuxVarType::diff || aux_var.type == AuxVarType::diffLag
orig_symb_id = diff_aux_var_symb_id; || aux_var.type == AuxVarType::diffLead || aux_var.type == AuxVarType::diffForward
else if (aux_var.get_type() == AuxVarType::diffLag || aux_var.get_type() == AuxVarType::diffLead) || aux_var.type == AuxVarType::unaryOp)
orig_symb_id = getOrigSymbIdForDiffAuxVar(aux_var.get_orig_symb_id()); && aux_var.symb_id == aux_var_symb_id_arg)
return orig_symb_id; {
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};
} }
expr_t pair<int, int>
SymbolTable::getAuxiliaryVarsExprNode(int symb_id) const noexcept(false) SymbolTable::unrollDiffLeadLagChain(int symb_id, int lag) const noexcept(false)
// throw exception if it is a Lagrange multiplier
{ {
for (const auto& aux_var : aux_vars) for (const auto& aux_var : aux_vars)
if (aux_var.get_symb_id() == symb_id) if (aux_var.symb_id == symb_id)
if (expr_t expr_node = aux_var.get_expr_node(); if (aux_var.type == AuxVarType::diffLag || aux_var.type == AuxVarType::diffLead)
expr_node) {
return expr_node; auto [orig_symb_id, orig_lag] = unrollDiffLeadLagChain(aux_var.orig_symb_id.value(), lag);
else return {orig_symb_id, orig_lag + aux_var.orig_lead_lag.value()};
throw SearchFailedException(symb_id); }
throw SearchFailedException(symb_id); return {symb_id, lag};
} }
void void
...@@ -767,17 +911,30 @@ SymbolTable::markPredetermined(int symb_id) noexcept(false) ...@@ -767,17 +911,30 @@ SymbolTable::markPredetermined(int symb_id) noexcept(false)
predetermined_variables.insert(symb_id); predetermined_variables.insert(symb_id);
} }
void
SymbolTable::markWithLogTransform(int symb_id) noexcept(false)
{
validateSymbID(symb_id);
if (frozen)
throw FrozenException();
assert(getType(symb_id) == SymbolType::endogenous);
with_log_transform.insert(symb_id);
}
bool bool
SymbolTable::isPredetermined(int symb_id) const noexcept(false) SymbolTable::isPredetermined(int symb_id) const noexcept(false)
{ {
validateSymbID(symb_id); validateSymbID(symb_id);
return (predetermined_variables.find(symb_id) != predetermined_variables.end()); return predetermined_variables.contains(symb_id);
} }
int int
SymbolTable::predeterminedNbr() const SymbolTable::predeterminedNbr() const
{ {
return (predetermined_variables.size()); return predetermined_variables.size();
} }
void void
...@@ -797,13 +954,13 @@ SymbolTable::observedVariablesNbr() const ...@@ -797,13 +954,13 @@ SymbolTable::observedVariablesNbr() const
bool bool
SymbolTable::isObservedVariable(int symb_id) const 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 int
SymbolTable::getObservedVariableIndex(int symb_id) const 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()); assert(it != varobs.end());
return static_cast<int>(it - varobs.begin()); return static_cast<int>(it - varobs.begin());
} }
...@@ -812,7 +969,7 @@ void ...@@ -812,7 +969,7 @@ void
SymbolTable::addObservedExogenousVariable(int symb_id) noexcept(false) SymbolTable::addObservedExogenousVariable(int symb_id) noexcept(false)
{ {
validateSymbID(symb_id); validateSymbID(symb_id);
assert(getType(symb_id) != SymbolType::endogenous); assert(getType(symb_id) == SymbolType::exogenous);
varexobs.push_back(symb_id); varexobs.push_back(symb_id);
} }
...@@ -825,13 +982,13 @@ SymbolTable::observedExogenousVariablesNbr() const ...@@ -825,13 +982,13 @@ SymbolTable::observedExogenousVariablesNbr() const
bool bool
SymbolTable::isObservedExogenousVariable(int symb_id) const 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 int
SymbolTable::getObservedExogenousVariableIndex(int symb_id) const 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()); assert(it != varexobs.end());
return static_cast<int>(it - varexobs.begin()); return static_cast<int>(it - varexobs.begin());
} }
...@@ -880,31 +1037,17 @@ SymbolTable::getEndogenous() const ...@@ -880,31 +1037,17 @@ SymbolTable::getEndogenous() const
bool bool
SymbolTable::isAuxiliaryVariable(int symb_id) const SymbolTable::isAuxiliaryVariable(int symb_id) const
{ {
for (const auto &aux_var : aux_vars) return ranges::any_of(aux_vars, [=](const auto& av) { return av.symb_id == symb_id; });
if (aux_var.get_symb_id() == symb_id)
return true;
return false;
}
bool
SymbolTable::isAuxiliaryVariableButNotMultiplier(int symb_id) const
{
for (const auto &aux_var : aux_vars)
if (aux_var.get_symb_id() == symb_id && aux_var.get_type() != AuxVarType::multiplier)
return true;
return false;
} }
bool bool
SymbolTable::isDiffAuxiliaryVariable(int symb_id) const SymbolTable::isDiffAuxiliaryVariable(int symb_id) const
{ {
for (const auto &aux_var : aux_vars) return ranges::any_of(aux_vars, [=](const auto& av) {
if (aux_var.get_symb_id() == symb_id return av.symb_id == symb_id
&& (aux_var.get_type() == AuxVarType::diff && (av.type == AuxVarType::diff || av.type == AuxVarType::diffLag
|| aux_var.get_type() == AuxVarType::diffLag || av.type == AuxVarType::diffLead);
|| aux_var.get_type() == AuxVarType::diffLead)) });
return true;
return false;
} }
set<int> set<int>
...@@ -918,151 +1061,136 @@ SymbolTable::getOrigEndogenous() const ...@@ -918,151 +1061,136 @@ SymbolTable::getOrigEndogenous() const
} }
void void
SymbolTable::writeJuliaOutput(ostream &output) const noexcept(false) SymbolTable::writeJsonOutput(ostream& output) const
{ {
if (!frozen) output << R"("endogenous": )";
throw NotYetFrozenException(); writeJsonVarVector(output, endo_ids);
output << "# Endogenous Variables" << endl output << R"(, "exogenous":)";
<< "model_.endo = [" << endl; writeJsonVarVector(output, exo_ids);
if (endo_nbr() > 0)
for (int id = 0; id < endo_nbr(); id++)
output << R"( DynareModel.Endo(")"
<< getName(endo_ids[id]) << R"(", raw")"
<< getTeXName(endo_ids[id]) << R"(", ")"
<< getLongName(endo_ids[id]) << R"("))" << endl;
output << " ]" << endl;
output << "model_.endo_nbr = " << endo_nbr() << ";" << endl;
output << "# Exogenous Variables" << endl output << R"(, "exogenous_deterministic": )";
<< "model_.exo = [" << endl; writeJsonVarVector(output, exo_det_ids);
if (exo_nbr() > 0)
for (int id = 0; id < exo_nbr(); id++) output << R"(, "parameters": )";
output << R"( DynareModel.Exo(")" writeJsonVarVector(output, param_ids);
<< getName(exo_ids[id]) << R"(", raw")"
<< getTeXName(exo_ids[id]) << R"(", ")" if (observedVariablesNbr() > 0)
<< getLongName(exo_ids[id]) << R"("))" << endl; {
output << R"(, "varobs": [)";
for (size_t i = 0; i < varobs.size(); i++)
{
if (i != 0)
output << ", ";
output << R"(")" << getName(varobs[i]) << R"(")";
}
output << "]" << endl; output << "]" << endl;
output << "model_.exo_nbr = " << exo_nbr() << ";" << endl;
if (exo_det_nbr() > 0) output << R"(, "varobs_ids": [)";
for (size_t i = 0; i < varobs.size(); i++)
{ {
output << "# Exogenous Deterministic Variables" << endl if (i != 0)
<< "model_.exo_det = [" << endl; output << ", ";
if (exo_det_nbr() > 0) output << getTypeSpecificID(varobs[i]) + 1;
for (int id = 0; id < exo_det_nbr(); id++) }
output << R"( DynareModel.ExoDet(")"
<< getName(exo_det_ids[id]) << R"(", raw")"
<< getTeXName(exo_det_ids[id]) << R"(", ")"
<< getLongName(exo_det_ids[id]) << R"("))" << endl;
output << "]" << endl; output << "]" << endl;
output << "model_.exo_det_nbr = " << exo_det_nbr() << ";" << endl;
} }
output << "# Parameters" << endl if (observedExogenousVariablesNbr() > 0)
<< "model_.param = [" << endl; {
if (param_nbr() > 0) output << R"(, "varexobs": [)";
for (int id = 0; id < param_nbr(); id++) for (size_t i = 0; i < varexobs.size(); i++)
output << R"( DynareModel.Param(")" {
<< getName(param_ids[id]) << R"(", raw")" if (i != 0)
<< getTeXName(param_ids[id]) << R"(", ")" output << ", ";
<< getLongName(param_ids[id]) << R"("))" << endl; output << R"(")" << getName(varexobs[i]) << R"(")";
}
output << "]" << endl; output << "]" << endl;
output << "model_.param_nbr = " << param_nbr() << ";" << endl;
output << "model_.orig_endo_nbr = " << orig_endo_nbr() << endl; output << R"(, "varexobs_ids": [)";
for (size_t i = 0; i < varexobs.size(); i++)
if (aux_vars.size() > 0)
{ {
output << "# Auxiliary Variables" << endl if (i != 0)
<< "model_.aux_vars = [" << endl; output << ", ";
for (const auto &aux_var : aux_vars) output << getTypeSpecificID(varexobs[i]) + 1;
}
output << "]" << endl;
}
// Write the auxiliary variable table
output << R"(, "orig_endo_nbr": )" << orig_endo_nbr() << endl;
if (aux_vars.size() == 0)
output << R"(, "aux_vars": [])";
else
{
output << R"(, "aux_vars": [)" << endl;
for (int i = 0; i < static_cast<int>(aux_vars.size()); i++)
{ {
output << " DynareModel.AuxVars(" if (i != 0)
<< getTypeSpecificID(aux_var.get_symb_id()) + 1 << ", " output << ", ";
<< aux_var.get_type_id() << ", "; output << R"({"endo_index": )" << getTypeSpecificID(aux_vars[i].symb_id) + 1
switch (aux_var.get_type()) << R"(, "type": )" << aux_vars[i].get_type_id();
switch (aux_vars[i].type)
{ {
case AuxVarType::endoLead: case AuxVarType::endoLead:
case AuxVarType::exoLead: case AuxVarType::exoLead:
case AuxVarType::expectation:
case AuxVarType::pacExpectation:
case AuxVarType::pacTargetNonstationary:
case AuxVarType::aggregationOp:
case AuxVarType::heterogeneousMultiplier:
break;
case AuxVarType::endoLag: case AuxVarType::endoLag:
case AuxVarType::exoLag: case AuxVarType::exoLag:
case AuxVarType::varModel: case AuxVarType::logTransform:
output << getTypeSpecificID(aux_var.get_orig_symb_id()) + 1 << ", " case AuxVarType::diffLag:
<< aux_var.get_orig_lead_lag() << ", typemin(Int), string(), string()"; case AuxVarType::diffLead:
case AuxVarType::diffForward:
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; break;
case AuxVarType::unaryOp: case AuxVarType::unaryOp:
if (aux_var.get_orig_symb_id() >= 0) output << R"(, "unary_op": ")" << aux_vars[i].unary_op << R"(")";
output << getTypeSpecificID(aux_var.get_orig_symb_id()) + 1 << ", " << aux_var.get_orig_lead_lag(); [[fallthrough]];
else
output << "typemin(Int), typemin(Int)";
output << ", typemin(Int), string(), "
<< R"(")" << aux_var.get_unary_op() << R"(")" << endl;
break;
case AuxVarType::diff: case AuxVarType::diff:
case AuxVarType::diffLag: if (aux_vars[i].orig_symb_id)
case AuxVarType::diffLead: output << R"(, "orig_index": )" << getTypeSpecificID(*aux_vars[i].orig_symb_id) + 1
if (aux_var.get_orig_symb_id() >= 0) << R"(, "orig_lead_lag": )" << aux_vars[i].orig_lead_lag.value();
output << getTypeSpecificID(aux_var.get_orig_symb_id()) + 1 << ", "
<< aux_var.get_orig_lead_lag() << ", typemin(Int), string(), string()";
break; break;
case AuxVarType::multiplier: case AuxVarType::multiplier:
output << "typemin(Int), typemin(Int), " << aux_var.get_equation_number_for_multiplier() + 1 output << R"(, "eq_nbr": )" << aux_vars[i].equation_number_for_multiplier + 1;
<< ", string(), string()";
break;
case AuxVarType::diffForward:
output << getTypeSpecificID(aux_var.get_orig_symb_id())+1 << ", typemin(Int), typemin(Int), string(), string()";
break; break;
case AuxVarType::expectation:
output << R"(typemin(Int), typemin(Int), typemin(Int), "\mathbb{E}_{t)"
<< (aux_var.get_information_set() < 0 ? "" : "+")
<< aux_var.get_information_set() << "}(";
aux_var.get_expr_node()->writeOutput(output, ExprNodeOutputType::latexDynamicModel);
output << R"lit()")lit";
break;
default:
output << " typemin(Int), typemin(Int), typemin(Int), string(), string()";
}
output << ")" << endl;
}
output << "]" << endl;
} }
if (predeterminedNbr() > 0) if (expr_t orig_expr = aux_vars[i].expr_node; orig_expr)
{ {
output << "# Predetermined Variables" << endl output << R"(, "orig_expr": ")";
<< "model_.pred_vars = [ " << endl; orig_expr->writeJsonOutput(output, {}, {});
for (int predetermined_variable : predetermined_variables) output << R"(")";
output << " DynareModel.PredVars("
<< getTypeSpecificID(predetermined_variable)+1 << ")" << endl;
output << " ]" << endl;
} }
output << '}' << endl;
if (observedVariablesNbr() > 0)
{
output << "# Observed Variables" << endl
<< "options_.obs_vars = [" << endl;
for (int varob : varobs)
output << " DynareModel.ObsVars("
<< getTypeSpecificID(varob)+1 << ")" << endl;
output << " ]" << endl;
} }
output << "]" << endl;
} }
void if (!heterogeneity_table.empty())
SymbolTable::writeJsonOutput(ostream &output) const
{ {
output << R"("endogenous": )"; output << R"(, "heterogeneous_symbols": [)";
writeJsonVarVector(output, endo_ids); 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": )"; output << R"(, "exogenous": )";
writeJsonVarVector(output, exo_ids); writeJsonVarVector(output, het_exo_ids.at(i));
output << R"(, "exogenous_deterministic": )";
writeJsonVarVector(output, exo_det_ids);
output << R"(, "parameters": )"; output << R"(, "parameters": )";
writeJsonVarVector(output, param_ids); writeJsonVarVector(output, het_param_ids.at(i));
output << "}";
}
output << "]" << endl;
}
} }
void void
...@@ -1075,9 +1203,10 @@ SymbolTable::writeJsonVarVector(ostream &output, const vector<int> &varvec) cons ...@@ -1075,9 +1203,10 @@ SymbolTable::writeJsonVarVector(ostream &output, const vector<int> &varvec) cons
output << ", "; output << ", ";
output << "{" output << "{"
<< R"("name":")" << getName(varvec[i]) << R"(", )" << R"("name":")" << getName(varvec[i]) << R"(", )"
<< R"("texName":")" << boost::replace_all_copy(getTeXName(varvec[i]), R"(\)", R"(\\)") << R"(", )" << R"("texName":")" << boost::replace_all_copy(getTeXName(varvec[i]), R"(\)", R"(\\)")
<< R"("longName":")" << boost::replace_all_copy(getLongName(varvec[i]), R"(\)", R"(\\)") << R"("})" << R"(", )"
<< endl; << R"("longName":")"
<< boost::replace_all_copy(getLongName(varvec[i]), R"(\)", R"(\\)") << R"("})" << endl;
} }
output << "]" << endl; output << "]" << endl;
} }
...@@ -1096,3 +1225,39 @@ SymbolTable::getUltimateOrigSymbID(int symb_id) const ...@@ -1096,3 +1225,39 @@ SymbolTable::getUltimateOrigSymbID(int symb_id) const
} }
return symb_id; return symb_id;
} }
optional<int>
SymbolTable::getEquationNumberForMultiplier(int symb_id) const
{
for (const auto& aux_var : aux_vars)
if (aux_var.symb_id == symb_id && aux_var.type == AuxVarType::multiplier)
return aux_var.equation_number_for_multiplier;
return nullopt;
}
const set<int>&
SymbolTable::getVariablesWithLogTransform() const
{
return with_log_transform;
}
set<int>
SymbolTable::getLagrangeMultipliers() const
{
set<int> r;
for (const auto& aux_var : aux_vars)
if (aux_var.type == AuxVarType::multiplier)
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-2019 Dynare Team * Copyright © 2003-2024 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,25 +14,25 @@ ...@@ -14,25 +14,25 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _SYMBOLTABLE_HH #ifndef SYMBOL_TABLE_HH
#define _SYMBOLTABLE_HH #define SYMBOL_TABLE_HH
using namespace std;
#include <map> #include <map>
#include <optional>
#include <ostream>
#include <set>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <set>
#include <ostream>
#include "CodeInterpreter.hh" #include "CommonEnums.hh"
#include "ExprNode.hh" #include "ExprNode.hh"
#include "HeterogeneityTable.hh"
using expr_t = class ExprNode *; using namespace std;
//! Types of auxiliary variables //! Types of auxiliary variables
enum class AuxVarType enum class AuxVarType
...@@ -42,79 +42,65 @@ enum class AuxVarType ...@@ -42,79 +42,65 @@ enum class AuxVarType
exoLead = 2, //!< Substitute for exo leads >= 1 exoLead = 2, //!< Substitute for exo leads >= 1
exoLag = 3, //!< Substitute for exo lags >= 1 exoLag = 3, //!< Substitute for exo lags >= 1
expectation = 4, //!< Substitute for Expectation Operator expectation = 4, //!< Substitute for Expectation Operator
diffForward = 5, //!< Substitute for the differentiate of a forward variable diffForward = 5, /* Substitute for the differentiate of a forward variable,
for the differentiate_forward_vars option.
N.B.: nothing to do with the diff() operator! */
multiplier = 6, //!< Multipliers for FOC of Ramsey Problem multiplier = 6, //!< Multipliers for FOC of Ramsey Problem
varModel = 7, //!< Variable for var_model with order > abs(min_lag()) present in model logTransform = 7, //!< Log-transformation of a variable declared with “var(log)”
diff = 8, //!< Variable for Diff operator diff = 8, //!< Variable for Diff operator
diffLag = 9, //!< Variable for timing between Diff operators 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
diffLead = 11 //!< Variable for timing between Diff operators //!< 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
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 //! Information on some auxiliary variables
class AuxVarInfo struct AuxVarInfo
{ {
private: const int symb_id; // Symbol ID of the auxiliary variable
int symb_id; //!< Symbol ID of the auxiliary variable const AuxVarType type; // Its type
AuxVarType type; //!< Its type const optional<int> orig_symb_id; /* Symbol ID of the (only) endo that appears on the RHS of
int orig_symb_id; //!< Symbol ID of the endo of the original model represented by this aux var. Only used for avEndoLag and avExoLag. the definition of this auxvar.
int orig_lead_lag; //!< Lead/lag of the endo of the original model represented by this aux var. Only used for avEndoLag and avExoLag. Used by endoLag, exoLag, diffForward, logTransform, diff,
int equation_number_for_multiplier; //!< Stores the original constraint equation number associated with this aux var. Only used for avMultiplier. diffLag, diffLead and unaryOp.
int information_set; //! Argument of expectation operator. Only used for avExpectation. For diff and unaryOp, if the argument expression is more
expr_t expr_node; //! Auxiliary variable definition complex than than a simple variable, this value is unset
string unary_op; //! Used with AuxUnaryOp (hence the need for std::optional). */
public: const optional<int> orig_lead_lag; /* Lead/lag of the (only) endo as it appears on the RHS of the
AuxVarInfo(int symb_id_arg, AuxVarType type_arg, int orig_symb_id, int orig_lead_lag, int equation_number_for_multiplier_arg, int information_set_arg, expr_t expr_node_arg, string unary_op_arg); definition of this auxvar. Only set if orig_symb_id is set
int (in particular, for diff and unaryOp, unset
get_symb_id() const if orig_symb_id is unset).
{ For diff and diffForward, since the definition of the
return symb_id; auxvar is a time difference, the value corresponds to the
}; time index of the first term of that difference. */
AuxVarType const int equation_number_for_multiplier; /* Stores the original constraint equation number
get_type() const associated with this aux var. Only used for
{ avMultiplier. */
return type; const int information_set; // Argument of expectation operator. Only used for avExpectation.
}; const expr_t expr_node; // Auxiliary variable definition
int const string unary_op; // Used with AuxUnaryOp
[[nodiscard]] int
get_type_id() const get_type_id() const
{ {
return static_cast<int>(type); return static_cast<int>(type);
} }
int
get_orig_symb_id() const
{
return orig_symb_id;
};
int
get_orig_lead_lag() const
{
return orig_lead_lag;
};
int
get_equation_number_for_multiplier() const
{
return equation_number_for_multiplier;
};
int
get_information_set() const
{
return information_set;
};
expr_t
get_expr_node() const
{
return expr_node;
};
string
get_unary_op() const
{
return unary_op;
};
}; };
//! Stores the symbol table //! Stores the symbol table
/*! /*!
A symbol is given by its name, and is internally represented by a unique integer. A symbol is given by its name, and is internally represented by a unique
integer, called a symbol ID.
There is a guarantee that symbol IDs are increasing, i.e. if symbol A is
added after symbol B, then the ID of A is greater than the ID of B.
When method freeze() is called, computes a distinct sequence of IDs for some types When method freeze() is called, computes a distinct sequence of IDs for some types
(endogenous, exogenous, parameters), which are used by the Matlab/Octave functions. (endogenous, exogenous, parameters), which are used by the Matlab/Octave functions.
...@@ -125,6 +111,8 @@ public: ...@@ -125,6 +111,8 @@ public:
class SymbolTable class SymbolTable
{ {
private: private:
HeterogeneityTable& heterogeneity_table;
//! Has method freeze() been called? //! Has method freeze() been called?
bool frozen {false}; bool frozen {false};
...@@ -142,9 +130,11 @@ private: ...@@ -142,9 +130,11 @@ private:
map<int, map<string, string>> partition_value_map; map<int, map<string, string>> partition_value_map;
//! Maps IDs to types //! Maps IDs to types
vector<SymbolType> type_table; 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 //! Maps symbol IDs to type specific IDs
vector<int> type_specific_ids; map<int, int> type_specific_ids;
//! Maps type specific IDs of endogenous to symbol IDs //! Maps type specific IDs of endogenous to symbol IDs
vector<int> endo_ids; vector<int> endo_ids;
...@@ -154,9 +144,22 @@ private: ...@@ -154,9 +144,22 @@ private:
vector<int> exo_det_ids; vector<int> exo_det_ids;
//! Maps type specific IDs of parameters to symbol IDs //! Maps type specific IDs of parameters to symbol IDs
vector<int> param_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 //! Information about auxiliary variables
vector<AuxVarInfo> aux_vars; vector<AuxVarInfo> aux_vars;
//! Information about heterogeneous auxiliary variables
vector<vector<AuxVarInfo>> het_aux_vars;
//! Stores the predetermined variables (by symbol IDs) //! Stores the predetermined variables (by symbol IDs)
set<int> predetermined_variables; set<int> predetermined_variables;
...@@ -166,48 +169,42 @@ private: ...@@ -166,48 +169,42 @@ private:
//! Stores the list of observed exogenous variables //! Stores the list of observed exogenous variables
vector<int> varexobs; vector<int> varexobs;
//! Stores the endogenous variables declared with “var(log)”
set<int> with_log_transform;
public: public:
//! Thrown when trying to access an unknown symbol (by name) //! Thrown when trying to access an unknown symbol (by name)
class UnknownSymbolNameException struct UnknownSymbolNameException
{ {
public:
//! Symbol name //! Symbol name
string name; const string name;
explicit UnknownSymbolNameException(string name_arg) : name{move(name_arg)}
{
}
}; };
//! Thrown when trying to access an unknown symbol (by id) //! Thrown when trying to access an unknown symbol (by id)
class UnknownSymbolIDException struct UnknownSymbolIDException
{ {
public:
//! Symbol ID //! Symbol ID
int id; const int id;
explicit UnknownSymbolIDException(int id_arg) : id{id_arg}
{
}
}; };
//! Thrown when trying to access an unknown type specific ID //! Thrown when trying to access an unknown type specific ID
class UnknownTypeSpecificIDException struct UnknownTypeSpecificIDException
{ {
public: const int tsid;
int tsid; const SymbolType type;
SymbolType type; const optional<int> heterogeneity_dimension;
UnknownTypeSpecificIDException(int tsid_arg, SymbolType type_arg) : tsid{tsid_arg}, type{type_arg} };
/* Thrown when requesting the type specific ID of a symbol which doesn’t
have one */
struct NoTypeSpecificIDException
{ {
} const int symb_id;
}; };
//! Thrown when trying to declare a symbol twice //! Thrown when trying to declare a symbol twice
class AlreadyDeclaredException struct AlreadyDeclaredException
{ {
public:
//! Symbol name //! Symbol name
string name; const string name;
//! Was the previous declaration done with the same symbol type ? //! Was the previous declaration done with the same symbol type ?
bool same_type; const bool same_type;
AlreadyDeclaredException(string name_arg, bool same_type_arg) : name{move(name_arg)}, same_type{same_type_arg}
{
}
}; };
//! Thrown when table is frozen and trying to modify it //! Thrown when table is frozen and trying to modify it
class FrozenException class FrozenException
...@@ -221,30 +218,44 @@ public: ...@@ -221,30 +218,44 @@ public:
class SearchFailedException class SearchFailedException
{ {
public: public:
int orig_symb_id, orig_lead_lag, symb_id; 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}, SearchFailedException(int orig_symb_id_arg, int orig_lead_lag_arg) :
orig_lead_lag{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: private:
//! Factorized code for adding aux lag variables //! 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 //! Factorized code for adding aux lead variables
int addLeadAuxiliaryVarInternal(bool endo, int index, expr_t arg) noexcept(false); int addLeadAuxiliaryVarInternal(bool endo, int index, expr_t arg) noexcept(false);
//! Factorized code for Json writing //! Factorized code for Json writing
void writeJsonVarVector(ostream& output, const vector<int>& varvec) const; void writeJsonVarVector(ostream& output, const vector<int>& varvec) const;
//! Factorized code for asserting that 0 <= symb_id <= symbol_table.size() //! Factorized code for asserting that 0 <= symb_id <= symbol_table.size()
inline void validateSymbID(int symb_id) const noexcept(false); inline void validateSymbID(int symb_id) const noexcept(false);
public: public:
SymbolTable(HeterogeneityTable& heterogeneity_table_arg) :
heterogeneity_table {heterogeneity_table_arg}
{
}
//! Add a symbol //! Add a symbol
/*! Returns the symbol ID */ /* Returns the symbol ID.
int addSymbol(const string &name, SymbolType type, const string &tex_name, const vector<pair<string, string>> &partition_value) noexcept(false); heterogeneity_dimension must be defined if this is a heterogeneous symbol (otherwise it is
//! Add a symbol without its TeX name (will be equal to its name) 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 */ /*! Returns the symbol ID */
int addSymbol(const string& name, SymbolType type) noexcept(false); int addSymbol(const string& name, SymbolType type) noexcept(false);
//! Adds an auxiliary variable for endogenous with lead >= 2 //! Adds an auxiliary variable for endogenous with lead >= 2
...@@ -254,9 +265,9 @@ public: ...@@ -254,9 +265,9 @@ public:
int addEndoLeadAuxiliaryVar(int index, expr_t arg) noexcept(false); int addEndoLeadAuxiliaryVar(int index, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for endogenous with lag >= 2 //! 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_symb_id symbol ID of the endogenous declared by the user that this new variable
\param[in] orig_lead_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lead_lag) will represent \param[in] orig_lead_lag lag value such that this new variable will be equivalent
\return the symbol ID of the new symbol */ 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); int addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for endogenous with lead >= 1 //! Adds an auxiliary variable for endogenous with lead >= 1
/*! /*!
...@@ -265,9 +276,9 @@ public: ...@@ -265,9 +276,9 @@ public:
int addExoLeadAuxiliaryVar(int index, expr_t arg) noexcept(false); int addExoLeadAuxiliaryVar(int index, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for exogenous with lag >= 1 //! 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_symb_id symbol ID of the exogenous declared by the user that this new variable
\param[in] orig_lead_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lead_lag) will represent \param[in] orig_lead_lag lag value such that this new variable will be equivalent
\return the symbol ID of the new symbol */ 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); int addExoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t arg) noexcept(false);
//! Adds an auxiliary variable for the expectation operator //! Adds an auxiliary variable for the expectation operator
/*! /*!
...@@ -276,71 +287,111 @@ public: ...@@ -276,71 +287,111 @@ public:
\return the symbol ID of the new symbol \return the symbol ID of the new symbol
*/ */
int addExpectationAuxiliaryVar(int information_set, int index, expr_t arg) noexcept(false); 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 //! Adds an auxiliary variable for the multiplier for the FOCs of the Ramsey Problem
/*! /*!
\param[in] index Used to construct the variable name \param[in] index Used to construct the variable name
\return the symbol ID of the new symbol \return the symbol ID of the new symbol
*/ */
int addMultiplierAuxiliaryVar(int index) noexcept(false); int addMultiplierAuxiliaryVar(int index) noexcept(false);
/* Adds an auxiliary variable associated to an endogenous declared with
“var(log)”.
– orig_symb_id is the symbol ID of the original variable
– 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);
//! Adds an auxiliary variable for the (time) differentiate of a forward var //! Adds an auxiliary variable for the (time) differentiate of a forward var
/*! /*!
\param[in] orig_symb_id The symb_id of the forward variable \param[in] orig_symb_id The symb_id of the forward variable
\return the symbol ID of the new symbol \return the symbol ID of the new symbol
*/ */
int addDiffForwardAuxiliaryVar(int orig_symb_id, expr_t arg) noexcept(false); int addDiffForwardAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t arg) noexcept(false);
//! Searches auxiliary variables which are substitutes for a given symbol_id and lead/lag //! Searches auxiliary variables which are substitutes for a given symbol_id and lead/lag
/*! /*!
The search is only performed among auxiliary variables of endo/exo lag. The search is only performed among auxiliary variables of endo/exo lag.
\return the symbol ID of the auxiliary variable \return the symbol ID of the auxiliary variable
Throws an exception if match not found. 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);
//! Serches aux_vars for the aux var represented by aux_var_symb_id and returns its associated orig_symb_id /* Searches aux_vars for the aux var represented by aux_var_symb_id and
int getOrigSymbIdForAuxVar(int aux_var_symb_id) const noexcept(false); returns its associated orig_symb_id.
//! Searches for diff aux var and finds the original lag associated with this variable Throws an UnknownSymbolIDException if there is no orig_symb_id associated to
int getOrigLeadLagForDiffAuxVar(int diff_aux_var_symb_id) const noexcept(false); this auxvar (either because it’s of the wrong type, or because there is
//! Searches for diff aux var and finds the symb id associated with this variable no such orig var for this specific auxvar, in case of complex expressions
int getOrigSymbIdForDiffAuxVar(int diff_aux_var_symb_id) const noexcept(false); in diff or unaryOp). */
//! Adds an auxiliary variable when var_model is used with an order that is greater in absolute value [[nodiscard]] int getOrigSymbIdForAuxVar(int aux_var_symb_id_arg) const noexcept(false);
//! than the largest lag present in the model. /* Unrolls a chain of diffLag or diffLead aux vars until it founds a (regular) diff aux
int addVarModelEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false); var. In other words:
- if the arg is a (regu) diff aux var, returns the arg
- if the arg is a diffLag/diffLead, get its orig symb ID, and call the
method recursively
- if the arg is something else, throw an UnknownSymbolIDException
exception
The 2nd input/output arguments are used to track leads/lags. The 2nd
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). */
[[nodiscard]] pair<int, int> unrollDiffLeadLagChain(int symb_id, int lag) const noexcept(false);
//! Adds an auxiliary variable when the diff operator is encountered //! Adds an auxiliary variable when the diff operator is encountered
int addDiffAuxiliaryVar(int index, expr_t expr_arg) noexcept(false); int addDiffAuxiliaryVar(int index, expr_t expr_arg, const optional<int>& orig_symb_id = nullopt,
int addDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) noexcept(false); const optional<int>& orig_lag = nullopt) noexcept(false);
//! Takes care of timing between diff statements //! 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 //! 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 //! An Auxiliary variable for a unary op
int addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op, int orig_symb_id = -1, int orig_lag = 0) 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 //! Returns the number of auxiliary variables
int [[nodiscard]] int
AuxVarsSize() const AuxVarsSize() const
{ {
return aux_vars.size(); return aux_vars.size();
}; }
//! Retruns expr_node for an auxiliary variable
expr_t getAuxiliaryVarsExprNode(int symb_id) const noexcept(false);
//! Tests if symbol already exists //! 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) //! 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 //! Get TeX name
inline string getTeXName(int id) const noexcept(false); [[nodiscard]] inline string getTeXName(int id) const noexcept(false);
//! Get long name //! Get long name
inline string getLongName(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 //! Returns true if the partition name is the first encountered for the type of variable
bool isFirstOfPartitionForType(int id) const noexcept(false); //! represented by id
[[nodiscard]] bool isFirstOfPartitionForType(int id) const noexcept(false);
//! Returns a list of partitions and symbols that belong to that partition //! 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) //! 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) //! 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) //! 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) //! 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 //! Freeze symbol table
void freeze() noexcept(false); void freeze() noexcept(false);
//! unreeze symbol table //! unreeze symbol table
...@@ -349,82 +400,111 @@ public: ...@@ -349,82 +400,111 @@ public:
//! Change the type of a symbol //! Change the type of a symbol
void changeType(int id, SymbolType newtype) noexcept(false); void changeType(int id, SymbolType newtype) noexcept(false);
//! Get type specific ID (by symbol ID) //! 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) //! 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 //! 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 //! 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 //! 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 //! 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) //! 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) //! 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 //! Write output of this class
void writeOutput(ostream& output) const noexcept(false); void writeOutput(ostream& output) const noexcept(false);
//! Write JSON Output //! Write JSON Output
void writeJsonOutput(ostream& output) const; void writeJsonOutput(ostream& output) const;
//! Write Julia output of this class
void writeJuliaOutput(ostream &output) const noexcept(false);
//! Mark a symbol as predetermined variable //! Mark a symbol as predetermined variable
void markPredetermined(int symb_id) noexcept(false); void markPredetermined(int symb_id) noexcept(false);
//! 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 //! 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 //! Return the number of predetermined variables
int predeterminedNbr() const; [[nodiscard]] int predeterminedNbr() const;
//! Add an observed variable //! Add an observed variable
void addObservedVariable(int symb_id) noexcept(false); void addObservedVariable(int symb_id) noexcept(false);
//! Return the number of observed variables //! Return the number of observed variables
int observedVariablesNbr() const; [[nodiscard]] int observedVariablesNbr() const;
//! Is a given symbol in the set of observed variables //! 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 //! 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 //! Add an observed exogenous variable
void addObservedExogenousVariable(int symb_id) noexcept(false); void addObservedExogenousVariable(int symb_id) noexcept(false);
//! Return the number of observed exogenous variables //! 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 //! Is a given symbol in the set of observed exogenous variables
bool isObservedExogenousVariable(int symb_id) const; [[nodiscard]] bool isObservedExogenousVariable(int symb_id) const;
//! Return the index of a given observed exogenous variable in the vector of all observed variables //! Return the index of a given observed exogenous variable in the vector of all observed
int getObservedExogenousVariableIndex(int symb_id) const; //! variables
vector <int> getTrendVarIds() const; [[nodiscard]] int getObservedExogenousVariableIndex(int symb_id) const;
[[nodiscard]] vector<int> getTrendVarIds() const;
//! Get list of exogenous variables //! Get list of exogenous variables
set <int> getExogenous() const; [[nodiscard]] set<int> getExogenous() const;
//! Get list of exogenous variables //! Get list of exogenous variables
set <int> getObservedExogenous() const; [[nodiscard]] set<int> getObservedExogenous() const;
//! Get list of endogenous variables //! Get list of endogenous variables
set <int> getEndogenous() const; [[nodiscard]] set<int> getEndogenous() const;
//! Is a given symbol an auxiliary variable //! Is a given symbol an auxiliary variable
bool isAuxiliaryVariable(int symb_id) const; [[nodiscard]] bool isAuxiliaryVariable(int symb_id) const;
//! Is a given symbol an auxiliary variable but not a Lagrange multiplier
bool isAuxiliaryVariableButNotMultiplier(int symb_id) const;
//! Is a given symbol a diff, diff lead, or diff lag auxiliary variable //! 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 //! 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 //! Returns the original symbol corresponding to this variable
/* If symb_id is not an auxiliary var, returns symb_id. Otherwise, /* If symb_id has no original variable, returns symb_id. Otherwise,
repeatedly call getOrigSymbIDForAuxVar() until an original repeatedly call getOrigSymbIDForAuxVar() until an original variable is
(non-auxiliary) variable is found. */ found. Note that the result may be an auxiliary variable if the latter has
int getUltimateOrigSymbID(int symb_id) const; no original variable (e.g. aux var for lead, Lagrange Multiplier or diff
associated to a complex expression). */
[[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 */
[[nodiscard]] const AuxVarInfo& getAuxVarInfo(int symb_id) const;
// Returns the set of all endogenous declared with “var(log)”
[[nodiscard]] const set<int>& getVariablesWithLogTransform() const;
// Returns all Lagrange multipliers
[[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 inline void
SymbolTable::validateSymbID(int symb_id) const noexcept(false) SymbolTable::validateSymbID(int symb_id) const noexcept(false)
{ {
if (symb_id < 0 || symb_id > static_cast<int>(symbol_table.size())) if (symb_id < 0 || symb_id > static_cast<int>(symbol_table.size()))
throw UnknownSymbolIDException(symb_id); throw UnknownSymbolIDException {symb_id};
}
inline void
SymbolTable::resizeHetAuxVars()
{
het_aux_vars.resize(heterogeneity_table.size());
} }
inline bool inline bool
SymbolTable::exists(const string& name) const SymbolTable::exists(const string& name) const
{ {
return symbol_table.find(name) != symbol_table.end(); return symbol_table.contains(name);
} }
inline string inline string
...@@ -464,11 +544,10 @@ SymbolTable::getType(const string &name) const noexcept(false) ...@@ -464,11 +544,10 @@ SymbolTable::getType(const string &name) const noexcept(false)
inline int inline int
SymbolTable::getID(const string& name) const noexcept(false) SymbolTable::getID(const string& name) const noexcept(false)
{ {
if (auto iter = symbol_table.find(name); if (auto iter = symbol_table.find(name); iter != symbol_table.end())
iter != symbol_table.end())
return iter->second; return iter->second;
else else
throw UnknownSymbolNameException(name); throw UnknownSymbolNameException {name};
} }
inline int inline int
...@@ -479,7 +558,10 @@ SymbolTable::getTypeSpecificID(int id) const noexcept(false) ...@@ -479,7 +558,10 @@ SymbolTable::getTypeSpecificID(int id) const noexcept(false)
validateSymbID(id); validateSymbID(id);
return type_specific_ids[id]; if (auto it = type_specific_ids.find(id); it != type_specific_ids.end())
return it->second;
else
throw NoTypeSpecificIDException {id};
} }
inline int inline int
...@@ -525,7 +607,43 @@ SymbolTable::param_nbr() const noexcept(false) ...@@ -525,7 +607,43 @@ SymbolTable::param_nbr() const noexcept(false)
} }
inline int 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; return symbol_table.size() - 1;
} }
...@@ -536,4 +654,13 @@ SymbolTable::orig_endo_nbr() const noexcept(false) ...@@ -536,4 +654,13 @@ SymbolTable::orig_endo_nbr() const noexcept(false)
return endo_nbr() - aux_vars.size(); return endo_nbr() - aux_vars.size();
} }
inline const AuxVarInfo&
SymbolTable::getAuxVarInfo(int symb_id) const
{
for (const auto& aux_var : aux_vars)
if (aux_var.symb_id == symb_id)
return aux_var;
throw UnknownSymbolIDException {symb_id};
}
#endif #endif
/*
* Copyright © 2009-2020 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <iostream>
#include "VariableDependencyGraph.hh"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#include <boost/graph/strong_components.hpp>
#include <boost/graph/topological_sort.hpp>
#pragma GCC diagnostic pop
#include <ranges>
using namespace boost;
VariableDependencyGraph::VariableDependencyGraph(int n) : base(n)
{
/* It is necessary to manually initialize the vertex_index property since
this graph uses listS and not vecS as underlying vertex container */
auto v_index = get(vertex_index, *this);
for (int i = 0; i < n; i++)
put(v_index, vertex(i, *this), i);
}
void
VariableDependencyGraph::suppress(vertex_descriptor vertex_to_eliminate)
{
clear_vertex(vertex_to_eliminate, *this);
remove_vertex(vertex_to_eliminate, *this);
}
void
VariableDependencyGraph::suppress(int vertex_num)
{
suppress(vertex(vertex_num, *this));
}
void
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)
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
{
auto v_index = get(vertex_index, *this);
color[u] = gray_color;
for (auto [vi, vi_end] = out_edges(u, *this); vi != vi_end; ++vi)
if (color[target(*vi, *this)] == white_color
&& hasCycleDFS(target(*vi, *this), color, circuit_stack))
{
// cycle detected, return immediately
circuit_stack.push_back(v_index[target(*vi, *this)]);
return true;
}
else if (color[target(*vi, *this)] == gray_color)
{
// *vi is an ancestor!
circuit_stack.push_back(v_index[target(*vi, *this)]);
return true;
}
color[u] = black_color;
return false;
}
bool
VariableDependencyGraph::hasCycle() const
{
// Initialize color map to white
color_t color;
vector<int> circuit_stack;
for (auto [vi, vi_end] = vertices(*this); vi != vi_end; ++vi)
color[*vi] = white_color;
// Perform depth-first search
for (auto [vi, vi_end] = vertices(*this); vi != vi_end; ++vi)
if (color[*vi] == white_color && hasCycleDFS(*vi, color, circuit_stack))
return true;
return false;
}
void
VariableDependencyGraph::print() const
{
auto v_index = get(vertex_index, *this);
cout << "Graph\n"
<< "-----\n";
for (auto [it, it_end] = vertices(*this); it != it_end; ++it)
{
cout << "vertex[" << v_index[*it] + 1 << "] <-";
for (auto [it_in, in_end] = in_edges(*it, *this); it_in != in_end; ++it_in)
cout << v_index[source(*it_in, *this)] + 1 << " ";
cout << "\n ->";
for (auto [it_out, out_end] = out_edges(*it, *this); it_out != out_end; ++it_out)
cout << v_index[target(*it_out, *this)] + 1 << " ";
cout << "\n";
}
}
VariableDependencyGraph
VariableDependencyGraph::extractSubgraph(const vector<int>& select_index) const
{
int n = select_index.size();
VariableDependencyGraph G(n);
auto v_index = get(vertex_index, *this);
auto v_index1_G = get(vertex_index1, G); // Maps new vertices to original indices
map<int, int> reverse_index; // Maps orig indices to new ones
for (int i = 0; i < n; i++)
{
reverse_index[select_index[i]] = i;
v_index1_G[vertex(i, G)] = select_index[i];
}
for (int i = 0; i < n; i++)
{
auto vi = vertex(select_index[i], *this);
for (auto [it_out, out_end] = out_edges(vi, *this); it_out != out_end; ++it_out)
if (auto it = reverse_index.find(v_index[target(*it_out, *this)]);
it != reverse_index.end())
add_edge(vertex(i, G), vertex(it->second, G), G);
}
return G;
}
bool
VariableDependencyGraph::vertexBelongsToAClique(vertex_descriptor vertex) const
{
vector<vertex_descriptor> liste;
bool agree = true;
auto [it_in, in_end] = in_edges(vertex, *this);
auto [it_out, out_end] = out_edges(vertex, *this);
while (it_in != in_end && it_out != out_end && agree)
{
agree = (source(*it_in, *this) == target(*it_out, *this)
&& source(*it_in, *this) != target(*it_in, *this)); // not a loop
liste.push_back(source(*it_in, *this));
++it_in;
++it_out;
}
if (agree)
{
if (it_in != in_end || it_out != out_end)
agree = false;
int i = 1;
while (i < static_cast<int>(liste.size()) && agree)
{
int j = i + 1;
while (j < static_cast<int>(liste.size()) && agree)
{
auto [ed1, exist1] = edge(liste[i], liste[j], *this);
auto [ed2, exist2] = edge(liste[j], liste[i], *this);
agree = exist1 && exist2;
j++;
}
i++;
}
}
return agree;
}
bool
VariableDependencyGraph::eliminationOfVerticesWithOneOrLessIndegreeOrOutdegree()
{
bool something_has_been_done = false;
bool not_a_loop;
int i;
vertex_iterator it, ita, it_end;
for (tie(it, it_end) = vertices(*this), i = 0; it != it_end; ++it, i++)
{
int in_degree_n = in_degree(*it, *this);
int out_degree_n = out_degree(*it, *this);
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!
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;
if (not_a_loop)
{
eliminate(*it);
something_has_been_done = true;
if (i > 0)
it = ita;
else
{
tie(it, it_end) = vertices(*this);
i--;
}
}
}
ita = it;
}
return something_has_been_done;
}
bool
VariableDependencyGraph::eliminationOfVerticesBelongingToAClique()
{
vertex_iterator it, ita, it_end;
bool something_has_been_done = false;
int i;
for (tie(it, it_end) = vertices(*this), i = 0; it != it_end; ++it, i++)
{
if (vertexBelongsToAClique(*it))
{
eliminate(*it);
something_has_been_done = true;
if (i > 0)
it = ita;
else
{
tie(it, it_end) = vertices(*this);
i--;
}
}
ita = it;
}
return something_has_been_done;
}
bool
VariableDependencyGraph::suppressionOfVerticesWithLoop(set<int>& feed_back_vertices)
{
bool something_has_been_done = false;
vertex_iterator ita;
int i = 0;
for (auto [it, it_end] = vertices(*this); it != it_end; ++it, i++)
{
auto [ed, exist] = edge(*it, *it, *this);
if (exist)
{
auto v_index = get(vertex_index, *this);
feed_back_vertices.insert(v_index[*it]);
suppress(*it);
something_has_been_done = true;
if (i > 0)
it = ita;
else
{
tie(it, it_end) = vertices(*this);
i--;
}
}
ita = it;
}
return something_has_been_done;
}
set<int>
VariableDependencyGraph::minimalSetOfFeedbackVertices() const
{
set<int> feed_back_vertices;
VariableDependencyGraph G(*this);
while (num_vertices(G) > 0)
{
bool something_has_been_done = true;
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;
}
if (!G.hasCycle())
return feed_back_vertices;
if (num_vertices(G) > 0)
{
/* If nothing has been done in the five previous rule then cut the
vertex with the maximum in_degree+out_degree */
int max_degree = 0, num = 0;
vertex_iterator max_degree_index;
for (auto [it, it_end] = vertices(G); it != it_end; ++it, num++)
if (static_cast<int>(in_degree(*it, G) + out_degree(*it, G)) > max_degree)
{
max_degree = in_degree(*it, G) + out_degree(*it, G);
max_degree_index = it;
}
auto v_index = get(vertex_index, G);
feed_back_vertices.insert(v_index[*max_degree_index]);
G.suppress(*max_degree_index);
}
}
return feed_back_vertices;
}
vector<int>
VariableDependencyGraph::reorderRecursiveVariables(const set<int>& feedback_vertices) const
{
vector<int> reordered_vertices;
VariableDependencyGraph G(*this);
auto v_index = get(vertex_index, G);
// Suppress feedback vertices, in decreasing order
for (int feedback_vertex : ranges::reverse_view(feedback_vertices))
G.suppress(feedback_vertex);
bool something_has_been_done = true;
while (something_has_been_done)
{
something_has_been_done = false;
vertex_iterator it, it_end, ita;
int i;
for (tie(it, it_end) = vertices(G), i = 0; it != it_end; ++it, i++)
{
if (in_degree(*it, G) == 0)
{
reordered_vertices.push_back(v_index[*it]);
G.suppress(*it);
something_has_been_done = true;
if (i > 0)
it = ita;
else
{
tie(it, it_end) = vertices(G);
i--;
}
}
ita = it;
}
}
if (num_vertices(G))
cout << "Error in the computation of feedback vertex set\n";
return reordered_vertices;
}
pair<int, vector<int>>
VariableDependencyGraph::sortedStronglyConnectedComponents() const
{
vector<int> vertex2scc(num_vertices(*this));
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));
// Create directed acyclic graph (DAG) associated to the SCCs
adjacency_list<vecS, vecS, directedS> dag(num_scc);
for (int i = 0; i < static_cast<int>(num_vertices(*this)); i++)
{
auto vi = vertex(i, *this);
for (auto [it_out, out_end] = out_edges(vi, *this); it_out != out_end; ++it_out)
if (int t_b = vertex2scc[v_index[target(*it_out, *this)]],
s_b = vertex2scc[v_index[source(*it_out, *this)]];
s_b != t_b)
add_edge(s_b, t_b, dag);
}
/* Compute topological sort of DAG (ordered list of unordered SCC)
Note: the order is reversed. */
vector<int> reverseOrdered2unordered;
topological_sort(dag, back_inserter(reverseOrdered2unordered));
// Construct mapping from unordered SCC to ordered SCC
vector<int> unordered2ordered(num_scc);
for (int j = 0; j < num_scc; j++)
unordered2ordered[reverseOrdered2unordered[num_scc - j - 1]] = j;
// Update the mapping of vertices to (now sorted) SCCs
for (int i = 0; i < static_cast<int>(num_vertices(*this)); i++)
vertex2scc[i] = unordered2ordered[vertex2scc[i]];
return {num_scc, vertex2scc};
}
/*
* Copyright © 2009-2023 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef VARIABLE_DEPENDENCY_GRAPH_HH
#define VARIABLE_DEPENDENCY_GRAPH_HH
#include <map>
#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#include <boost/graph/adjacency_list.hpp>
#pragma GCC diagnostic pop
using namespace std;
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>
{
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>;
VariableDependencyGraph(int n);
//! Extracts a subgraph
/*!
\param[in] select_index The vertex indices to select
\return The subgraph
The property vertex_index1 of the subgraph contains indices of the original
graph.
*/
[[nodiscard]] VariableDependencyGraph extractSubgraph(const vector<int>& select_index) const;
//! Return the feedback set
[[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
*/
[[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. */
[[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);
// Remove a vertex (including all edges to and from it); takes a vertex index
void suppress(int vertex_num);
/* Remove a vertex, but keeping the paths that go through it (i.e. by adding
edges that directly connect vertices that would otherwise be connected
through the vertex to be removed) */
void eliminate(vertex_descriptor vertex_to_eliminate);
// Internal helper for hasCycle()
bool hasCycleDFS(vertex_descriptor u, color_t& color, vector<int>& circuit_stack) const;
// Determine whether the graph has a cycle
[[nodiscard]] bool hasCycle() const;
bool vertexBelongsToAClique(vertex_descriptor vertex) const;
bool eliminationOfVerticesWithOneOrLessIndegreeOrOutdegree();
bool eliminationOfVerticesBelongingToAClique();
// The suppressed vertices are stored in feedback set
bool suppressionOfVerticesWithLoop(set<int>& feed_back_vertices);
};
#endif
/* /*
* Copyright © 2012-2017 Dynare Team * Copyright © 2012-2024 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,46 +14,37 @@ ...@@ -14,46 +14,37 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "WarningConsolidation.hh" #include "WarningConsolidation.hh"
#include <ostream>
WarningConsolidation ostream&
& operator<<(ostream& stream, const Dynare::location& l)
operator<<(WarningConsolidation &wcc, const string &warning)
{ {
if (wcc.no_warn) stream << *l.begin.filename << ": line " << l.begin.line;
return wcc; 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;
cerr << warning; return stream;
wcc.addWarning(warning); }
return wcc;
};
WarningConsolidation & void
operator<<(WarningConsolidation &wcc, const Dynare::location &loc) WarningConsolidation::incrementWarnings(const string& msg)
{ {
if (wcc.no_warn) size_t p {0};
return wcc; while ((p = msg.find('\n', p)) != string::npos)
{
stringstream ostr; p++;
Dynare::position last = loc.end - 1; num_warnings++;
ostr << loc.begin; }
if (last.filename }
&& (!loc.begin.filename
|| *loc.begin.filename != *last.filename))
ostr << '-' << last;
else if (loc.begin.line != last.line)
ostr << '-' << last.line << '.' << last.column;
else if (loc.begin.column != last.column)
ostr << '-' << last.column;
cerr << ostr.str();
wcc.addWarning(ostr.str());
return wcc;
};
WarningConsolidation& WarningConsolidation&
operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&)) operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&))
...@@ -61,49 +52,12 @@ operator<<(WarningConsolidation &wcc, ostream &(*pf)(ostream &)) ...@@ -61,49 +52,12 @@ operator<<(WarningConsolidation &wcc, ostream &(*pf)(ostream &))
if (wcc.no_warn) if (wcc.no_warn)
return wcc; return wcc;
cerr << pf; ostringstream ostr;
wcc.addWarning(pf); ostr << pf;
return wcc;
}
void
WarningConsolidation::writeOutput(ostream &output) const
{
if (warnings.str().empty())
return;
output << "disp([char(10) 'Dynare Preprocessor Warning(s) Encountered:']);" << endl; cerr << ostr.str();
bool writedisp = true; wcc.incrementWarnings(ostr.str());
string warningsstr = warnings.str();
for (size_t i = 0; i < warningsstr.length(); i++)
{
if (writedisp)
{
output << "disp(' ";
writedisp = false;
}
if (warningsstr[i] != '\n') return wcc;
output << warningsstr[i];
else
{
output << "');" << endl;
if (i+1 < warningsstr.length())
writedisp = true;
}
}
}
int
WarningConsolidation::countWarnings() const
{
size_t p = 0;
int n = 0;
while ((p = warnings.str().find('\n', p)) != string::npos)
{
p++;
n++;
}
return n;
} }
/* /*
* Copyright © 2012-2017 Dynare Team * Copyright © 2012-2024 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,52 +14,71 @@ ...@@ -14,52 +14,71 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef _WARNINGCONSOLIDATION_HH #ifndef WARNING_CONSOLIDATION_HH
#define _WARNINGCONSOLIDATION_HH #define WARNING_CONSOLIDATION_HH
#include "DynareBisonLocation.hh"
#include <iostream>
#include <ostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include "location.hh"
using namespace std; using namespace std;
//! Stores Warnings issued by the Preprocessor /* Provide our implementation of operator<< with locations in DynareBison.hh. Note that the
following is a template specialization of the version provided in DynareBisonLocation.hh.
Ideally it should go into DynareBisonLocation.hh, but there does not seem to be a way to achieve
that. */
ostream& operator<<(ostream& stream, const Dynare::location& l);
class WarningConsolidation class WarningConsolidation
{ {
private: private:
stringstream warnings; const bool no_warn;
bool no_warn; int num_warnings {0};
// Increases the warning counter by as many newlines as there are in the message
void incrementWarnings(const string& msg);
public: public:
explicit WarningConsolidation(bool no_warn_arg) : no_warn {no_warn_arg} explicit WarningConsolidation(bool no_warn_arg) : no_warn {no_warn_arg}
{ {
}; }
// Generic function to print something to the warning stream
friend WarningConsolidation& operator<<(WarningConsolidation& wcc, auto&& warning);
//! Add A Warning to the StringStream /* Print std::endl to the warning stream. Unfortunately, since std::endl is a template of
friend WarningConsolidation &operator<<(WarningConsolidation &wcc, const string &warning); functions, it cannot be bound to the universal reference of the generic function, hence the
friend WarningConsolidation &operator<<(WarningConsolidation &wcc, const Dynare::location &loc); need for this specialization. */
friend WarningConsolidation& operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&)); friend WarningConsolidation& operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&));
inline void int
addWarning(const string &w) numWarnings() const
{ {
warnings << w; return num_warnings;
}
}; };
inline void
addWarning(ostream &(*pf)(ostream &)) WarningConsolidation&
operator<<(WarningConsolidation& wcc, auto&& warning)
{ {
warnings << pf; if (wcc.no_warn)
}; return wcc;
//! Write Warnings to m file ostringstream ostr;
void writeOutput(ostream &output) const; ostr << warning;
//! Count warnings
/*! This is done in a very lousy way, by counting newlines in the cerr << ostr.str();
stringstream... */
int countWarnings() const; wcc.incrementWarnings(ostr.str());
};
return wcc;
}
#endif #endif
# GDB pretty-printer for ExprNode class hierarchy
# Copyright © 2022-2023 Dynare Team
#
# This file is part of Dynare.
#
# Dynare is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Dynare is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Dynare. If not, see <https://www.gnu.org/licenses/>.
class ExprNodePrinter:
'''Pretty-prints an ExprNode value'''
def __init__(self, val):
self.val = val
def to_string(self):
# Call the toString() method on the pointer.
# We must use the raw pretty-printer for the pointer itself, otherwise
# we enter an infinite loop.
# We retrieve a C string, because with C++ strings the gdb pretty-printer
# insists on keeping the quotes around it.
r = gdb.parse_and_eval("((ExprNode *) " + self.val.format_string(raw = True) + ")->toString().c_str()")
typestr = "(" + str(self.val.type) + ") ";
# Add dynamic type information between brackets, if different from static type
if str(self.val.type) != str(self.val.dynamic_type):
typestr += "[" + str(self.val.dynamic_type) + "] "
return typestr + r.string()
class ExprNodePrinterControl(gdb.printing.PrettyPrinter):
'''Determines whether a value can be pretty printed with ExprNodePrinter. To be directly registered within the GDB API.'''
def __init__(self):
# The name below will appear in “info pretty-printer”, and can be used with “enable/disable pretty-printer”
super().__init__('ExprNode')
def __call__(self, val):
# Check if the value is a subtype of ExprNode *.
# Doing a dynamic_cast on a non-pointer type triggers an exception, so we first check
# whether it’s a pointer (after resolving for typedefs, such as “expr_t”).
if val.type.strip_typedefs().code == gdb.TYPE_CODE_PTR and val.dynamic_cast(gdb.lookup_type('ExprNode').pointer()) != 0:
return ExprNodePrinter(val)
# Register the pretty printer
gdb.pretty_printers.append(ExprNodePrinterControl())
/* /*
* Copyright © 2019 Dynare Team * Copyright © 2019-2023 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
...@@ -14,22 +14,23 @@ ...@@ -14,22 +14,23 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <http://www.gnu.org/licenses/>. * along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "Directives.hh" #include "Directives.hh"
#include "Driver.hh" #include "Driver.hh"
#include <fstream> #include <fstream>
#include <utility>
using namespace macro; using namespace macro;
void void
Eval::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) Eval::interpret(ostream& output, Environment& env, [[maybe_unused]] vector<filesystem::path>& paths)
{ {
try try
{ {
output << expr->eval()->to_string(); output << expr->eval(env)->to_string();
} }
catch (StackTrace& ex) catch (StackTrace& ex)
{ {
...@@ -43,12 +44,12 @@ Eval::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &p ...@@ -43,12 +44,12 @@ Eval::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &p
} }
void void
Include::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) Include::interpret(ostream& output, Environment& env, vector<filesystem::path>& paths)
{ {
using namespace filesystem; using namespace filesystem;
try try
{ {
StringPtr msp = dynamic_pointer_cast<String>(expr->eval()); StringPtr msp = dynamic_pointer_cast<String>(expr->eval(env));
if (!msp) if (!msp)
throw StackTrace("File name does not evaluate to a string"); throw StackTrace("File name does not evaluate to a string");
path filename = msp->to_string(); path filename = msp->to_string();
...@@ -67,15 +68,18 @@ Include::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> ...@@ -67,15 +68,18 @@ Include::interpret(ostream &output, bool no_line_macro, vector<filesystem::path>
errmsg << " * " << current_path().string() << endl; errmsg << " * " << current_path().string() << endl;
for (const auto& dir : paths) for (const auto& dir : paths)
errmsg << " * " << absolute(dir).string() << endl; errmsg << " * " << absolute(dir).string() << endl;
error(StackTrace("@#includepath", "Could not open " + filename.string() error(StackTrace("@#include",
+". The following directories were searched:\n" + errmsg.str(), location)); "Could not open " + filename.string()
+ ". The following directories were searched:\n" + errmsg.str(),
location));
} }
} }
Driver m(env, no_line_macro); Driver m;
// Calling `string()` method on filename and filename.stem() because of bug in /* Calling string() method on filename: not necessary on GNU/Linux and macOS because there is
// MinGW 8.3.0 that ignores implicit conversion to string from filename::path. an implicit conversion from from filesystem:path to string (i.e. basic_string<char>), but
// Test if bug exists when version of MinGW is upgraded on Debian runners needed on Windows because the implicit conversion is only to wstring (i.e.
m.parse(filename.string(), filename.stem().string(), incfile, output, false, vector<pair<string, string>>{}, paths); basic_string<wchar_t>). */
m.parse(filename.string(), incfile, false, {}, env, paths, output);
} }
catch (StackTrace& ex) catch (StackTrace& ex)
{ {
...@@ -86,15 +90,17 @@ Include::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> ...@@ -86,15 +90,17 @@ Include::interpret(ostream &output, bool no_line_macro, vector<filesystem::path>
{ {
error(StackTrace("@#include", e.what(), location)); error(StackTrace("@#include", e.what(), location));
} }
printEndLineInfo(output);
} }
void void
IncludePath::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) IncludePath::interpret([[maybe_unused]] ostream& output, Environment& env,
vector<filesystem::path>& paths)
{ {
using namespace filesystem; using namespace filesystem;
try try
{ {
StringPtr msp = dynamic_pointer_cast<String>(expr->eval()); StringPtr msp = dynamic_pointer_cast<String>(expr->eval(env));
if (!msp) if (!msp)
throw StackTrace("File name does not evaluate to a string"); throw StackTrace("File name does not evaluate to a string");
path ip = static_cast<string>(*msp); path ip = static_cast<string>(*msp);
...@@ -113,10 +119,12 @@ IncludePath::interpret(ostream &output, bool no_line_macro, vector<filesystem::p ...@@ -113,10 +119,12 @@ IncludePath::interpret(ostream &output, bool no_line_macro, vector<filesystem::p
{ {
error(StackTrace("@#includepath", e.what(), location)); error(StackTrace("@#includepath", e.what(), location));
} }
printEndLineInfo(output);
} }
void void
Define::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) Define::interpret([[maybe_unused]] ostream& output, Environment& env,
[[maybe_unused]] vector<filesystem::path>& paths)
{ {
try try
{ {
...@@ -136,14 +144,15 @@ Define::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> ...@@ -136,14 +144,15 @@ Define::interpret(ostream &output, bool no_line_macro, vector<filesystem::path>
{ {
error(StackTrace("@#define", e.what(), location)); error(StackTrace("@#define", e.what(), location));
} }
printEndLineInfo(output);
} }
void void
Echo::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) Echo::interpret(ostream& output, Environment& env, [[maybe_unused]] vector<filesystem::path>& paths)
{ {
try try
{ {
cout << "@#echo (" << getLocation() << "): " << expr->eval()->to_string() << endl; cout << "@#echo (" << getLocation() << "): " << expr->eval(env)->to_string() << endl;
} }
catch (StackTrace& ex) catch (StackTrace& ex)
{ {
...@@ -154,15 +163,16 @@ Echo::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &p ...@@ -154,15 +163,16 @@ Echo::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &p
{ {
error(StackTrace("@#echo", e.what(), location)); error(StackTrace("@#echo", e.what(), location));
} }
printEndLineInfo(output, no_line_macro); printEndLineInfo(output);
} }
void void
Error::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) Error::interpret([[maybe_unused]] ostream& output, Environment& env,
[[maybe_unused]] vector<filesystem::path>& paths)
{ {
try try
{ {
throw StackTrace(expr->eval()->to_string()); throw StackTrace(expr->eval(env)->to_string());
} }
catch (StackTrace& ex) catch (StackTrace& ex)
{ {
...@@ -176,22 +186,20 @@ Error::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> & ...@@ -176,22 +186,20 @@ Error::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &
} }
void void
EchoMacroVars::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) EchoMacroVars::interpret(ostream& output, Environment& env,
[[maybe_unused]] vector<filesystem::path>& paths)
{ {
if (save) env.print(save ? output : cout, vars, location.begin.line, save);
env.print(output, vars, location.begin.line, true); printEndLineInfo(output);
else
env.print(cout, vars);
printEndLineInfo(output, no_line_macro);
} }
void void
For::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) For::interpret(ostream& output, Environment& env, vector<filesystem::path>& paths)
{ {
ArrayPtr ap; ArrayPtr ap;
try try
{ {
ap = dynamic_pointer_cast<Array>(index_vals->eval()); ap = dynamic_pointer_cast<Array>(index_vals->eval(env));
if (!ap) if (!ap)
throw StackTrace("The index must loop through an array"); throw StackTrace("The index must loop through an array");
} }
...@@ -219,8 +227,11 @@ For::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &pa ...@@ -219,8 +227,11 @@ For::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &pa
{ {
TuplePtr mtp = dynamic_pointer_cast<Tuple>(btp); TuplePtr mtp = dynamic_pointer_cast<Tuple>(btp);
if (index_vec.size() != mtp->size()) if (index_vec.size() != mtp->size())
error(StackTrace("@#for", "Encountered tuple of size " + to_string(mtp->size()) error(StackTrace("@#for",
+ " but only have " + to_string(index_vec.size()) + " index variables", location)); "Encountered tuple of size " + to_string(mtp->size())
+ " but only have " + to_string(index_vec.size())
+ " index variables",
location));
else else
for (size_t j = 0; j < index_vec.size(); j++) for (size_t j = 0; j < index_vec.size(); j++)
env.define(index_vec.at(j), mtp->at(j)); env.define(index_vec.at(j), mtp->at(j));
...@@ -232,33 +243,49 @@ For::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &pa ...@@ -232,33 +243,49 @@ For::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &pa
{ {
if (printLine) if (printLine)
{ {
statement->printLineInfo(output, no_line_macro); statement->printLineInfo(output);
printLine = false; printLine = false;
} }
statement->interpret(output, no_line_macro, paths); statement->interpret(output, env, paths);
} }
} }
printEndLineInfo(output, no_line_macro); printEndLineInfo(output);
} }
void void
If::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) If::interpret(ostream& output, Environment& env, vector<filesystem::path>& paths)
{ {
for (const auto & [expr, body] : expr_and_body) for (bool first_clause {true}; const auto& [expr, body] : expr_and_body)
try try
{ {
auto tmp = expr->eval(); if ((ifdef || ifndef) && exchange(first_clause, false))
{
VariablePtr vp = dynamic_pointer_cast<Variable>(expr);
if (!vp)
error(StackTrace(ifdef ? "@#ifdef" : "@#ifndef",
"The condition must be a variable name", location));
if ((ifdef && env.isVariableDefined(vp->getName()))
|| (ifndef && !env.isVariableDefined(vp->getName())))
{
interpretBody(body, output, env, paths);
break;
}
}
else
{
auto tmp = expr->eval(env);
RealPtr dp = dynamic_pointer_cast<Real>(tmp); RealPtr dp = dynamic_pointer_cast<Real>(tmp);
BoolPtr bp = dynamic_pointer_cast<Bool>(tmp); BoolPtr bp = dynamic_pointer_cast<Bool>(tmp);
if (!bp && !dp) if (!bp && !dp)
error(StackTrace("@#if", error(StackTrace("@#if", "The condition must evaluate to a boolean or a double",
"The condition must evaluate to a boolean or a double", location)); location));
if ((bp && *bp) || (dp && *dp)) if ((bp && *bp) || (dp && *dp))
{ {
interpretBody(body, output, no_line_macro, paths); interpretBody(body, output, env, paths);
break; break;
} }
} }
}
catch (StackTrace& ex) catch (StackTrace& ex)
{ {
ex.push("@#if", location); ex.push("@#if", location);
...@@ -268,48 +295,17 @@ If::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &pat ...@@ -268,48 +295,17 @@ If::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &pat
{ {
error(StackTrace("@#if", e.what(), location)); error(StackTrace("@#if", e.what(), location));
} }
printEndLineInfo(output, no_line_macro); printEndLineInfo(output);
} }
void void
If::interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro, vector<filesystem::path> &paths) If::interpretBody(const vector<DirectivePtr>& body, ostream& output, Environment& env,
vector<filesystem::path>& paths)
{ {
bool printLine = !no_line_macro; for (bool printLine {true}; const auto& statement : body)
for (const auto &statement : body)
{
if (printLine)
{ {
statement->printLineInfo(output, no_line_macro); if (exchange(printLine, false))
printLine = false; statement->printLineInfo(output);
} statement->interpret(output, env, paths);
statement->interpret(output, no_line_macro, paths);
}
}
void
Ifdef::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
{
for (const auto & [expr, body] : expr_and_body)
if (VariablePtr vp = dynamic_pointer_cast<Variable>(expr);
dynamic_pointer_cast<BaseType>(expr)
|| (vp && env.isVariableDefined(vp->getName())))
{
interpretBody(body, output, no_line_macro, paths);
break;
}
printEndLineInfo(output, no_line_macro);
}
void
Ifndef::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
{
for (const auto & [expr, body] : expr_and_body)
if (VariablePtr vp = dynamic_pointer_cast<Variable>(expr);
!(dynamic_pointer_cast<BaseType>(expr)
|| (vp && env.isVariableDefined(vp->getName()))))
{
interpretBody(body, output, no_line_macro, paths);
break;
} }
printEndLineInfo(output, no_line_macro);
} }