Merge branch 'exclude_eqs' into 'master'

introduce command line options: `exclude_eqs` and `include_eqs`

See merge request Dynare/preprocessor!7
issue#70
Sébastien Villemot 2019-11-26 15:04:00 +00:00
commit 8be9efa425
11 changed files with 400 additions and 20 deletions

View File

@ -150,7 +150,8 @@ enum class SymbolType
logTrend = 15, //!< Log-trend variable logTrend = 15, //!< Log-trend variable
unusedEndogenous = 16, //!< Type to mark unused endogenous variables when `nostrict` option is passed unusedEndogenous = 16, //!< Type to mark unused endogenous variables when `nostrict` option is passed
endogenousVAR = 17, //!< Variables declared in a var_model statement endogenousVAR = 17, //!< Variables declared in a var_model statement
epilogue = 18 //!< Variables created in epilogue block epilogue = 18, //!< Variables created in epilogue block
excludedVariable = 19 //!< Type to use when an equation is excluded via include/exclude_eqs and the LHS variable is not used elsewhere in the model
}; };
enum ExpressionType enum ExpressionType

View File

@ -23,6 +23,7 @@
#include <cassert> #include <cassert>
#include <algorithm> #include <algorithm>
#include <numeric> #include <numeric>
#include <regex>
#include "DynamicModel.hh" #include "DynamicModel.hh"
@ -103,6 +104,7 @@ DynamicModel::DynamicModel(const DynamicModel &m) :
balanced_growth_test_tol {m.balanced_growth_test_tol}, balanced_growth_test_tol {m.balanced_growth_test_tol},
static_only_equations_lineno {m.static_only_equations_lineno}, static_only_equations_lineno {m.static_only_equations_lineno},
static_only_equations_equation_tags {m.static_only_equations_equation_tags}, static_only_equations_equation_tags {m.static_only_equations_equation_tags},
static_only_equation_tags_xref {m.static_only_equation_tags_xref},
deriv_id_table {m.deriv_id_table}, deriv_id_table {m.deriv_id_table},
inv_deriv_id_table {m.inv_deriv_id_table}, inv_deriv_id_table {m.inv_deriv_id_table},
dyn_jacobian_cols_table {m.dyn_jacobian_cols_table}, dyn_jacobian_cols_table {m.dyn_jacobian_cols_table},
@ -165,6 +167,7 @@ DynamicModel::operator=(const DynamicModel &m)
static_only_equations_lineno = m.static_only_equations_lineno; static_only_equations_lineno = m.static_only_equations_lineno;
static_only_equations_equation_tags = m.static_only_equations_equation_tags; static_only_equations_equation_tags = m.static_only_equations_equation_tags;
static_only_equation_tags_xref = m.static_only_equation_tags_xref;
deriv_id_table = m.deriv_id_table; deriv_id_table = m.deriv_id_table;
inv_deriv_id_table = m.inv_deriv_id_table; inv_deriv_id_table = m.inv_deriv_id_table;
dyn_jacobian_cols_table = m.dyn_jacobian_cols_table; dyn_jacobian_cols_table = m.dyn_jacobian_cols_table;
@ -2930,6 +2933,179 @@ DynamicModel::writeDynamicJacobianNonZeroElts(const string &basename) const
output.close(); output.close();
} }
void
DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_eq_tags, set<pair<string, string>> & eq_tag_set, bool exclude_eqs)
{
string tags;
if (filesystem::exists(inc_exc_eq_tags))
{
ifstream exclude_file;
exclude_file.open(inc_exc_eq_tags, ifstream::in);
if (!exclude_file.is_open())
{
cerr << "ERROR: Could not open " << inc_exc_eq_tags << endl;
exit(EXIT_FAILURE);
}
string line;
bool tagname_on_first_line = false;
while (getline(exclude_file, line))
{
removeLeadingTrailingWhitespace(line);
if (!line.empty())
if (tags.empty() && line.find("=") != string::npos)
{
tagname_on_first_line = true;
tags += line + "(";
}
else
if (line.find("'") != string::npos)
tags += line + ",";
else
tags += "'" + line + "',";
}
if (!tags.empty())
{
tags = tags.substr(0, tags.size()-1);
if (tagname_on_first_line)
tags += ")";
}
}
else
tags = inc_exc_eq_tags;
removeLeadingTrailingWhitespace(tags);
if (tags.front() == '[' && tags.back() != ']')
{
cerr << "Error: " << (exclude_eqs ? "exclude_eqs" : "include_eqs")
<< ": if the first character is '[' the last must be ']'" << endl;
exit(EXIT_FAILURE);
}
if (tags.front() == '[' && tags.back() == ']')
tags = tags.substr(1, tags.length() - 2);
removeLeadingTrailingWhitespace(tags);
regex q ("^\\w+\\s*=");
smatch matches;
string tagname = "name";
if (regex_search(tags, matches, q))
{
tagname = matches[0].str();
tags = tags.substr(tagname.size(), tags.length() - tagname.size() + 1);
removeLeadingTrailingWhitespace(tags);
if (tags.front() == '(' && tags.back() == ')')
{
tags = tags.substr(1, tags.length() - 2);
removeLeadingTrailingWhitespace(tags);
}
tagname = tagname.substr(0, tagname.size()-1);
removeLeadingTrailingWhitespace(tagname);
}
string quote_regex = "'[^']+'";
string non_quote_regex = "[^,\\s]+";
regex r ("(\\s*" + quote_regex + "|" + non_quote_regex + "\\s*)(,\\s*(" + quote_regex + "|" + non_quote_regex + ")\\s*)*");
if (!regex_match (tags, r))
{
cerr << "Error: " << (exclude_eqs ? "exclude_eqs" : "include_eqs")
<< ": argument is of incorrect format." << endl;
exit(EXIT_FAILURE);
}
regex s (quote_regex + "|" + non_quote_regex);
for (auto it = sregex_iterator(tags.begin(), tags.end(), s);
it != sregex_iterator(); it++)
{
auto str = it->str();
if (str[0] == '\'' && str[str.size()-1] == '\'')
str = str.substr(1, str.size()-2);
eq_tag_set.insert({tagname, str});
}
}
void
DynamicModel::includeExcludeEquations(const string & eqs, bool exclude_eqs)
{
if (eqs.empty())
return;
set<pair<string, string>> eq_tag_set;
parseIncludeExcludeEquations(eqs, eq_tag_set, exclude_eqs);
vector<int> excluded_vars =
ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
equations, equations_lineno,
equation_tags, equation_tags_xref, false);
// `static_only_equation_tags` is `vector<vector<pair<string, string>>>`
// while `equation_tags` is `vector<pair<int, pair<string, string>>>`
// so convert former structure to latter to conform with function call
int n = 0;
vector<pair<int, pair<string, string>>> tmp_static_only_equation_tags;
for (auto & eqn_tags : static_only_equations_equation_tags)
{
for (auto & eqn_tag : eqn_tags)
tmp_static_only_equation_tags.emplace_back(make_pair(n, eqn_tag));
n++;
}
// Ignore output because variables are not excluded when equations marked 'static' are excluded
ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
static_only_equations, static_only_equations_lineno,
tmp_static_only_equation_tags,
static_only_equation_tags_xref, true);
if (!eq_tag_set.empty())
{
cerr << "ERROR: " << (exclude_eqs ? "exclude_eqs" : "include_eqs") << ": The equations specified by `";
cerr << eq_tag_set.begin()->first << "= ";
for (auto & it : eq_tag_set)
cerr << it.second << ", ";
cerr << "` were not found." << endl;
exit(EXIT_FAILURE);
}
if (staticOnlyEquationsNbr() != dynamicOnlyEquationsNbr())
{
cerr << "ERROR: " << (exclude_eqs ? "exclude_eqs" : "include_eqs")
<< ": You must remove the same number of equations marked `static` as equations marked `dynamic`." << endl;
exit(EXIT_FAILURE);
}
// convert back static equation info
if (static_only_equations.empty())
static_only_equations_equation_tags.clear();
else
{
static_only_equations_equation_tags.resize(static_only_equations.size());
fill(static_only_equations_equation_tags.begin(), static_only_equations_equation_tags.end(), vector<pair<string, string>>());
for (auto & it : tmp_static_only_equation_tags)
static_only_equations_equation_tags.at(it.first).emplace_back(it.second);
}
// Collect list of used variables in updated list of equations
set<pair<int, int>> eqn_vars;
for (const auto & eqn : equations)
eqn->collectDynamicVariables(SymbolType::endogenous, eqn_vars);
for (const auto & eqn : static_only_equations)
eqn->collectDynamicVariables(SymbolType::endogenous, eqn_vars);
// Change LHS variable type of excluded equation if it is used in an eqution that has been kept
for (auto ev : excluded_vars)
{
bool found = false;
for (const auto & it : eqn_vars)
if (it.first == ev)
{
symbol_table.changeType(ev, SymbolType::exogenous);
found = true;
break;
}
if (!found)
symbol_table.changeType(ev, SymbolType::excludedVariable);
}
}
void void
DynamicModel::writeOutput(ostream &output, const string &basename, bool block_decomposition, bool linear_decomposition, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const DynamicModel::writeOutput(ostream &output, const string &basename, bool block_decomposition, bool linear_decomposition, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const
{ {
@ -6305,13 +6481,22 @@ DynamicModel::getEquationNumbersFromTags(const set<string> &eqtags) const
{ {
vector<int> eqnumbers; vector<int> eqnumbers;
for (auto & eqtag : eqtags) for (auto & eqtag : eqtags)
{
bool found = false;
for (const auto & equation_tag : equation_tags) for (const auto & equation_tag : equation_tags)
if (equation_tag.second.first == "name" if (equation_tag.second.first == "name"
&& equation_tag.second.second == eqtag) && equation_tag.second.second == eqtag)
{ {
found = true;
eqnumbers.push_back(equation_tag.first); eqnumbers.push_back(equation_tag.first);
break; break;
} }
if (!found)
{
cerr << "ERROR: looking for equation tag " << eqtag << " failed." << endl;
exit(EXIT_FAILURE);
}
}
return eqnumbers; return eqnumbers;
} }
@ -6618,9 +6803,12 @@ DynamicModel::addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<str
for (const auto & eq_tag : eq_tags) for (const auto & eq_tag : eq_tags)
soe_eq_tags.push_back(eq_tag); soe_eq_tags.push_back(eq_tag);
int n = static_only_equations.size();
static_only_equations.push_back(beq); static_only_equations.push_back(beq);
static_only_equations_lineno.push_back(lineno); static_only_equations_lineno.push_back(lineno);
static_only_equations_equation_tags.push_back(soe_eq_tags); static_only_equations_equation_tags.push_back(soe_eq_tags);
for (auto & it : soe_eq_tags)
static_only_equation_tags_xref.emplace(it, n);
} }
size_t size_t

View File

@ -56,6 +56,9 @@ private:
//! Stores the equation tags of equations declared as [static] //! Stores the equation tags of equations declared as [static]
vector<vector<pair<string, string>>> static_only_equations_equation_tags; vector<vector<pair<string, string>>> static_only_equations_equation_tags;
//! Stores mapping from equation tags to equation number
multimap<pair<string, string>, int> static_only_equation_tags_xref;
using deriv_id_table_t = map<pair<int, int>, int>; using deriv_id_table_t = map<pair<int, int>, int>;
//! Maps a pair (symbol_id, lag) to a deriv ID //! Maps a pair (symbol_id, lag) to a deriv ID
deriv_id_table_t deriv_id_table; deriv_id_table_t deriv_id_table;
@ -266,6 +269,32 @@ private:
pointers into their equivalent in the new tree */ pointers into their equivalent in the new tree */
void copyHelper(const DynamicModel &m); void copyHelper(const DynamicModel &m);
// Internal helper functions for includeExcludeEquations()
/*! Handles parsing of argument passed to exclude_eqs/include_eqs*/
/*
Expects command line arguments of the form:
* filename.txt
* eq1
* ['eq 1', 'eq 2']
* [tagname='eq 1']
* [tagname=('eq 1', 'eq 2')]
If argument is a file, the file should be formatted as:
eq 1
eq 2
OR
tagname=
X
Y
*/
void parseIncludeExcludeEquations(const string &inc_exc_eq_tags, set<pair<string, string>> & eq_tag_set, bool exclude_eqs);
// General function that removes leading/trailing whitespace from a string
inline void removeLeadingTrailingWhitespace(string & str)
{
str.erase(0, str.find_first_not_of("\t\n\v\f\r "));
str.erase(str.find_last_not_of("\t\n\v\f\r ") + 1);
}
public: public:
DynamicModel(SymbolTable &symbol_table_arg, DynamicModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg, NumericalConstants &num_constants_arg,
@ -397,6 +426,9 @@ public:
//! Set the max leads/lags of the original model //! Set the max leads/lags of the original model
void setLeadsLagsOrig(); void setLeadsLagsOrig();
//! Removes equations from the model according to name tags
void includeExcludeEquations(const string & eqs, bool exclude_eqs);
//! Replaces model equations with derivatives of Lagrangian w.r.t. endogenous //! Replaces model equations with derivatives of Lagrangian w.r.t. endogenous
void computeRamseyPolicyFOCs(const StaticModel &static_model); void computeRamseyPolicyFOCs(const StaticModel &static_model);
//! Replaces the model equations in dynamic_model with those in this model //! Replaces the model equations in dynamic_model with those in this model

View File

@ -46,6 +46,7 @@ void main2(stringstream &in, const string &basename, bool debug, bool clear_all,
WarningConsolidation &warnings_arg, bool nostrict, bool stochastic, bool check_model_changes, WarningConsolidation &warnings_arg, bool nostrict, bool stochastic, bool check_model_changes,
bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode, bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops, LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops,
const string &exclude_eqs, const string &include_eqs,
JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple, JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple,
const string &mexext, const filesystem::path &matlabroot, const string &mexext, const filesystem::path &matlabroot,
const filesystem::path &dynareroot, bool onlymodel); const filesystem::path &dynareroot, bool onlymodel);
@ -60,7 +61,7 @@ usage()
cerr << "Dynare usage: dynare mod_file [debug] [noclearall] [onlyclearglobals] [savemacro[=macro_file]] [onlymacro] [nolinemacro] [noemptylinemacro] [notmpterms] [nolog] [warn_uninit]" cerr << "Dynare usage: dynare mod_file [debug] [noclearall] [onlyclearglobals] [savemacro[=macro_file]] [onlymacro] [nolinemacro] [noemptylinemacro] [notmpterms] [nolog] [warn_uninit]"
<< " [console] [nograph] [nointeractive] [parallel[=cluster_name]] [conffile=parallel_config_path_and_filename] [parallel_slave_open_mode] [parallel_test]" << " [console] [nograph] [nointeractive] [parallel[=cluster_name]] [conffile=parallel_config_path_and_filename] [parallel_slave_open_mode] [parallel_test]"
<< " [-D<variable>[=<value>]] [-I/path] [nostrict] [stochastic] [fast] [minimal_workspace] [compute_xrefs] [output=dynamic|first|second|third] [language=matlab|julia]" << " [-D<variable>[=<value>]] [-I/path] [nostrict] [stochastic] [fast] [minimal_workspace] [compute_xrefs] [output=dynamic|first|second|third] [language=matlab|julia]"
<< " [params_derivs_order=0|1|2] [transform_unary_ops]" << " [params_derivs_order=0|1|2] [transform_unary_ops] [exclude_eqs=<equation_tag_list_or_file>] [include_eqs=<equation_tag_list_or_file>]"
<< " [json=parse|check|transform|compute] [jsonstdout] [onlyjson] [jsonderivsimple] [nopathchange] [nopreprocessoroutput]" << " [json=parse|check|transform|compute] [jsonstdout] [onlyjson] [jsonderivsimple] [nopathchange] [nopreprocessoroutput]"
<< " [mexext=<extension>] [matlabroot=<path>] [onlymodel]" << " [mexext=<extension>] [matlabroot=<path>] [onlymodel]"
<< endl; << endl;
@ -154,6 +155,7 @@ main(int argc, char **argv)
bool minimal_workspace = false; bool minimal_workspace = false;
bool compute_xrefs = false; bool compute_xrefs = false;
bool transform_unary_ops = false; bool transform_unary_ops = false;
string exclude_eqs, include_eqs;
vector<pair<string, string>> defines; vector<pair<string, string>> defines;
vector<filesystem::path> paths; vector<filesystem::path> paths;
FileOutputType output_mode{FileOutputType::none}; FileOutputType output_mode{FileOutputType::none};
@ -371,6 +373,24 @@ main(int argc, char **argv)
} }
mexext = s.substr(7); mexext = s.substr(7);
} }
else if (s.substr(0, 11) == "exclude_eqs")
{
if (s.length() <= 12 || s.at(11) != '=')
{
cerr << "Incorrect syntax for exclude_eqs option" << endl;
usage();
}
exclude_eqs = s.substr(12);
}
else if (s.substr(0, 11) == "include_eqs")
{
if (s.length() <= 12 || s.at(11) != '=')
{
cerr << "Incorrect syntax for include_eqs option" << endl;
usage();
}
include_eqs = s.substr(12);
}
else if (s.substr(0, 10) == "matlabroot") else if (s.substr(0, 10) == "matlabroot")
{ {
if (s.length() <= 11 || s.at(10) != '=') if (s.length() <= 11 || s.at(10) != '=')
@ -418,11 +438,17 @@ main(int argc, char **argv)
if (only_macro) if (only_macro)
return EXIT_SUCCESS; return EXIT_SUCCESS;
if (!exclude_eqs.empty() && !include_eqs.empty())
{
cerr << "You may only pass one of `include_eqs` and `exclude_eqs`" << endl;
exit(EXIT_FAILURE);
}
// Do the rest // Do the rest
main2(macro_output, basename, debug, clear_all, clear_global, main2(macro_output, basename, debug, clear_all, clear_global,
no_tmp_terms, no_log, no_warn, warn_uninit, console, nograph, nointeractive, no_tmp_terms, no_log, no_warn, warn_uninit, console, nograph, nointeractive,
parallel, config_file, warnings, nostrict, stochastic, check_model_changes, minimal_workspace, parallel, config_file, warnings, nostrict, stochastic, check_model_changes, minimal_workspace,
compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops, compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops, exclude_eqs, include_eqs,
json, json_output_mode, onlyjson, jsonderivsimple, json, json_output_mode, onlyjson, jsonderivsimple,
mexext, matlabroot, dynareroot, onlymodel); mexext, matlabroot, dynareroot, onlymodel);

View File

@ -32,6 +32,7 @@ main2(stringstream &in, const string &basename, bool debug, bool clear_all, bool
WarningConsolidation &warnings, bool nostrict, bool stochastic, bool check_model_changes, WarningConsolidation &warnings, bool nostrict, bool stochastic, bool check_model_changes,
bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode, bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
LanguageOutputType language, int params_derivs_order, bool transform_unary_ops, LanguageOutputType language, int params_derivs_order, bool transform_unary_ops,
const string &exclude_eqs, const string &include_eqs,
JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple, JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonderivsimple,
const string &mexext, const filesystem::path &matlabroot, const string &mexext, const filesystem::path &matlabroot,
const filesystem::path &dynareroot, bool onlymodel) const filesystem::path &dynareroot, bool onlymodel)
@ -51,7 +52,8 @@ main2(stringstream &in, const string &basename, bool debug, bool clear_all, bool
mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson); mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);
// Perform transformations on the model (creation of auxiliary vars and equations) // Perform transformations on the model (creation of auxiliary vars and equations)
mod_file->transformPass(nostrict, stochastic, compute_xrefs || json == JsonOutputPointType::transformpass, transform_unary_ops); mod_file->transformPass(nostrict, stochastic, compute_xrefs || json == JsonOutputPointType::transformpass,
transform_unary_ops, exclude_eqs, include_eqs);
if (json == JsonOutputPointType::transformpass) if (json == JsonOutputPointType::transformpass)
mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson); mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);

