rework equation tags
Create new EquationTags class to simplify use of equation tags throughout the code and avoid repeated code issue #38issue#70
parent
28b98c7c0e
commit
7371558321
|
@ -103,7 +103,6 @@ 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},
|
||||||
|
@ -166,7 +165,6 @@ 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;
|
||||||
|
@ -2907,7 +2905,8 @@ DynamicModel::writeDynamicJacobianNonZeroElts(const string &basename) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_eq_tags, set<pair<string, string>> &eq_tag_set, bool exclude_eqs)
|
DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_eq_tags,
|
||||||
|
set<pair<string, string>> &eq_tag_set, bool exclude_eqs)
|
||||||
{
|
{
|
||||||
string tags;
|
string tags;
|
||||||
if (filesystem::exists(inc_exc_eq_tags))
|
if (filesystem::exists(inc_exc_eq_tags))
|
||||||
|
@ -3010,24 +3009,13 @@ DynamicModel::includeExcludeEquations(const string &eqs, bool exclude_eqs)
|
||||||
vector<int> excluded_vars
|
vector<int> excluded_vars
|
||||||
= ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
|
= ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
|
||||||
equations, equations_lineno,
|
equations, equations_lineno,
|
||||||
equation_tags, equation_tags_xref, false);
|
equation_tags, 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
|
// Ignore output because variables are not excluded when equations marked 'static' are excluded
|
||||||
ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
|
ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
|
||||||
static_only_equations, static_only_equations_lineno,
|
static_only_equations, static_only_equations_lineno,
|
||||||
tmp_static_only_equation_tags,
|
static_only_equations_equation_tags, true);
|
||||||
static_only_equation_tags_xref, true);
|
|
||||||
if (!eq_tag_set.empty())
|
if (!eq_tag_set.empty())
|
||||||
{
|
{
|
||||||
cerr << "ERROR: " << (exclude_eqs ? "exclude_eqs" : "include_eqs") << ": The equations specified by `";
|
cerr << "ERROR: " << (exclude_eqs ? "exclude_eqs" : "include_eqs") << ": The equations specified by `";
|
||||||
|
@ -3045,17 +3033,6 @@ DynamicModel::includeExcludeEquations(const string &eqs, bool exclude_eqs)
|
||||||
exit(EXIT_FAILURE);
|
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
|
// Collect list of used variables in updated list of equations
|
||||||
set<pair<int, int>> eqn_vars;
|
set<pair<int, int>> eqn_vars;
|
||||||
for (const auto &eqn : equations)
|
for (const auto &eqn : equations)
|
||||||
|
@ -3180,42 +3157,10 @@ DynamicModel::writeOutput(ostream &output, const string &basename, bool block_de
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write equation tags
|
// Write equation tags
|
||||||
if (julia)
|
equation_tags.writeOutput(output, modstruct, julia);
|
||||||
{
|
|
||||||
output << modstruct << "equation_tags = [" << endl;
|
|
||||||
for (const auto &equation_tag : equation_tags)
|
|
||||||
output << " EquationTag("
|
|
||||||
<< equation_tag.first + 1 << R"( , ")"
|
|
||||||
<< equation_tag.second.first << R"(" , ")"
|
|
||||||
<< equation_tag.second.second << R"("))" << endl;
|
|
||||||
output << " ]" << endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output << modstruct << "equations_tags = {" << endl;
|
|
||||||
for (const auto &equation_tag : equation_tags)
|
|
||||||
output << " " << equation_tag.first + 1 << " , '"
|
|
||||||
<< equation_tag.second.first << "' , '"
|
|
||||||
<< equation_tag.second.second << "' ;" << endl;
|
|
||||||
output << "};" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write Occbin tags
|
// Write Occbin tags
|
||||||
map<int, vector<pair<string, string>>> occbin_options;
|
equation_tags.writeOccbinOutput(output, modstruct, julia);
|
||||||
for (const auto &[eqn, tag] : equation_tags)
|
|
||||||
if (tag.first == "pswitch"
|
|
||||||
|| tag.first == "bind"
|
|
||||||
|| tag.first == "relax"
|
|
||||||
|| tag.first == "pcrit")
|
|
||||||
occbin_options[eqn].push_back(tag);
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
for (const auto &[eqn, tags] : occbin_options)
|
|
||||||
{
|
|
||||||
idx++;
|
|
||||||
for (const auto &[tag_name, tag_value] : tags)
|
|
||||||
output << "M_.occbin.constraint(" << idx << ")." << tag_name << " = '" << tag_value << "';" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write mapping for variables and equations they are present in
|
// Write mapping for variables and equations they are present in
|
||||||
for (const auto &variable : variableMapping)
|
for (const auto &variable : variableMapping)
|
||||||
|
@ -4071,16 +4016,8 @@ DynamicModel::fillVarModelTable() const
|
||||||
|
|
||||||
for (const auto &eqtag : it.second)
|
for (const auto &eqtag : it.second)
|
||||||
{
|
{
|
||||||
int eqn = -1;
|
|
||||||
set<pair<int, int>> lhs_set, lhs_tmp_set, rhs_set;
|
set<pair<int, int>> lhs_set, lhs_tmp_set, rhs_set;
|
||||||
for (const auto &equation_tag : equation_tags)
|
int eqn = equation_tags.getEqnByTag("name", eqtag);
|
||||||
if (equation_tag.second.first == "name"
|
|
||||||
&& equation_tag.second.second == eqtag)
|
|
||||||
{
|
|
||||||
eqn = equation_tag.first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eqn == -1)
|
if (eqn == -1)
|
||||||
{
|
{
|
||||||
cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl;
|
cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl;
|
||||||
|
@ -4243,15 +4180,7 @@ DynamicModel::fillTrendComponentModelTable() const
|
||||||
vector<int> trend_eqnumber;
|
vector<int> trend_eqnumber;
|
||||||
for (const auto &eqtag : it.second)
|
for (const auto &eqtag : it.second)
|
||||||
{
|
{
|
||||||
int eqn = -1;
|
int eqn = equation_tags.getEqnByTag("name", eqtag);
|
||||||
for (const auto &equation_tag : equation_tags)
|
|
||||||
if (equation_tag.second.first == "name"
|
|
||||||
&& equation_tag.second.second == eqtag)
|
|
||||||
{
|
|
||||||
eqn = equation_tag.first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eqn == -1)
|
if (eqn == -1)
|
||||||
{
|
{
|
||||||
cerr << "ERROR: trend equation tag '" << eqtag << "' not found" << endl;
|
cerr << "ERROR: trend equation tag '" << eqtag << "' not found" << endl;
|
||||||
|
@ -4270,16 +4199,8 @@ DynamicModel::fillTrendComponentModelTable() const
|
||||||
|
|
||||||
for (const auto &eqtag : it.second)
|
for (const auto &eqtag : it.second)
|
||||||
{
|
{
|
||||||
int eqn = -1;
|
|
||||||
set<pair<int, int>> lhs_set, lhs_tmp_set, rhs_set;
|
set<pair<int, int>> lhs_set, lhs_tmp_set, rhs_set;
|
||||||
for (const auto &equation_tag : equation_tags)
|
int eqn = equation_tags.getEqnByTag("name", eqtag);
|
||||||
if (equation_tag.second.first == "name"
|
|
||||||
&& equation_tag.second.second == eqtag)
|
|
||||||
{
|
|
||||||
eqn = equation_tag.first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eqn == -1)
|
if (eqn == -1)
|
||||||
{
|
{
|
||||||
cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl;
|
cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl;
|
||||||
|
@ -4636,14 +4557,7 @@ DynamicModel::walkPacParameters(const string &name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string eqtag;
|
string eqtag = equation_tags.getTagValueByEqnAndKey(&equation - &equations[0], "name");
|
||||||
for (auto &tag : equation_tags)
|
|
||||||
if (tag.first == (&equation - &equations[0]))
|
|
||||||
if (tag.second.first == "name")
|
|
||||||
{
|
|
||||||
eqtag = tag.second.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (eqtag.empty())
|
if (eqtag.empty())
|
||||||
{
|
{
|
||||||
cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
|
cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
|
||||||
|
@ -4686,14 +4600,7 @@ DynamicModel::getPacMaxLag(const string &pac_model_name, map<pair<string, string
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
string eqtag;
|
string eqtag = equation_tags.getTagValueByEqnAndKey(&equation - &equations[0], "name");
|
||||||
for (auto &tag : equation_tags)
|
|
||||||
if (tag.first == (&equation - &equations[0]))
|
|
||||||
if (tag.second.first == "name")
|
|
||||||
{
|
|
||||||
eqtag = tag.second.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
string eq = eqtag_and_lag[{pac_model_name, eqtag}].first;
|
string eq = eqtag_and_lag[{pac_model_name, eqtag}].first;
|
||||||
eqtag_and_lag[{pac_model_name, eqtag}] = {eq, equation->PacMaxLag(endogs.begin()->first)};
|
eqtag_and_lag[{pac_model_name, eqtag}] = {eq, equation->PacMaxLag(endogs.begin()->first)};
|
||||||
}
|
}
|
||||||
|
@ -4731,15 +4638,7 @@ DynamicModel::declarePacModelConsistentExpectationEndogs(const string &name)
|
||||||
for (auto &equation : equations)
|
for (auto &equation : equations)
|
||||||
if (equation->containsPacExpectation())
|
if (equation->containsPacExpectation())
|
||||||
{
|
{
|
||||||
string eqtag;
|
if (!equation_tags.exists(&equation - &equations[0], "name"))
|
||||||
for (auto &tag : equation_tags)
|
|
||||||
if (tag.first == (&equation - &equations[0]))
|
|
||||||
if (tag.second.first == "name")
|
|
||||||
{
|
|
||||||
eqtag = tag.second.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (eqtag.empty())
|
|
||||||
{
|
{
|
||||||
cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
|
cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -4934,15 +4833,13 @@ DynamicModel::substitutePacExpectation(const string &pac_model_name)
|
||||||
for (auto &it : pac_expectation_substitution)
|
for (auto &it : pac_expectation_substitution)
|
||||||
if (it.first.first == pac_model_name)
|
if (it.first.first == pac_model_name)
|
||||||
for (auto &equation : equations)
|
for (auto &equation : equations)
|
||||||
for (auto & [tagged_eq, tag_pair] : equation_tags)
|
if (equation_tags.exists(&equation - &equations[0], "name", it.first.second))
|
||||||
if (tagged_eq == (&equation - &equations[0])
|
{
|
||||||
&& tag_pair.first == "name" && tag_pair.second == it.first.second)
|
auto substeq = dynamic_cast<BinaryOpNode *>(equation->substitutePacExpectation(pac_model_name, it.second));
|
||||||
{
|
assert(substeq);
|
||||||
auto substeq = dynamic_cast<BinaryOpNode *>(equation->substitutePacExpectation(pac_model_name, it.second));
|
equation = substeq;
|
||||||
assert(substeq);
|
break;
|
||||||
equation = substeq;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -5536,7 +5433,6 @@ DynamicModel::clearEquations()
|
||||||
equations.clear();
|
equations.clear();
|
||||||
equations_lineno.clear();
|
equations_lineno.clear();
|
||||||
equation_tags.clear();
|
equation_tags.clear();
|
||||||
equation_tags_xref.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -5548,7 +5444,6 @@ DynamicModel::replaceMyEquations(DynamicModel &dynamic_model) const
|
||||||
dynamic_model.addEquation(equations[i]->clone(dynamic_model), equations_lineno[i]);
|
dynamic_model.addEquation(equations[i]->clone(dynamic_model), equations_lineno[i]);
|
||||||
|
|
||||||
dynamic_model.equation_tags = equation_tags;
|
dynamic_model.equation_tags = equation_tags;
|
||||||
dynamic_model.equation_tags_xref = equation_tags_xref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -5623,7 +5518,7 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model)
|
||||||
(i.e. a FOC identical to an equation of the original model) */
|
(i.e. a FOC identical to an equation of the original model) */
|
||||||
vector<expr_t> neweqs;
|
vector<expr_t> neweqs;
|
||||||
vector<int> neweqs_lineno;
|
vector<int> neweqs_lineno;
|
||||||
map<int, vector<pair<string, string>>> neweqs_tags;
|
map<int, map<string, string>> neweqs_tags;
|
||||||
for (auto &[symb_id_and_lag, deriv_id] : deriv_id_table)
|
for (auto &[symb_id_and_lag, deriv_id] : deriv_id_table)
|
||||||
{
|
{
|
||||||
auto &[symb_id, lag] = symb_id_and_lag;
|
auto &[symb_id, lag] = symb_id_and_lag;
|
||||||
|
@ -5635,10 +5530,10 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model)
|
||||||
{
|
{
|
||||||
// This is a derivative w.r.t. a Lagrange multiplier
|
// This is a derivative w.r.t. a Lagrange multiplier
|
||||||
neweqs_lineno.push_back(old_equations_lineno[i]);
|
neweqs_lineno.push_back(old_equations_lineno[i]);
|
||||||
vector<pair<string, string>> tags;
|
map<string, string> tags;
|
||||||
for (auto &[j, tagpair] : old_equation_tags)
|
auto tmp = old_equation_tags.getTagsByEqn(i);
|
||||||
if (j == i)
|
for (const auto &[key, value] : tmp)
|
||||||
tags.emplace_back(tagpair);
|
tags[key] = value;
|
||||||
neweqs_tags[neweqs.size()-1] = tags;
|
neweqs_tags[neweqs.size()-1] = tags;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -5686,30 +5581,20 @@ DynamicModel::createVariableMapping(int orig_eq_nbr)
|
||||||
void
|
void
|
||||||
DynamicModel::expandEqTags()
|
DynamicModel::expandEqTags()
|
||||||
{
|
{
|
||||||
set<int> existing_tags;
|
set<int> existing_tags = equation_tags.getEqnsByKey("name");
|
||||||
for (const auto &eqn : equation_tags)
|
|
||||||
if (eqn.second.first == "name")
|
|
||||||
existing_tags.insert(eqn.first);
|
|
||||||
|
|
||||||
for (int eq = 0; eq < static_cast<int>(equations.size()); eq++)
|
for (int eq = 0; eq < static_cast<int>(equations.size()); eq++)
|
||||||
if (existing_tags.find(eq) == existing_tags.end())
|
if (existing_tags.find(eq) == existing_tags.end())
|
||||||
if (auto lhs_expr = dynamic_cast<VariableNode *>(equations[eq]->arg1); lhs_expr && equation_tags_xref.find({ "name", symbol_table.getName(lhs_expr->symb_id)}) == equation_tags_xref.end())
|
if (auto lhs_expr = dynamic_cast<VariableNode *>(equations[eq]->arg1);
|
||||||
{
|
lhs_expr
|
||||||
equation_tags.emplace_back(eq, pair("name", symbol_table.getName(lhs_expr->symb_id)));
|
&& !equation_tags.exists("name", symbol_table.getName(lhs_expr->symb_id)))
|
||||||
equation_tags_xref.emplace(pair("name", symbol_table.getName(lhs_expr->symb_id)), eq);
|
equation_tags.add(eq, "name", symbol_table.getName(lhs_expr->symb_id));
|
||||||
}
|
else if (!equation_tags.exists("name", to_string(eq+1)))
|
||||||
else if (equation_tags_xref.find({ "name", to_string(eq+1) }) == equation_tags_xref.end())
|
equation_tags.add(eq, "name", to_string(eq+1));
|
||||||
{
|
|
||||||
equation_tags.emplace_back(eq, pair("name", to_string(eq+1)));
|
|
||||||
equation_tags_xref.emplace(pair("name", to_string(eq+1)), eq);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cerr << "Error creating default equation tag: cannot assign default tag to equation number " << eq+1 << " because it is already in use" << endl;
|
cerr << "Error creating default equation tag: cannot assign default tag to equation number " << eq+1 << " because it is already in use" << endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
sort(equation_tags.begin(), equation_tags.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set<int>
|
set<int>
|
||||||
|
@ -6459,39 +6344,32 @@ DynamicModel::substituteAdl()
|
||||||
equation = dynamic_cast<BinaryOpNode *>(equation->substituteAdl());
|
equation = dynamic_cast<BinaryOpNode *>(equation->substituteAdl());
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<int>
|
set<int>
|
||||||
DynamicModel::getEquationNumbersFromTags(const set<string> &eqtags) const
|
DynamicModel::getEquationNumbersFromTags(const set<string> &eqtags) const
|
||||||
{
|
{
|
||||||
vector<int> eqnumbers;
|
set<int> eqnumbers;
|
||||||
for (auto &eqtag : eqtags)
|
for (auto &eqtag : eqtags)
|
||||||
{
|
{
|
||||||
bool found = false;
|
set<int> tmp = equation_tags.getEqnsByTag("name", eqtag);
|
||||||
for (const auto &equation_tag : equation_tags)
|
if (tmp.empty())
|
||||||
if (equation_tag.second.first == "name"
|
|
||||||
&& equation_tag.second.second == eqtag)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
eqnumbers.push_back(equation_tag.first);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
{
|
{
|
||||||
cerr << "ERROR: looking for equation tag " << eqtag << " failed." << endl;
|
cerr << "ERROR: looking for equation tag " << eqtag << " failed." << endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
eqnumbers.insert(tmp.begin(), tmp.end());
|
||||||
}
|
}
|
||||||
return eqnumbers;
|
return eqnumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DynamicModel::findPacExpectationEquationNumbers(vector<int> &eqnumbers) const
|
DynamicModel::findPacExpectationEquationNumbers(set<int> &eqnumbers) const
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto &equation : equations)
|
for (auto &equation : equations)
|
||||||
{
|
{
|
||||||
if (equation->containsPacExpectation()
|
if (equation->containsPacExpectation()
|
||||||
&& find(eqnumbers.begin(), eqnumbers.end(), i) == eqnumbers.end())
|
&& find(eqnumbers.begin(), eqnumbers.end(), i) == eqnumbers.end())
|
||||||
eqnumbers.push_back(i);
|
eqnumbers.insert(i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6507,9 +6385,10 @@ DynamicModel::substituteUnaryOps()
|
||||||
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
|
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
|
||||||
DynamicModel::substituteUnaryOps(const set<string> &var_model_eqtags)
|
DynamicModel::substituteUnaryOps(const set<string> &var_model_eqtags)
|
||||||
{
|
{
|
||||||
vector<int> eqnumbers = getEquationNumbersFromTags(var_model_eqtags);
|
set<int> eqnumbers = getEquationNumbersFromTags(var_model_eqtags);
|
||||||
findPacExpectationEquationNumbers(eqnumbers);
|
findPacExpectationEquationNumbers(eqnumbers);
|
||||||
return substituteUnaryOps(eqnumbers);
|
vector<int> eqnumbers_vec(eqnumbers.begin(), eqnumbers.end());
|
||||||
|
return substituteUnaryOps(eqnumbers_vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
|
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
|
||||||
|
@ -6751,21 +6630,14 @@ DynamicModel::isModelLocalVariableUsed() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DynamicModel::addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags)
|
DynamicModel::addStaticOnlyEquation(expr_t eq, int lineno, const map<string, string> &eq_tags)
|
||||||
{
|
{
|
||||||
auto beq = dynamic_cast<BinaryOpNode *>(eq);
|
auto beq = dynamic_cast<BinaryOpNode *>(eq);
|
||||||
assert(beq && beq->op_code == BinaryOpcode::equal);
|
assert(beq && beq->op_code == BinaryOpcode::equal);
|
||||||
|
|
||||||
vector<pair<string, string>> soe_eq_tags;
|
static_only_equations_equation_tags.add(static_only_equations.size(), eq_tags);
|
||||||
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.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);
|
|
||||||
for (auto &it : soe_eq_tags)
|
|
||||||
static_only_equation_tags_xref.emplace(it, n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
@ -6777,13 +6649,7 @@ DynamicModel::staticOnlyEquationsNbr() const
|
||||||
size_t
|
size_t
|
||||||
DynamicModel::dynamicOnlyEquationsNbr() const
|
DynamicModel::dynamicOnlyEquationsNbr() const
|
||||||
{
|
{
|
||||||
set<int> eqs;
|
return equation_tags.getDynamicEqns().size();
|
||||||
|
|
||||||
for (const auto &equation_tag : equation_tags)
|
|
||||||
if (equation_tag.second.first == "dynamic")
|
|
||||||
eqs.insert(equation_tag.first);
|
|
||||||
|
|
||||||
return eqs.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -6792,10 +6658,7 @@ DynamicModel::isChecksumMatching(const string &basename, bool block) const
|
||||||
stringstream buffer;
|
stringstream buffer;
|
||||||
|
|
||||||
// Write equation tags
|
// Write equation tags
|
||||||
for (const auto &equation_tag : equation_tags)
|
equation_tags.writeCheckSumInfo(buffer);
|
||||||
buffer << " " << equation_tag.first + 1
|
|
||||||
<< equation_tag.second.first
|
|
||||||
<< equation_tag.second.second << endl;
|
|
||||||
|
|
||||||
ExprNodeOutputType buffer_type = block ? ExprNodeOutputType::matlabDynamicModelSparse : ExprNodeOutputType::CDynamicModel;
|
ExprNodeOutputType buffer_type = block ? ExprNodeOutputType::matlabDynamicModelSparse : ExprNodeOutputType::CDynamicModel;
|
||||||
|
|
||||||
|
@ -6866,24 +6729,7 @@ DynamicModel::writeJsonAST(ostream &output) const
|
||||||
output << R"({ "number":)" << eq
|
output << R"({ "number":)" << eq
|
||||||
<< R"(, "line":)" << equations_lineno[eq];
|
<< R"(, "line":)" << equations_lineno[eq];
|
||||||
|
|
||||||
for (const auto &equation_tag : equation_tags)
|
equation_tags.writeJsonAST(output, eq);
|
||||||
if (equation_tag.first == eq)
|
|
||||||
eqtags.push_back(equation_tag.second);
|
|
||||||
|
|
||||||
if (!eqtags.empty())
|
|
||||||
{
|
|
||||||
output << R"(, "tags": {)";
|
|
||||||
int i = 0;
|
|
||||||
for (const auto &[name, value] : eqtags)
|
|
||||||
{
|
|
||||||
if (i != 0)
|
|
||||||
output << ", ";
|
|
||||||
output << R"(")" << name << R"(": ")" << value << R"(")";
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
output << "}";
|
|
||||||
eqtags.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
output << R"(, "AST": )";
|
output << R"(, "AST": )";
|
||||||
equations[eq]->writeJsonAST(output);
|
equations[eq]->writeJsonAST(output);
|
||||||
|
@ -6904,9 +6750,8 @@ DynamicModel::writeJsonVariableMapping(ostream &output) const
|
||||||
int it = 0;
|
int it = 0;
|
||||||
int end_idx_eq = static_cast<int>(variable.second.size())-1;
|
int end_idx_eq = static_cast<int>(variable.second.size())-1;
|
||||||
for (const auto &equation : variable.second)
|
for (const auto &equation : variable.second)
|
||||||
for (const auto &equation_tag : equation_tags)
|
if (auto tmp = equation_tags.getTagValueByEqnAndKey(equation, "name"); !tmp.empty())
|
||||||
if (equation_tag.first == equation && equation_tag.second.first == "name")
|
output << R"(")" << tmp << (it++ == end_idx_eq ? R"("])" : R"(", )");
|
||||||
output << R"(")" << equation_tag.second.second << (it++ == end_idx_eq ? R"("])" : R"(", )");
|
|
||||||
output << (ii++ == end_idx_map ? R"(})" : R"(},)") << endl;
|
output << (ii++ == end_idx_map ? R"(})" : R"(},)") << endl;
|
||||||
}
|
}
|
||||||
output << "]";
|
output << "]";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright © 2003-2019 Dynare Team
|
* Copyright © 2003-2020 Dynare Team
|
||||||
*
|
*
|
||||||
* This file is part of Dynare.
|
* This file is part of Dynare.
|
||||||
*
|
*
|
||||||
|
@ -54,10 +54,7 @@ private:
|
||||||
vector<int> static_only_equations_lineno;
|
vector<int> static_only_equations_lineno;
|
||||||
|
|
||||||
//! 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;
|
EquationTags 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
|
||||||
|
@ -260,9 +257,9 @@ private:
|
||||||
//! Create a legacy *_dynamic.m file for Matlab/Octave not yet using the temporary terms array interface
|
//! Create a legacy *_dynamic.m file for Matlab/Octave not yet using the temporary terms array interface
|
||||||
void writeDynamicMatlabCompatLayer(const string &basename) const;
|
void writeDynamicMatlabCompatLayer(const string &basename) const;
|
||||||
|
|
||||||
vector<int> getEquationNumbersFromTags(const set<string> &eqtags) const;
|
set<int> getEquationNumbersFromTags(const set<string> &eqtags) const;
|
||||||
|
|
||||||
void findPacExpectationEquationNumbers(vector<int> &eqnumber) const;
|
void findPacExpectationEquationNumbers(set<int> &eqnumber) const;
|
||||||
|
|
||||||
//! Internal helper for the copy constructor and assignment operator
|
//! Internal helper for the copy constructor and assignment operator
|
||||||
/*! Copies all the structures that contain ExprNode*, by the converting the
|
/*! Copies all the structures that contain ExprNode*, by the converting the
|
||||||
|
@ -452,7 +449,7 @@ public:
|
||||||
void replaceMyEquations(DynamicModel &dynamic_model) const;
|
void replaceMyEquations(DynamicModel &dynamic_model) const;
|
||||||
|
|
||||||
//! Adds an equation marked as [static]
|
//! Adds an equation marked as [static]
|
||||||
void addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
|
void addStaticOnlyEquation(expr_t eq, int lineno, const map<string, string> &eq_tags);
|
||||||
|
|
||||||
//! Returns number of static only equations
|
//! Returns number of static only equations
|
||||||
size_t staticOnlyEquationsNbr() const;
|
size_t staticOnlyEquationsNbr() const;
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EquationTags.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
set<int>
|
||||||
|
EquationTags::getEqnsByKey(const string &key) const
|
||||||
|
{
|
||||||
|
set<int> retval;
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
if (tags.find(key) != tags.end())
|
||||||
|
retval.insert(eqn);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
set<int>
|
||||||
|
EquationTags::getEqnsByTag(const string &key, const string &value) const
|
||||||
|
{
|
||||||
|
set<int> retval;
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
if (auto tmp = tags.find(key); tmp != tags.end() && tmp->second == value)
|
||||||
|
retval.insert(eqn);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
EquationTags::getEqnByTag(const string &key, const string &value) const
|
||||||
|
{
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
if (auto tmp = tags.find(key); tmp != tags.end() && tmp->second == value)
|
||||||
|
return eqn;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EquationTags::erase(const set<int> &eqns, const map<int, int> &old_eqn_num_2_new)
|
||||||
|
{
|
||||||
|
for (const auto &eqn : eqns)
|
||||||
|
eqn_tags.erase(eqn);
|
||||||
|
|
||||||
|
for (const auto & [oldeqn, neweqn] : old_eqn_num_2_new)
|
||||||
|
for (auto & [eqn, tags] : eqn_tags)
|
||||||
|
if (eqn == oldeqn)
|
||||||
|
{
|
||||||
|
auto tmp = eqn_tags.extract(eqn);
|
||||||
|
tmp.key() = neweqn;
|
||||||
|
eqn_tags.insert(move(tmp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EquationTags::writeCheckSumInfo(ostream &output) const
|
||||||
|
{
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
for (const auto & [key, value] : tags)
|
||||||
|
output << " " << eqn + 1
|
||||||
|
<< key << " " << value << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EquationTags::writeOutput(ostream &output, const string &modstruct, bool julia) const
|
||||||
|
{
|
||||||
|
if (julia)
|
||||||
|
{
|
||||||
|
output << modstruct << "equation_tags = [" << endl;
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
for (const auto & [key, value] : tags)
|
||||||
|
output << " EquationTag("
|
||||||
|
<< eqn + 1 << R"( , ")"
|
||||||
|
<< key << R"(" , ")" << value << R"("))" << endl;
|
||||||
|
output << " ]" << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output << modstruct << "equations_tags = {" << endl;
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
{
|
||||||
|
for (const auto & [key, value] : tags)
|
||||||
|
output << " " << eqn + 1 << " , '"
|
||||||
|
<< key << "' , '" << value << "' ;" << endl;
|
||||||
|
}
|
||||||
|
output << "};" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EquationTags::writeOccbinOutput(ostream &output, const string &modstruct, bool julia) const
|
||||||
|
{
|
||||||
|
if (julia)
|
||||||
|
return;
|
||||||
|
|
||||||
|
map<int, map<string, string>> occbin_options;
|
||||||
|
for (const auto & [eqn, tags] : eqn_tags)
|
||||||
|
for (const auto & [key, value] : tags)
|
||||||
|
if (key == "pswitch"
|
||||||
|
|| key == "bind"
|
||||||
|
|| key == "relax"
|
||||||
|
|| key == "pcrit")
|
||||||
|
occbin_options[eqn][key] = value;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (const auto & [eqn, tags] : occbin_options)
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
for (const auto & [key, value] : tags)
|
||||||
|
output << modstruct << "occbin.constraint(" << idx << ")."
|
||||||
|
<< key << " = '" << value << "';" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EquationTags::writeLatexOutput(ostream &output, int eqn) const
|
||||||
|
{
|
||||||
|
if (!exists(eqn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto escape_special_latex_symbols
|
||||||
|
= [](string str)
|
||||||
|
{
|
||||||
|
const regex special_latex_chars (R"([&%$#_{}])");
|
||||||
|
const regex backslash (R"(\\)");
|
||||||
|
const regex tilde (R"(~)");
|
||||||
|
const regex carrot (R"(\^)");
|
||||||
|
const regex textbackslash (R"(\\textbackslash)");
|
||||||
|
str = regex_replace(str, backslash, R"(\textbackslash)");
|
||||||
|
str = regex_replace(str, special_latex_chars, R"(\$&)");
|
||||||
|
str = regex_replace(str, carrot, R"(\^{})");
|
||||||
|
str = regex_replace(str, tilde, R"(\textasciitilde{})");
|
||||||
|
return regex_replace(str, textbackslash, R"(\textbackslash{})");
|
||||||
|
};
|
||||||
|
|
||||||
|
bool wrote_eq_tag = false;
|
||||||
|
output << R"(\noindent[)";
|
||||||
|
for (const auto & [key, value] : eqn_tags.at(eqn))
|
||||||
|
{
|
||||||
|
if (wrote_eq_tag)
|
||||||
|
output << ", ";
|
||||||
|
output << escape_special_latex_symbols(key);
|
||||||
|
|
||||||
|
if (!value.empty())
|
||||||
|
output << "= `" << escape_special_latex_symbols(value) << "'";
|
||||||
|
|
||||||
|
wrote_eq_tag = true;
|
||||||
|
}
|
||||||
|
output << "]" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EquationTags::writeJsonAST(ostream &output, const int eqn) const
|
||||||
|
{
|
||||||
|
if (!exists(eqn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
output << R"(, "tags": {)";
|
||||||
|
bool wroteFirst = false;
|
||||||
|
for (const auto &[key, value] : eqn_tags.at(eqn))
|
||||||
|
{
|
||||||
|
if (wroteFirst)
|
||||||
|
output << ", ";
|
||||||
|
else
|
||||||
|
wroteFirst = true;
|
||||||
|
output << R"(")" << key << R"(": ")" << value << R"(")";
|
||||||
|
}
|
||||||
|
output << "}";
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _EQUATION_TAGS_HH
|
||||||
|
#define _EQUATION_TAGS_HH
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class EquationTags
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
map<int, map<string, string>> eqn_tags;
|
||||||
|
public:
|
||||||
|
// Add multiple equatoin tags for the given equation
|
||||||
|
inline void add(int eqn, map<string, string> tags)
|
||||||
|
{
|
||||||
|
if (eqn_tags.find(eqn) == eqn_tags.end())
|
||||||
|
eqn_tags[eqn] = move(tags);
|
||||||
|
else
|
||||||
|
eqn_tags[eqn].insert(tags.begin(), tags.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Add a single equation tag for the given equation
|
||||||
|
inline void add(int eqn, string key, string value)
|
||||||
|
{
|
||||||
|
eqn_tags[eqn][move(key)] = move(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Clear all equation tag information
|
||||||
|
inline void clear()
|
||||||
|
{
|
||||||
|
eqn_tags.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Erase tags for given equations, using old_eqn_num_2_new as the mapping
|
||||||
|
//! to use for the remaining equation numbers
|
||||||
|
void erase(const set<int> &eqns, const map<int, int> &old_eqn_num_2_new);
|
||||||
|
|
||||||
|
//! Various functions to get info from equation tags
|
||||||
|
//! Get equation tags for a given equation
|
||||||
|
inline map<string, string> getTagsByEqn(const int eqn) const
|
||||||
|
{
|
||||||
|
if (eqn_tags.find(eqn) != eqn_tags.end())
|
||||||
|
return eqn_tags.find(eqn)->second;
|
||||||
|
return map<string, string>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get equations that have the given key
|
||||||
|
set<int> getEqnsByKey(const string &key) const;
|
||||||
|
|
||||||
|
//! Get equations that have the given key and value
|
||||||
|
set<int> getEqnsByTag(const string &key, const string &value) const;
|
||||||
|
|
||||||
|
//! Get the first equation that has the given key and value
|
||||||
|
int getEqnByTag(const string &key, const string &value) const;
|
||||||
|
|
||||||
|
//! Get the tag value given the equation number and key
|
||||||
|
inline string getTagValueByEqnAndKey(const int eqn, const string &key) const
|
||||||
|
{
|
||||||
|
return exists(eqn, key) ? eqn_tags.at(eqn).at(key) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the equations marked dynamic
|
||||||
|
inline set<int> getDynamicEqns() const
|
||||||
|
{
|
||||||
|
return getEqnsByTag("dynamic", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns true if equation tag with key and value exists
|
||||||
|
inline bool exists(const string &key, const string &value) const
|
||||||
|
{
|
||||||
|
return getEqnByTag(key, value) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool exists(const int eqn) const
|
||||||
|
{
|
||||||
|
return eqn_tags.find(eqn) != eqn_tags.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns true if equation tag with key exists for a given equation
|
||||||
|
inline bool exists(const int eqn, const string &key) const
|
||||||
|
{
|
||||||
|
return exists(eqn) ? eqn_tags.at(eqn).find(key) != eqn_tags.at(eqn).end() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns true if equation tag with key and value exists for a given equation
|
||||||
|
inline bool exists(const int eqn, const string &key, const string &value) const
|
||||||
|
{
|
||||||
|
return exists(eqn, key) ? eqn_tags.at(eqn).at(key) == value : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Various functions to write equation tags
|
||||||
|
void writeCheckSumInfo(ostream &output) const;
|
||||||
|
void writeOutput(ostream &output, const string &modstruct, bool julia) const;
|
||||||
|
void writeOccbinOutput(ostream &output, const string &modstruct, bool julia) const;
|
||||||
|
void writeLatexOutput(ostream &output, int eqn) const;
|
||||||
|
void writeJsonAST(ostream &output, const int eq) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -10,6 +10,8 @@ dynare_m_SOURCES = \
|
||||||
DynareBison.yy \
|
DynareBison.yy \
|
||||||
ComputingTasks.cc \
|
ComputingTasks.cc \
|
||||||
ComputingTasks.hh \
|
ComputingTasks.hh \
|
||||||
|
EquationTags.cc \
|
||||||
|
EquationTags.hh \
|
||||||
ModelTree.cc \
|
ModelTree.cc \
|
||||||
ModelTree.hh \
|
ModelTree.hh \
|
||||||
StaticModel.cc \
|
StaticModel.cc \
|
||||||
|
|
|
@ -111,7 +111,6 @@ ModelTree::ModelTree(const ModelTree &m) :
|
||||||
user_set_compiler{m.user_set_compiler},
|
user_set_compiler{m.user_set_compiler},
|
||||||
equations_lineno{m.equations_lineno},
|
equations_lineno{m.equations_lineno},
|
||||||
equation_tags{m.equation_tags},
|
equation_tags{m.equation_tags},
|
||||||
equation_tags_xref{m.equation_tags_xref},
|
|
||||||
computed_derivs_order{m.computed_derivs_order},
|
computed_derivs_order{m.computed_derivs_order},
|
||||||
NNZDerivatives{m.NNZDerivatives},
|
NNZDerivatives{m.NNZDerivatives},
|
||||||
equation_reordered{m.equation_reordered},
|
equation_reordered{m.equation_reordered},
|
||||||
|
@ -138,7 +137,6 @@ ModelTree::operator=(const ModelTree &m)
|
||||||
equations_lineno = m.equations_lineno;
|
equations_lineno = m.equations_lineno;
|
||||||
aux_equations.clear();
|
aux_equations.clear();
|
||||||
equation_tags = m.equation_tags;
|
equation_tags = m.equation_tags;
|
||||||
equation_tags_xref = m.equation_tags_xref;
|
|
||||||
computed_derivs_order = m.computed_derivs_order;
|
computed_derivs_order = m.computed_derivs_order;
|
||||||
NNZDerivatives = m.NNZDerivatives;
|
NNZDerivatives = m.NNZDerivatives;
|
||||||
|
|
||||||
|
@ -1857,41 +1855,7 @@ ModelTree::writeLatexModelFile(const string &mod_basename, const string &latex_b
|
||||||
{
|
{
|
||||||
content_output << "% Equation " << eq + 1 << endl;
|
content_output << "% Equation " << eq + 1 << endl;
|
||||||
if (write_equation_tags)
|
if (write_equation_tags)
|
||||||
{
|
equation_tags.writeLatexOutput(content_output, eq);
|
||||||
auto escape_special_latex_symbols
|
|
||||||
= [](string str)
|
|
||||||
{
|
|
||||||
const regex special_latex_chars (R"([&%$#_{}])");
|
|
||||||
const regex backslash (R"(\\)");
|
|
||||||
const regex tilde (R"(~)");
|
|
||||||
const regex carrot (R"(\^)");
|
|
||||||
const regex textbackslash (R"(\\textbackslash)");
|
|
||||||
str = regex_replace(str, backslash, R"(\textbackslash)");
|
|
||||||
str = regex_replace(str, special_latex_chars, R"(\$&)");
|
|
||||||
str = regex_replace(str, carrot, R"(\^{})");
|
|
||||||
str = regex_replace(str, tilde, R"(\textasciitilde{})");
|
|
||||||
return regex_replace(str, textbackslash, R"(\textbackslash{})");
|
|
||||||
};
|
|
||||||
bool wrote_eq_tag = false;
|
|
||||||
for (const auto & [tagged_eq, tag_pair] : equation_tags)
|
|
||||||
if (tagged_eq == eq)
|
|
||||||
{
|
|
||||||
if (!wrote_eq_tag)
|
|
||||||
content_output << R"(\noindent[)";
|
|
||||||
else
|
|
||||||
content_output << ", ";
|
|
||||||
|
|
||||||
content_output << escape_special_latex_symbols(tag_pair.first);
|
|
||||||
|
|
||||||
if (!(tag_pair.second.empty()))
|
|
||||||
content_output << "= `" << escape_special_latex_symbols(tag_pair.second) << "'";
|
|
||||||
|
|
||||||
wrote_eq_tag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wrote_eq_tag)
|
|
||||||
content_output << "]" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
content_output << R"(\begin{dmath})" << endl;
|
content_output << R"(\begin{dmath})" << endl;
|
||||||
// Here it is necessary to cast to superclass ExprNode, otherwise the overloaded writeOutput() method is not found
|
// Here it is necessary to cast to superclass ExprNode, otherwise the overloaded writeOutput() method is not found
|
||||||
|
@ -1919,8 +1883,7 @@ ModelTree::addEquation(expr_t eq, int lineno)
|
||||||
vector<int>
|
vector<int>
|
||||||
ModelTree::includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
|
ModelTree::includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
|
||||||
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
|
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
|
||||||
vector<pair<int, pair<string, string>>> &equation_tags,
|
EquationTags &equation_tags, bool static_equations) const
|
||||||
multimap<pair<string, string>, int> &equation_tags_xref, bool static_equations) const
|
|
||||||
{
|
{
|
||||||
vector<int> excluded_vars;
|
vector<int> excluded_vars;
|
||||||
if (equations.empty())
|
if (equations.empty())
|
||||||
|
@ -1929,12 +1892,12 @@ ModelTree::includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_
|
||||||
// Get equation numbers of tags
|
// Get equation numbers of tags
|
||||||
set<int> tag_eqns;
|
set<int> tag_eqns;
|
||||||
for (auto &it : eqs)
|
for (auto &it : eqs)
|
||||||
if (equation_tags_xref.find(it) != equation_tags_xref.end())
|
if (auto tmp = equation_tags.getEqnsByTag(it.first, it.second); !tmp.empty())
|
||||||
{
|
{
|
||||||
auto range = equation_tags_xref.equal_range(it);
|
tag_eqns.insert(tmp.begin(), tmp.end());
|
||||||
for_each(range.first, range.second, [&tag_eqns](auto &x) { tag_eqns.insert(x.second); });
|
|
||||||
eqs.erase(it);
|
eqs.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag_eqns.empty())
|
if (tag_eqns.empty())
|
||||||
return excluded_vars;
|
return excluded_vars;
|
||||||
|
|
||||||
|
@ -1946,23 +1909,16 @@ ModelTree::includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_
|
||||||
if (tag_eqns.find(i) == tag_eqns.end())
|
if (tag_eqns.find(i) == tag_eqns.end())
|
||||||
eqns.insert(i);
|
eqns.insert(i);
|
||||||
|
|
||||||
// remove from equations, equations_lineno, equation_tags, equation_tags_xref
|
// remove from equations, equations_lineno, equation_tags
|
||||||
vector<BinaryOpNode *> new_eqns;
|
vector<BinaryOpNode *> new_eqns;
|
||||||
vector<int> new_equations_lineno;
|
vector<int> new_equations_lineno;
|
||||||
map<int, int> old_eqn_num_2_new;
|
map<int, int> old_eqn_num_2_new;
|
||||||
for (size_t i = 0; i < equations.size(); i++)
|
for (size_t i = 0; i < equations.size(); i++)
|
||||||
if (eqns.find(i) != eqns.end())
|
if (eqns.find(i) != eqns.end())
|
||||||
{
|
{
|
||||||
bool found = false;
|
if (auto tmp = equation_tags.getTagValueByEqnAndKey(i, "endogenous"); !tmp.empty())
|
||||||
for (const auto & [tagged_eq, tag_pair] : equation_tags)
|
|
||||||
if (tagged_eq == static_cast<int>(i) && tag_pair.first == "endogenous")
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
excluded_vars.push_back(symbol_table.getID(tag_pair.second));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
{
|
{
|
||||||
|
excluded_vars.push_back(symbol_table.getID(tmp));
|
||||||
set<pair<int, int>> result;
|
set<pair<int, int>> result;
|
||||||
equations[i]->arg1->collectDynamicVariables(SymbolType::endogenous, result);
|
equations[i]->arg1->collectDynamicVariables(SymbolType::endogenous, result);
|
||||||
if (result.size() == 1)
|
if (result.size() == 1)
|
||||||
|
@ -1986,17 +1942,7 @@ ModelTree::includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_
|
||||||
equations = new_eqns;
|
equations = new_eqns;
|
||||||
equations_lineno = new_equations_lineno;
|
equations_lineno = new_equations_lineno;
|
||||||
|
|
||||||
equation_tags.erase(remove_if(equation_tags.begin(), equation_tags.end(),
|
equation_tags.erase(eqns, old_eqn_num_2_new);
|
||||||
[&](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)
|
if (!static_equations)
|
||||||
for (size_t i = 0; i < excluded_vars.size(); i++)
|
for (size_t i = 0; i < excluded_vars.size(); i++)
|
||||||
|
@ -2040,14 +1986,9 @@ ModelTree::findConstantEquationsWithoutTags(map<VariableNode *, NumConstNode *>
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelTree::addEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags)
|
ModelTree::addEquation(expr_t eq, int lineno, const map<string, string> &eq_tags)
|
||||||
{
|
{
|
||||||
int n = equations.size();
|
equation_tags.add(equations.size(), eq_tags);
|
||||||
for (const auto &eq_tag : eq_tags)
|
|
||||||
{
|
|
||||||
equation_tags.emplace_back(n, eq_tag);
|
|
||||||
equation_tags_xref.emplace(eq_tag, n);
|
|
||||||
}
|
|
||||||
addEquation(eq, lineno);
|
addEquation(eq, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ using namespace std;
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "DataTree.hh"
|
#include "DataTree.hh"
|
||||||
|
#include "EquationTags.hh"
|
||||||
#include "ExtendedPreprocessorTypes.hh"
|
#include "ExtendedPreprocessorTypes.hh"
|
||||||
|
|
||||||
// Helper to convert a vector into a tuple
|
// Helper to convert a vector into a tuple
|
||||||
|
@ -87,9 +88,7 @@ protected:
|
||||||
//! 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;
|
EquationTags equation_tags;
|
||||||
//! Stores mapping from equation tags to equation number
|
|
||||||
multimap<pair<string, string>, int> equation_tags_xref;
|
|
||||||
/*
|
/*
|
||||||
* ************** END **************
|
* ************** END **************
|
||||||
*/
|
*/
|
||||||
|
@ -274,8 +273,7 @@ protected:
|
||||||
//! Remove equations specified by exclude_eqs
|
//! Remove equations specified by exclude_eqs
|
||||||
vector<int> includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
|
vector<int> includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
|
||||||
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
|
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
|
||||||
vector<pair<int, pair<string, string>>> &equation_tags,
|
EquationTags &equation_tags, bool static_equations) const;
|
||||||
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;
|
||||||
|
@ -361,7 +359,7 @@ public:
|
||||||
//! Declare a node as an equation of the model; also give its line number
|
//! Declare a node as an equation of the model; also give its line number
|
||||||
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 map<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
|
||||||
|
@ -394,11 +392,7 @@ public:
|
||||||
inline map<string, string>
|
inline map<string, string>
|
||||||
getEquationTags(int eq) const
|
getEquationTags(int eq) const
|
||||||
{
|
{
|
||||||
map<string, string> r;
|
return equation_tags.getTagsByEqn(eq);
|
||||||
for (auto &[eq2, tagpair] : equation_tags)
|
|
||||||
if (eq2 == eq)
|
|
||||||
r[tagpair.first] = tagpair.second;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static string
|
inline static string
|
||||||
|
|
|
@ -296,7 +296,7 @@ ParsingDriver::add_predetermined_variable(const string &name)
|
||||||
void
|
void
|
||||||
ParsingDriver::add_equation_tags(string key, string value)
|
ParsingDriver::add_equation_tags(string key, string value)
|
||||||
{
|
{
|
||||||
eq_tags.emplace_back(key, value);
|
eq_tags[key] = value;
|
||||||
|
|
||||||
transform(key.begin(), key.end(), key.begin(), ::tolower);
|
transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||||
if (key.compare("endogenous") == 0)
|
if (key.compare("endogenous") == 0)
|
||||||
|
@ -2494,15 +2494,7 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2)
|
||||||
expr_t id = model_tree->AddEqual(arg1, arg2);
|
expr_t id = model_tree->AddEqual(arg1, arg2);
|
||||||
|
|
||||||
// Detect if the equation is tagged [static]
|
// Detect if the equation is tagged [static]
|
||||||
bool is_static_only = false;
|
if (eq_tags.find("static") != eq_tags.end())
|
||||||
for (auto &eq_tag : eq_tags)
|
|
||||||
if (eq_tag.first == "static")
|
|
||||||
{
|
|
||||||
is_static_only = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_static_only)
|
|
||||||
{
|
{
|
||||||
if (!id->isInStaticForm())
|
if (!id->isInStaticForm())
|
||||||
error("An equation tagged [static] cannot contain leads, lags, expectations or STEADY_STATE operators");
|
error("An equation tagged [static] cannot contain leads, lags, expectations or STEADY_STATE operators");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright © 2003-2019 Dynare Team
|
* Copyright © 2003-2020 Dynare Team
|
||||||
*
|
*
|
||||||
* This file is part of Dynare.
|
* This file is part of Dynare.
|
||||||
*
|
*
|
||||||
|
@ -248,7 +248,7 @@ private:
|
||||||
//! For parsing the graph_format option
|
//! For parsing the graph_format option
|
||||||
SymbolList graph_formats;
|
SymbolList graph_formats;
|
||||||
//! Temporary storage for equation tags
|
//! Temporary storage for equation tags
|
||||||
vector<pair<string, string>> eq_tags;
|
map<string, string> eq_tags;
|
||||||
|
|
||||||
//! Map Var name to variables
|
//! Map Var name to variables
|
||||||
map<string, vector<string>> var_map;
|
map<string, vector<string>> var_map;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright © 2003-2019 Dynare Team
|
* Copyright © 2003-2020 Dynare Team
|
||||||
*
|
*
|
||||||
* This file is part of Dynare.
|
* This file is part of Dynare.
|
||||||
*
|
*
|
||||||
|
@ -159,38 +159,32 @@ StaticModel::StaticModel(const DynamicModel &m) :
|
||||||
|
|
||||||
// Convert equations
|
// Convert equations
|
||||||
int static_only_index = 0;
|
int static_only_index = 0;
|
||||||
|
set<int> dynamic_equations = m.equation_tags.getDynamicEqns();
|
||||||
for (int i = 0; i < static_cast<int>(m.equations.size()); i++)
|
for (int i = 0; i < static_cast<int>(m.equations.size()); i++)
|
||||||
{
|
try
|
||||||
// Detect if equation is marked [dynamic]
|
{
|
||||||
bool is_dynamic_only = false;
|
// If equation is dynamic, replace it by an equation marked [static]
|
||||||
vector<pair<string, string>> eq_tags;
|
if (dynamic_equations.find(i) != dynamic_equations.end())
|
||||||
for (const auto & [tagged_eq, tag_pair] : m.equation_tags)
|
|
||||||
if (tagged_eq == i)
|
|
||||||
{
|
{
|
||||||
eq_tags.push_back(tag_pair);
|
auto [static_only_equations,
|
||||||
if (tag_pair.first == "dynamic")
|
static_only_equations_lineno,
|
||||||
is_dynamic_only = true;
|
static_only_equations_equation_tags] = m.getStaticOnlyEquationsInfo();
|
||||||
|
|
||||||
|
addEquation(static_only_equations[static_only_index]->toStatic(*this),
|
||||||
|
static_only_equations_lineno[static_only_index],
|
||||||
|
static_only_equations_equation_tags.getTagsByEqn(static_only_index));
|
||||||
|
static_only_index++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
try
|
addEquation(m.equations[i]->toStatic(*this),
|
||||||
{
|
m.equations_lineno[i],
|
||||||
// If yes, replace it by an equation marked [static]
|
m.equation_tags.getTagsByEqn(i));
|
||||||
if (is_dynamic_only)
|
}
|
||||||
{
|
catch (DataTree::DivisionByZeroException)
|
||||||
auto [static_only_equations, static_only_equations_lineno, static_only_equations_equation_tags] = m.getStaticOnlyEquationsInfo();
|
{
|
||||||
|
cerr << "...division by zero error encountred when converting equation " << i << " to static" << endl;
|
||||||
addEquation(static_only_equations[static_only_index]->toStatic(*this), static_only_equations_lineno[static_only_index], static_only_equations_equation_tags[static_only_index]);
|
exit(EXIT_FAILURE);
|
||||||
static_only_index++;
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
addEquation(m.equations[i]->toStatic(*this), m.equations_lineno[i], eq_tags);
|
|
||||||
}
|
|
||||||
catch (DataTree::DivisionByZeroException)
|
|
||||||
{
|
|
||||||
cerr << "...division by zero error encountred when converting equation " << i << " to static" << endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert auxiliary equations
|
// Convert auxiliary equations
|
||||||
for (auto aux_eq : m.aux_equations)
|
for (auto aux_eq : m.aux_equations)
|
||||||
|
|
Loading…
Reference in New Issue