Merge branch 'exclude_eqs' into 'master'
introduce command line options: `exclude_eqs` and `include_eqs` See merge request Dynare/preprocessor!7issue#70
commit
8be9efa425
|
@ -150,7 +150,8 @@ enum class SymbolType
|
|||
logTrend = 15, //!< Log-trend variable
|
||||
unusedEndogenous = 16, //!< Type to mark unused endogenous variables when `nostrict` option is passed
|
||||
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
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <regex>
|
||||
|
||||
#include "DynamicModel.hh"
|
||||
|
||||
|
@ -103,6 +104,7 @@ DynamicModel::DynamicModel(const DynamicModel &m) :
|
|||
balanced_growth_test_tol {m.balanced_growth_test_tol},
|
||||
static_only_equations_lineno {m.static_only_equations_lineno},
|
||||
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},
|
||||
inv_deriv_id_table {m.inv_deriv_id_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_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;
|
||||
inv_deriv_id_table = m.inv_deriv_id_table;
|
||||
dyn_jacobian_cols_table = m.dyn_jacobian_cols_table;
|
||||
|
@ -2930,6 +2933,179 @@ DynamicModel::writeDynamicJacobianNonZeroElts(const string &basename) const
|
|||
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
|
||||
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;
|
||||
for (auto & eqtag : eqtags)
|
||||
for (const auto & equation_tag : equation_tags)
|
||||
if (equation_tag.second.first == "name"
|
||||
&& equation_tag.second.second == eqtag)
|
||||
{
|
||||
bool found = false;
|
||||
for (const auto & equation_tag : equation_tags)
|
||||
if (equation_tag.second.first == "name"
|
||||
&& equation_tag.second.second == eqtag)
|
||||
{
|
||||
found = true;
|
||||
eqnumbers.push_back(equation_tag.first);
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
eqnumbers.push_back(equation_tag.first);
|
||||
break;
|
||||
cerr << "ERROR: looking for equation tag " << eqtag << " failed." << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
return eqnumbers;
|
||||
}
|
||||
|
||||
|
@ -6618,9 +6803,12 @@ DynamicModel::addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<str
|
|||
for (const auto & eq_tag : eq_tags)
|
||||
soe_eq_tags.push_back(eq_tag);
|
||||
|
||||
int n = static_only_equations.size();
|
||||
static_only_equations.push_back(beq);
|
||||
static_only_equations_lineno.push_back(lineno);
|
||||
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
|
||||
|
|
|
@ -56,6 +56,9 @@ private:
|
|||
//! Stores the equation tags of equations declared as [static]
|
||||
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>;
|
||||
//! Maps a pair (symbol_id, lag) to a deriv ID
|
||||
deriv_id_table_t deriv_id_table;
|
||||
|
@ -266,6 +269,32 @@ private:
|
|||
pointers into their equivalent in the new tree */
|
||||
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:
|
||||
DynamicModel(SymbolTable &symbol_table_arg,
|
||||
NumericalConstants &num_constants_arg,
|
||||
|
@ -397,6 +426,9 @@ public:
|
|||
//! Set the max leads/lags of the original model
|
||||
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
|
||||
void computeRamseyPolicyFOCs(const StaticModel &static_model);
|
||||
//! Replaces the model equations in dynamic_model with those in this model
|
||||
|
|
|
@ -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,
|
||||
bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
|
||||
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,
|
||||
const string &mexext, const filesystem::path &matlabroot,
|
||||
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]"
|
||||
<< " [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]"
|
||||
<< " [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]"
|
||||
<< " [mexext=<extension>] [matlabroot=<path>] [onlymodel]"
|
||||
<< endl;
|
||||
|
@ -154,6 +155,7 @@ main(int argc, char **argv)
|
|||
bool minimal_workspace = false;
|
||||
bool compute_xrefs = false;
|
||||
bool transform_unary_ops = false;
|
||||
string exclude_eqs, include_eqs;
|
||||
vector<pair<string, string>> defines;
|
||||
vector<filesystem::path> paths;
|
||||
FileOutputType output_mode{FileOutputType::none};
|
||||
|
@ -371,6 +373,24 @@ main(int argc, char **argv)
|
|||
}
|
||||
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")
|
||||
{
|
||||
if (s.length() <= 11 || s.at(10) != '=')
|
||||
|
@ -418,11 +438,17 @@ main(int argc, char **argv)
|
|||
if (only_macro)
|
||||
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
|
||||
main2(macro_output, basename, debug, clear_all, clear_global,
|
||||
no_tmp_terms, no_log, no_warn, warn_uninit, console, nograph, nointeractive,
|
||||
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,
|
||||
mexext, matlabroot, dynareroot, onlymodel);
|
||||
|
||||
|
|
|
@ -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,
|
||||
bool minimal_workspace, bool compute_xrefs, FileOutputType output_mode,
|
||||
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,
|
||||
const string &mexext, const filesystem::path &matlabroot,
|
||||
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);
|
||||
|
||||
// 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)
|
||||
mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);
|
||||
|
||||
|
|
|
@ -839,6 +839,11 @@ VariableNode::prepareForDerivation()
|
|||
case SymbolType::epilogue:
|
||||
cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
|
||||
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::endogenousVAR:
|
||||
case SymbolType::epilogue:
|
||||
case SymbolType::excludedVariable:
|
||||
cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -939,6 +945,9 @@ VariableNode::writeJsonAST(ostream &output) const
|
|||
case SymbolType::epilogue:
|
||||
output << "epilogue";
|
||||
break;
|
||||
case SymbolType::excludedVariable:
|
||||
cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
output << R"(", "lag" : )" << lag << "}";
|
||||
}
|
||||
|
@ -1220,6 +1229,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
|
|||
case SymbolType::logTrend:
|
||||
case SymbolType::statementDeclaredVariable:
|
||||
case SymbolType::endogenousVAR:
|
||||
case SymbolType::excludedVariable:
|
||||
cerr << "VariableNode::writeOutput: Impossible case" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -1439,6 +1449,7 @@ VariableNode::getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recur
|
|||
case SymbolType::externalFunction:
|
||||
case SymbolType::endogenousVAR:
|
||||
case SymbolType::epilogue:
|
||||
case SymbolType::excludedVariable:
|
||||
cerr << "VariableNode::getChainRuleDerivative: Impossible case" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -1478,6 +1489,7 @@ VariableNode::computeXrefs(EquationInfo &ei) const
|
|||
case SymbolType::externalFunction:
|
||||
case SymbolType::endogenousVAR:
|
||||
case SymbolType::epilogue:
|
||||
case SymbolType::excludedVariable:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -381,7 +381,8 @@ ModFile::checkPass(bool nostrict, bool stochastic)
|
|||
}
|
||||
|
||||
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)
|
||||
— 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
|
||||
DataTree:AddDiff()
|
||||
*/
|
||||
dynamic_model.includeExcludeEquations(exclude_eqs, true);
|
||||
dynamic_model.includeExcludeEquations(include_eqs, false);
|
||||
dynamic_model.simplifyEquations();
|
||||
dynamic_model.substituteAdl();
|
||||
dynamic_model.setLeadsLagsOrig();
|
||||
|
|
|
@ -146,7 +146,8 @@ public:
|
|||
void checkPass(bool nostrict, bool stochastic);
|
||||
//! Perform some transformations on the model (creation of auxiliary vars and equations)
|
||||
/*! \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
|
||||
/*! \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 */
|
||||
|
|
|
@ -1934,6 +1934,104 @@ ModelTree::addEquation(expr_t eq, int 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
|
||||
ModelTree::simplifyEquations()
|
||||
{
|
||||
|
|
|
@ -75,13 +75,10 @@ protected:
|
|||
*/
|
||||
//! Stores declared and generated auxiliary equations
|
||||
vector<BinaryOpNode *> equations;
|
||||
|
||||
//! Stores line numbers of declared equations; -1 means undefined
|
||||
vector<int> equations_lineno;
|
||||
|
||||
//! Stores equation tags
|
||||
vector<pair<int, pair<string, string>>> equation_tags;
|
||||
|
||||
//! Stores mapping from equation tags to equation number
|
||||
multimap<pair<string, string>, int> equation_tags_xref;
|
||||
/*
|
||||
|
@ -262,6 +259,11 @@ protected:
|
|||
void printBlockDecomposition(const vector<pair<int, int>> &blocks) const;
|
||||
//! 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;
|
||||
//! 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
|
||||
virtual BlockSimulationType getBlockSimulationType(int block_number) const = 0;
|
||||
|
@ -348,6 +350,8 @@ public:
|
|||
void addEquation(expr_t eq, int lineno);
|
||||
//! 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);
|
||||
//! 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
|
||||
void addAuxEquation(expr_t eq);
|
||||
//! Returns the number of equations in the model
|
||||
|
|
|
@ -148,12 +148,25 @@ InitOrEndValStatement::writeInitValues(ostream &output) const
|
|||
SymbolType type = symbol_table.getType(symb_id);
|
||||
int tsid = symbol_table.getTypeSpecificID(symb_id) + 1;
|
||||
|
||||
if (type == SymbolType::endogenous)
|
||||
output << "oo_.steady_state";
|
||||
else if (type == SymbolType::exogenous)
|
||||
output << "oo_.exo_steady_state";
|
||||
else if (type == SymbolType::exogenousDet)
|
||||
output << "oo_.exo_det_steady_state";
|
||||
switch (type)
|
||||
{
|
||||
case SymbolType::endogenous:
|
||||
output << "oo_.steady_state";
|
||||
break;
|
||||
case SymbolType::exogenous:
|
||||
output << "oo_.exo_steady_state";
|
||||
break;
|
||||
case SymbolType::exogenousDet:
|
||||
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 << " ) = ";
|
||||
expression->writeOutput(output);
|
||||
|
|
Loading…
Reference in New Issue