View File

@ -839,6 +839,11 @@ VariableNode::prepareForDerivation()
case SymbolType::epilogue: case SymbolType::epilogue:
cerr << "VariableNode::prepareForDerivation: impossible case" << endl; cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
case SymbolType::excludedVariable:
cerr << "VariableNode::prepareForDerivation: impossible case: "
<< "You are trying to derive a variable that has been excluded via include_eqs/exclude_eqs: "
<< datatree.symbol_table.getName(symb_id) << endl;
exit(EXIT_FAILURE);
} }
} }
@ -871,6 +876,7 @@ VariableNode::computeDerivative(int deriv_id)
case SymbolType::externalFunction: case SymbolType::externalFunction:
case SymbolType::endogenousVAR: case SymbolType::endogenousVAR:
case SymbolType::epilogue: case SymbolType::epilogue:
case SymbolType::excludedVariable:
cerr << "VariableNode::computeDerivative: Impossible case!" << endl; cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -939,6 +945,9 @@ VariableNode::writeJsonAST(ostream &output) const
case SymbolType::epilogue: case SymbolType::epilogue:
output << "epilogue"; output << "epilogue";
break; break;
case SymbolType::excludedVariable:
cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
exit(EXIT_FAILURE);
} }
output << R"(", "lag" : )" << lag << "}"; output << R"(", "lag" : )" << lag << "}";
} }
@ -1220,6 +1229,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
case SymbolType::logTrend: case SymbolType::logTrend:
case SymbolType::statementDeclaredVariable: case SymbolType::statementDeclaredVariable:
case SymbolType::endogenousVAR: case SymbolType::endogenousVAR:
case SymbolType::excludedVariable:
cerr << "VariableNode::writeOutput: Impossible case" << endl; cerr << "VariableNode::writeOutput: Impossible case" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -1439,6 +1449,7 @@ VariableNode::getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recur
case SymbolType::externalFunction: case SymbolType::externalFunction:
case SymbolType::endogenousVAR: case SymbolType::endogenousVAR:
case SymbolType::epilogue: case SymbolType::epilogue:
case SymbolType::excludedVariable:
cerr << "VariableNode::getChainRuleDerivative: Impossible case" << endl; cerr << "VariableNode::getChainRuleDerivative: Impossible case" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -1478,6 +1489,7 @@ VariableNode::computeXrefs(EquationInfo &ei) const
case SymbolType::externalFunction: case SymbolType::externalFunction:
case SymbolType::endogenousVAR: case SymbolType::endogenousVAR:
case SymbolType::epilogue: case SymbolType::epilogue:
case SymbolType::excludedVariable:
break; break;
} }
} }

View File

@ -381,7 +381,8 @@ ModFile::checkPass(bool nostrict, bool stochastic)
} }
void void
ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool transform_unary_ops) ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool transform_unary_ops,
const string &exclude_eqs, const string &include_eqs)
{ {
/* Save the original model (must be done before any model transformations by preprocessor) /* Save the original model (must be done before any model transformations by preprocessor)
except substituting out variables which we know are constant (they except substituting out variables which we know are constant (they
@ -390,6 +391,8 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const
except diff operators with a lead which have been expanded by except diff operators with a lead which have been expanded by
DataTree:AddDiff() DataTree:AddDiff()
*/ */
dynamic_model.includeExcludeEquations(exclude_eqs, true);
dynamic_model.includeExcludeEquations(include_eqs, false);
dynamic_model.simplifyEquations(); dynamic_model.simplifyEquations();
dynamic_model.substituteAdl(); dynamic_model.substituteAdl();
dynamic_model.setLeadsLagsOrig(); dynamic_model.setLeadsLagsOrig();

View File

@ -146,7 +146,8 @@ public:
void checkPass(bool nostrict, bool stochastic); void checkPass(bool nostrict, bool stochastic);
//! Perform some transformations on the model (creation of auxiliary vars and equations) //! Perform some transformations on the model (creation of auxiliary vars and equations)
/*! \param compute_xrefs if true, equation cross references will be computed */ /*! \param compute_xrefs if true, equation cross references will be computed */
void transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool transform_unary_ops); void transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool transform_unary_ops,
const string &exclude_eqs, const string &include_eqs);
//! Execute computations //! Execute computations
/*! \param no_tmp_terms if true, no temporary terms will be computed in the static and dynamic files */ /*! \param no_tmp_terms if true, no temporary terms will be computed in the static and dynamic files */
/*! \param params_derivs_order compute this order of derivs wrt parameters */ /*! \param params_derivs_order compute this order of derivs wrt parameters */

View File

@ -1934,6 +1934,104 @@ ModelTree::addEquation(expr_t eq, int lineno)
equations_lineno.push_back(lineno); equations_lineno.push_back(lineno);
} }
vector<int>
ModelTree::includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
vector<pair<int, pair<string, string>>> &equation_tags,
multimap<pair<string, string>, int> &equation_tags_xref, bool static_equations) const
{
vector<int> excluded_vars;
if (equations.empty())
return excluded_vars;
// Get equation numbers of tags
set<int> tag_eqns;
for (auto & it : eqs)
if (equation_tags_xref.find(it) != equation_tags_xref.end())
{
auto range = equation_tags_xref.equal_range(it);
for_each ( range.first, range.second, [&tag_eqns](auto & x){ tag_eqns.insert(x.second); } );
eqs.erase(it);
}
if (tag_eqns.empty())
return excluded_vars;
set<int> eqns;
if (exclude_eqs)
eqns = tag_eqns;
else
for (size_t i = 0; i < equations.size(); i++)
if (tag_eqns.find(i) == tag_eqns.end())
eqns.insert(i);
// remove from equations, equations_lineno, equation_tags, equation_tags_xref
vector<BinaryOpNode *> new_eqns;
vector<int> new_equations_lineno;
map<int, int> old_eqn_num_2_new;
for (size_t i = 0; i < equations.size(); i++)
if (eqns.find(i) != eqns.end())
{
bool found = false;
for (const auto & it : equation_tags)
if (it.first == static_cast<int>(i) && it.second.first == "endogenous")
{
found = true;
excluded_vars.push_back(symbol_table.getID(it.second.second));
break;
}
if (!found)
{
set<pair<int, int>> result;
equations[i]->arg1->collectDynamicVariables(SymbolType::endogenous, result);
if (result.size() == 1)
excluded_vars.push_back(result.begin()->first);
else
{
cerr << "ERROR: Equation " << i
<< " has been excluded but does not have a single variable on LHS or `endogenous` tag" << endl;
exit(EXIT_FAILURE);
}
}
}
else
{
new_eqns.emplace_back(equations[i]);
old_eqn_num_2_new[i] = new_eqns.size() - 1;
new_equations_lineno.emplace_back(equations_lineno[i]);
}
int n_excl = equations.size() - new_eqns.size();
equations = new_eqns;
equations_lineno = new_equations_lineno;
equation_tags.erase(remove_if(equation_tags.begin(), equation_tags.end(),
[&](const auto& it) { return eqns.find(it.first) != eqns.end(); }),
equation_tags.end());
for (auto & it : old_eqn_num_2_new)
for (auto & it1 : equation_tags)
if (it1.first == it.first)
it1.first = it.second;
equation_tags_xref.clear();
for (const auto & it : equation_tags)
equation_tags_xref.emplace(it.second, it.first);
if (!static_equations)
for (size_t i = 0; i < excluded_vars.size(); i++)
for (size_t j = i+1; j < excluded_vars.size(); j++)
if (excluded_vars[i] == excluded_vars[j])
{
cerr << "Error: Variable " << symbol_table.getName(i) << " was excluded twice"
<< " via in/exclude_eqs option" << endl;
exit(EXIT_FAILURE);
}
cout << "Excluded " << n_excl << (static_equations ? " static " : " dynamic ")
<< "equation" << (n_excl > 1 ? "s" : "" ) << " via in/exclude_eqs option" << endl;
return excluded_vars;
}
void void
ModelTree::simplifyEquations() ModelTree::simplifyEquations()
{ {

View File

@ -75,13 +75,10 @@ protected:
*/ */
//! Stores declared and generated auxiliary equations //! Stores declared and generated auxiliary equations
vector<BinaryOpNode *> equations; vector<BinaryOpNode *> equations;
//! Stores line numbers of declared equations; -1 means undefined //! Stores line numbers of declared equations; -1 means undefined
vector<int> equations_lineno; vector<int> equations_lineno;
//! Stores equation tags //! Stores equation tags
vector<pair<int, pair<string, string>>> equation_tags; vector<pair<int, pair<string, string>>> equation_tags;
//! Stores mapping from equation tags to equation number //! Stores mapping from equation tags to equation number
multimap<pair<string, string>, int> equation_tags_xref; multimap<pair<string, string>, int> equation_tags_xref;
/* /*
@ -262,6 +259,11 @@ protected:
void printBlockDecomposition(const vector<pair<int, int>> &blocks) const; void printBlockDecomposition(const vector<pair<int, int>> &blocks) const;
//! Determine for each block if it is linear or not //! Determine for each block if it is linear or not
vector<bool> BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vector<int> &variable_reordered) const; vector<bool> BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vector<int> &variable_reordered) const;
//! Remove equations specified by exclude_eqs
vector<int> includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
vector<pair<int, pair<string, string>>> &equation_tags,
multimap<pair<string, string>, int> &equation_tags_xref, bool static_equations) const;
//! Determine the simulation type of each block //! Determine the simulation type of each block
virtual BlockSimulationType getBlockSimulationType(int block_number) const = 0; virtual BlockSimulationType getBlockSimulationType(int block_number) const = 0;
@ -348,6 +350,8 @@ public:
void addEquation(expr_t eq, int lineno); void addEquation(expr_t eq, int lineno);
//! Declare a node as an equation of the model, also giving its tags //! Declare a node as an equation of the model, also giving its tags
void addEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags); void addEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
//! Add equation tags to equation tag table
void addEquationTagsToTable(const vector<pair<string, string>> &eq_tags);
//! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations //! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations
void addAuxEquation(expr_t eq); void addAuxEquation(expr_t eq);
//! Returns the number of equations in the model //! Returns the number of equations in the model

View File

@ -148,12 +148,25 @@ InitOrEndValStatement::writeInitValues(ostream &output) const
SymbolType type = symbol_table.getType(symb_id); SymbolType type = symbol_table.getType(symb_id);
int tsid = symbol_table.getTypeSpecificID(symb_id) + 1; int tsid = symbol_table.getTypeSpecificID(symb_id) + 1;
if (type == SymbolType::endogenous) switch (type)
{
case SymbolType::endogenous:
output << "oo_.steady_state"; output << "oo_.steady_state";
else if (type == SymbolType::exogenous) break;
case SymbolType::exogenous:
output << "oo_.exo_steady_state"; output << "oo_.exo_steady_state";
else if (type == SymbolType::exogenousDet) break;
case SymbolType::exogenousDet:
output << "oo_.exo_det_steady_state"; output << "oo_.exo_det_steady_state";
break;
case SymbolType::excludedVariable:
cerr << "ERROR: Variable `" << symbol_table.getName(symb_id)
<< "` was excluded but found in an initval or endval statement" << endl;
exit(EXIT_FAILURE);
default:
cerr << "Should not arrive here" << endl;
exit(EXIT_FAILURE);
}
output << "( " << tsid << " ) = "; output << "( " << tsid << " ) = ";
expression->writeOutput(output); expression->writeOutput(output);