diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 8678b6e977472231942b9df9b850761179647f8e..f01a5abd63782c43bdf0e18b25ab1df27e55799e 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -5429,28 +5429,29 @@ DynamicModel::substituteAdl() } void -DynamicModel::substituteDiff(StaticModel &static_model, ExprNode::subst_table_t &diff_subst_table) +DynamicModel::substituteUnaryOps(StaticModel &static_model) { - // Find diff Nodes - diff_table_t diff_table; + diff_table_t nodes; + // Find matching unary ops that may be outside of diffs (i.e., those with different lags) for (map<int, expr_t>::iterator it = local_variables_table.begin(); it != local_variables_table.end(); it++) - it->second->findDiffNodes(static_model, diff_table); + it->second->findUnaryOpNodesForAuxVarCreation(static_model, nodes); for (int i = 0; i < (int) equations.size(); i++) - equations[i]->findDiffNodes(static_model, diff_table); + equations[i]->findUnaryOpNodesForAuxVarCreation(static_model, nodes); // Substitute in model local variables + ExprNode::subst_table_t subst_table; vector<BinaryOpNode *> neweqs; for (map<int, expr_t>::iterator it = local_variables_table.begin(); it != local_variables_table.end(); it++) - it->second = it->second->substituteDiff(static_model, diff_table, diff_subst_table, neweqs); + it->second = it->second->substituteUnaryOpNodes(static_model, nodes, subst_table, neweqs); // Substitute in equations for (int i = 0; i < (int) equations.size(); i++) { BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]-> - substituteDiff(static_model, diff_table, diff_subst_table, neweqs)); + substituteUnaryOpNodes(static_model, nodes, subst_table, neweqs)); assert(substeq != NULL); equations[i] = substeq; } @@ -5461,34 +5462,33 @@ DynamicModel::substituteDiff(StaticModel &static_model, ExprNode::subst_table_t copy(neweqs.begin(), neweqs.end(), back_inserter(diff_aux_equations)); - if (diff_subst_table.size() > 0) - cout << "Substitution of Diff operator: added " << neweqs.size() << " auxiliary variables and equations." << endl; + if (subst_table.size() > 0) + cout << "Substitution of Unary Ops: added " << neweqs.size() << " auxiliary variables and equations." << endl; } void -DynamicModel::substituteDiffUnaryOps(StaticModel &static_model) +DynamicModel::substituteDiff(StaticModel &static_model, ExprNode::subst_table_t &diff_subst_table) { // Find diff Nodes - set<UnaryOpNode *> nodes; + diff_table_t diff_table; for (map<int, expr_t>::iterator it = local_variables_table.begin(); it != local_variables_table.end(); it++) - it->second->findDiffUnaryOpNodes(static_model, nodes); + it->second->findDiffNodes(static_model, diff_table); for (int i = 0; i < (int) equations.size(); i++) - equations[i]->findDiffUnaryOpNodes(static_model, nodes); + equations[i]->findDiffNodes(static_model, diff_table); // Substitute in model local variables - ExprNode::subst_table_t subst_table; vector<BinaryOpNode *> neweqs; for (map<int, expr_t>::iterator it = local_variables_table.begin(); it != local_variables_table.end(); it++) - it->second = it->second->substituteDiffUnaryOpNodes(static_model, nodes, subst_table, neweqs); + it->second = it->second->substituteDiff(static_model, diff_table, diff_subst_table, neweqs); // Substitute in equations for (int i = 0; i < (int) equations.size(); i++) { BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]-> - substituteDiffUnaryOpNodes(static_model, nodes, subst_table, neweqs)); + substituteDiff(static_model, diff_table, diff_subst_table, neweqs)); assert(substeq != NULL); equations[i] = substeq; } @@ -5499,8 +5499,8 @@ DynamicModel::substituteDiffUnaryOps(StaticModel &static_model) copy(neweqs.begin(), neweqs.end(), back_inserter(diff_aux_equations)); - if (subst_table.size() > 0) - cout << "Substitution of Unary Ops in Diff operator: added " << neweqs.size() << " auxiliary variables and equations." << endl; + if (diff_subst_table.size() > 0) + cout << "Substitution of Diff operator: added " << neweqs.size() << " auxiliary variables and equations." << endl; } void diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 140c5a5f7c5a0ef1c12e1fa97c9431fa7e251c48..db8634e17a88b987fc94b10bb0fc487c899b520b 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -419,9 +419,11 @@ public: //! Substitutes adl operator void substituteAdl(); + //! Creates aux vars for certain unary operators: originally implemented for support of VARs + void substituteUnaryOps(StaticModel &static_model); + //! Substitutes diff operator void substituteDiff(StaticModel &static_model, ExprNode::subst_table_t &diff_subst_table); - void substituteDiffUnaryOps(StaticModel &static_model); //! Table to undiff LHS variables for pac vector z void getUndiffLHSForPac(vector<int> &lhs, vector<expr_t> &lhs_expr_t, vector<bool> &diff, vector<int> &orig_diff_var, diff --git a/src/DynareMain.cc b/src/DynareMain.cc index 30a3aa16d1ddb0214b755fd9882bf56bc69bc55d..00974428e90c73f9d388890811d1d96324ec4628 100644 --- a/src/DynareMain.cc +++ b/src/DynareMain.cc @@ -41,7 +41,7 @@ void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file, 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 + LanguageOutputType lang, int params_derivs_order, bool transform_unary_ops #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) , bool cygwin, bool msvc, bool mingw #endif @@ -58,7 +58,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=C|C++|julia]" - << " [params_derivs_order=0|1|2]" + << " [params_derivs_order=0|1|2] [transform_unary_ops]" #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) << " [cygwin] [msvc] [mingw]" #endif @@ -114,6 +114,7 @@ main(int argc, char **argv) bool check_model_changes = false; bool minimal_workspace = false; bool compute_xrefs = false; + bool transform_unary_ops = false; map<string, string> defines; vector<string> path; FileOutputType output_mode = none; @@ -210,6 +211,8 @@ main(int argc, char **argv) minimal_workspace = true; else if (!strcmp(argv[arg], "compute_xrefs")) compute_xrefs = true; + else if (!strcmp(argv[arg], "transform_unary_ops")) + transform_unary_ops = true; else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "parallel", 8)) { parallel = true; @@ -401,7 +404,7 @@ main(int argc, char **argv) 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 + compute_xrefs, output_mode, language, params_derivs_order, transform_unary_ops #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) , cygwin, msvc, mingw #endif diff --git a/src/DynareMain2.cc b/src/DynareMain2.cc index d61df45b5039433290c4a67cc0e50dffd0c42276..b5ae53a150395cb75b08e4dbf13f084f47f27600 100644 --- a/src/DynareMain2.cc +++ b/src/DynareMain2.cc @@ -30,7 +30,7 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear bool nograph, bool nointeractive, bool parallel, ConfigFile &config_file, 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 + LanguageOutputType language, int params_derivs_order, bool transform_unary_ops #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) , bool cygwin, bool msvc, bool mingw #endif @@ -51,7 +51,7 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson, nopreprocessoroutput); // Perform transformations on the model (creation of auxiliary vars and equations) - mod_file->transformPass(nostrict, stochastic, compute_xrefs || json == transformpass, nopreprocessoroutput); + mod_file->transformPass(nostrict, stochastic, compute_xrefs || json == transformpass, nopreprocessoroutput, transform_unary_ops); if (json == transformpass) mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson, nopreprocessoroutput); diff --git a/src/ExprNode.cc b/src/ExprNode.cc index f4da2283a890e0eab95fef0003afef3a34df7fd8..15ad3b220a87458a948c346ed28062509a05ed8b 100644 --- a/src/ExprNode.cc +++ b/src/ExprNode.cc @@ -559,7 +559,7 @@ NumConstNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) } void -NumConstNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +NumConstNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { } @@ -570,7 +570,7 @@ NumConstNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table } expr_t -NumConstNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +NumConstNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { return const_cast<NumConstNode *>(this); } @@ -1438,7 +1438,7 @@ VariableNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) } void -VariableNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +VariableNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { } @@ -1450,7 +1450,7 @@ VariableNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table } expr_t -VariableNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +VariableNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { return const_cast<VariableNode *>(this); } @@ -3042,45 +3042,6 @@ UnaryOpNode::isDiffPresent() const return arg->isDiffPresent(); } -void -UnaryOpNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const -{ - if (op_code != oDiff) - { - arg->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); - return; - } - - VariableNode *vn = dynamic_cast<VariableNode *>(arg); - if (vn != NULL) - return; - - UnaryOpNode *sarg = dynamic_cast<UnaryOpNode *>(arg->toStatic(static_datatree)); - if (sarg == NULL || (!sarg->createAuxVarForUnaryOpNodeInDiffOp() && sarg->get_op_code() != oDiff)) - { - cerr << "Error: diff operator can only contain certain unary operations" << endl; - exit(EXIT_FAILURE); - } - - if (unary_op_nodes_in_diff.find(sarg) != unary_op_nodes_in_diff.end()) - return; - - if (sarg->get_op_code() == oDiff) - { - arg->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); - return; - } - - vn = dynamic_cast<VariableNode *>(sarg->get_arg()); - if (vn == NULL) - { - cerr << "Error: A unary op inside of a diff can only take a variable as an argument" << endl; - exit(EXIT_FAILURE); - } - - unary_op_nodes_in_diff.insert(sarg); -} - bool UnaryOpNode::createAuxVarForUnaryOpNodeInDiffOp() const { @@ -3111,6 +3072,30 @@ UnaryOpNode::createAuxVarForUnaryOpNodeInDiffOp() const } } +void +UnaryOpNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const +{ + if (!this->createAuxVarForUnaryOpNodeInDiffOp()) + { + arg->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); + return; + } + + expr_t sthis = this->toStatic(static_datatree); + int arg_max_lag = -arg->maxLag(); + diff_table_t::iterator it = nodes.find(sthis); + if (it != nodes.end()) + { + for (map<int, expr_t>::const_iterator it1 = it->second.begin(); + it1 != it->second.end(); it1++) + if (arg == it1->second) + return; + it->second[arg_max_lag] = const_cast<UnaryOpNode *>(this); + } + else + nodes[sthis][arg_max_lag] = const_cast<UnaryOpNode *>(this); +} + void UnaryOpNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const { @@ -3296,40 +3281,42 @@ UnaryOpNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, } expr_t -UnaryOpNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +UnaryOpNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { - UnaryOpNode *sarg, *argtouse; - if (op_code == oDiff) - { - sarg = dynamic_cast<UnaryOpNode *>(arg->toStatic(static_datatree)); - argtouse = dynamic_cast<UnaryOpNode *>(arg); - } - else - { - sarg = dynamic_cast<UnaryOpNode *>(this->toStatic(static_datatree)); - argtouse = const_cast<UnaryOpNode *>(this); - } + subst_table_t::const_iterator sit = subst_table.find(this); + if (sit != subst_table.end()) + return const_cast<VariableNode *>(sit->second); - if (sarg == NULL || nodes.find(sarg) == nodes.end()) + UnaryOpNode *sthis = dynamic_cast<UnaryOpNode *>(this->toStatic(static_datatree)); + diff_table_t::iterator it = nodes.find(sthis); + if (it == nodes.end()) { - expr_t argsubst = arg->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); + expr_t argsubst = arg->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); return buildSimilarUnaryOpNode(argsubst, datatree); } - subst_table_t::const_iterator sit = subst_table.find(argtouse); - if (sit != subst_table.end()) - return const_cast<VariableNode *>(sit->second); + VariableNode *aux_var = NULL; + for (map<int, expr_t>::reverse_iterator rit = it->second.rbegin(); + rit != it->second.rend(); rit++) + { + if (rit == it->second.rbegin()) + { + VariableNode *vn = dynamic_cast<VariableNode *>(const_cast<UnaryOpNode *>(this)->get_arg()); + int symb_id = datatree.symbol_table.addUnaryOpAuxiliaryVar(this->idx, const_cast<UnaryOpNode *>(this), + vn->get_symb_id(), vn->get_lag()); + aux_var = datatree.AddVariable(symb_id, 0); + neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(aux_var, const_cast<UnaryOpNode *>(this)))); + subst_table[rit->second] = dynamic_cast<VariableNode *>(aux_var); + } + else + { + VariableNode *vn = dynamic_cast<VariableNode *>(dynamic_cast<UnaryOpNode *>(rit->second)->get_arg()); + subst_table[rit->second] = dynamic_cast<VariableNode *>(aux_var->decreaseLeadsLags(-vn->get_lag())); + } + } - VariableNode *vn = dynamic_cast<VariableNode *>(dynamic_cast<UnaryOpNode *>(argtouse)->get_arg()); - int lag = vn->get_lag(); - int symb_id = datatree.symbol_table.addUnaryOpInsideDiffAuxiliaryVar(argtouse->idx, argtouse, - vn->get_symb_id(), lag); - VariableNode *aux_var = datatree.AddVariable(symb_id, 0); - neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(aux_var, argtouse))); - subst_table[argtouse] = dynamic_cast<VariableNode *>(aux_var); - if (op_code == oDiff) - return buildSimilarUnaryOpNode(aux_var, datatree); - return const_cast<VariableNode *>(aux_var); + sit = subst_table.find(this); + return const_cast<VariableNode *>(sit->second); } expr_t @@ -4995,10 +4982,10 @@ BinaryOpNode::substituteAdl() const } void -BinaryOpNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +BinaryOpNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { - arg1->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); - arg2->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); + arg1->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); + arg2->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); } void @@ -5018,10 +5005,10 @@ BinaryOpNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table } expr_t -BinaryOpNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +BinaryOpNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { - expr_t arg1subst = arg1->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); - expr_t arg2subst = arg2->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); + expr_t arg1subst = arg1->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); + expr_t arg2subst = arg2->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); } @@ -5908,11 +5895,11 @@ TrinaryOpNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table } void -TrinaryOpNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +TrinaryOpNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { - arg1->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); - arg2->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); - arg3->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); + arg1->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); + arg2->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); + arg3->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); } expr_t @@ -5926,11 +5913,11 @@ TrinaryOpNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_tabl } expr_t -TrinaryOpNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +TrinaryOpNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { - expr_t arg1subst = arg1->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); - expr_t arg2subst = arg2->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); - expr_t arg3subst = arg3->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); + expr_t arg1subst = arg1->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); + expr_t arg2subst = arg2->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); + expr_t arg3subst = arg3->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs); return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); } @@ -6348,10 +6335,10 @@ AbstractExternalFunctionNode::findDiffNodes(DataTree &static_datatree, diff_tabl } void -AbstractExternalFunctionNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +AbstractExternalFunctionNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++) - (*it)->findDiffUnaryOpNodes(static_datatree, unary_op_nodes_in_diff); + (*it)->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes); } expr_t @@ -6365,11 +6352,11 @@ AbstractExternalFunctionNode::substituteDiff(DataTree &static_datatree, diff_tab } expr_t -AbstractExternalFunctionNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +AbstractExternalFunctionNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { vector<expr_t> arguments_subst; for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++) - arguments_subst.push_back((*it)->substituteDiffUnaryOpNodes(static_datatree, nodes, subst_table, neweqs)); + arguments_subst.push_back((*it)->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs)); return buildSimilarExternalFunctionNode(arguments_subst, datatree); } @@ -7952,7 +7939,7 @@ VarExpectationNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_ } void -VarExpectationNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +VarExpectationNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { } @@ -7964,7 +7951,7 @@ VarExpectationNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff } expr_t -VarExpectationNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +VarExpectationNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { return const_cast<VarExpectationNode *>(this); } @@ -8398,7 +8385,7 @@ PacExpectationNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_ } void -PacExpectationNode::findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const +PacExpectationNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const { } @@ -8410,7 +8397,7 @@ PacExpectationNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff } expr_t -PacExpectationNode::substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const +PacExpectationNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const { return const_cast<PacExpectationNode *>(this); } diff --git a/src/ExprNode.hh b/src/ExprNode.hh index 5527451304b746883a5b9f6a8420542fd1ce988a..e99d8d19b30173145f425b04f502e55d9e6fc904 100644 --- a/src/ExprNode.hh +++ b/src/ExprNode.hh @@ -506,9 +506,9 @@ class ExprNode //! Substitute diff operator virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const = 0; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const = 0; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const = 0; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0; //! Substitute pac_expectation operator virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table) = 0; @@ -603,9 +603,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; @@ -693,9 +693,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; @@ -807,10 +807,10 @@ public: virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; bool createAuxVarForUnaryOpNodeInDiffOp() const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; void getDiffArgUnaryOperatorIfAny(string &op_handle) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; @@ -938,9 +938,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; @@ -1044,9 +1044,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; @@ -1154,9 +1154,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual expr_t buildSimilarExternalFunctionNode(vector<expr_t> &alt_args, DataTree &alt_datatree) const = 0; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; @@ -1351,9 +1351,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<pair<int, pair<expr_t, expr_t> > > &List_of_Op_RHS) const; virtual void compile(ostream &CompileCode, unsigned int &instruction_number, @@ -1436,9 +1436,9 @@ public: virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual expr_t substituteAdl() const; virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const; - virtual void findDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &unary_op_nodes_in_diff) const; + virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const; virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; - virtual expr_t substituteDiffUnaryOpNodes(DataTree &static_datatree, set<UnaryOpNode *> &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; + virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual expr_t substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table); virtual pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<pair<int, pair<expr_t, expr_t> > > &List_of_Op_RHS) const; virtual void compile(ostream &CompileCode, unsigned int &instruction_number, diff --git a/src/ModFile.cc b/src/ModFile.cc index e96fc8868bf6c283f5fe961c963174c532189116..873127df6375c9d7f333f18cf5bb1848ff7246fe 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -347,7 +347,7 @@ ModFile::checkPass(bool nostrict, bool stochastic) } void -ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool nopreprocessoroutput) +ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool nopreprocessoroutput, const bool transform_unary_ops) { // Save the original model (must be done before any model transformations by preprocessor) // - except adl and diff which we always want expanded @@ -366,9 +366,11 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const } } + if (transform_unary_ops) + dynamic_model.substituteUnaryOps(diff_static_model); + // Create auxiliary variable and equations for Diff operator ExprNode::subst_table_t diff_subst_table; - dynamic_model.substituteDiffUnaryOps(diff_static_model); dynamic_model.substituteDiff(diff_static_model, diff_subst_table); // Var Model diff --git a/src/ModFile.hh b/src/ModFile.hh index 08ee6c4213b839a854b705ab1b0acf70e43ae3e1..6664c88b2d1185fef3868a756185879426e20b2b 100644 --- a/src/ModFile.hh +++ b/src/ModFile.hh @@ -136,7 +136,7 @@ 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 nopreprocessoroutput); + void transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const bool nopreprocessoroutput, const bool transform_unary_ops); //! 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 */ diff --git a/src/SymbolTable.cc b/src/SymbolTable.cc index e41eec3596a64081c68b88b288991e7047786ee1..a15460bd5cf9aaf196c07367d25d7f05dc2cf503 100644 --- a/src/SymbolTable.cc +++ b/src/SymbolTable.cc @@ -373,6 +373,7 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException) case avEndoLag: case avExoLag: case avVarModel: + case avUnaryOp: output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; break; @@ -391,7 +392,6 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException) break; case avDiff: case avDiffLag: - case avUnaryOpInsideDiff: if (aux_vars[i].get_orig_symb_id() >= 0) output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; @@ -507,12 +507,12 @@ SymbolTable::writeCOutput(ostream &output) const throw (NotYetFrozenException) case avEndoLag: case avExoLag: case avVarModel: + case avUnaryOp: output << "av[" << i << "].orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id()) << ";" << endl << "av[" << i << "].orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; break; case avDiff: case avDiffLag: - case avUnaryOpInsideDiff: if (aux_vars[i].get_orig_symb_id() >= 0) output << "av[" << i << "].orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id()) << ";" << endl << "av[" << i << "].orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; @@ -607,12 +607,12 @@ SymbolTable::writeCCOutput(ostream &output) const throw (NotYetFrozenException) case avEndoLag: case avExoLag: case avVarModel: + case avUnaryOp: output << "av" << i << ".orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id()) << ";" << endl << "av" << i << ".orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; break; case avDiff: case avDiffLag: - case avUnaryOpInsideDiff: if (aux_vars[i].get_orig_symb_id() >= 0) output << "av" << i << ".orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id()) << ";" << endl << "av" << i << ".orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; @@ -809,12 +809,12 @@ SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg) throw (FrozenExcept } int -SymbolTable::addUnaryOpInsideDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) throw (FrozenException) +SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) throw (FrozenException) { ostringstream varname; int symb_id; - varname << "AUX_UOP_IN_DIFF_" << index; + varname << "AUX_UOP_" << index; try { symb_id = addSymbol(varname.str(), eEndogenous); @@ -825,7 +825,7 @@ SymbolTable::addUnaryOpInsideDiffAuxiliaryVar(int index, expr_t expr_arg, int or exit(EXIT_FAILURE); } - aux_vars.push_back(AuxVarInfo(symb_id, avUnaryOpInsideDiff, orig_symb_id, orig_lag, 0, 0, expr_arg)); + aux_vars.push_back(AuxVarInfo(symb_id, avUnaryOp, orig_symb_id, orig_lag, 0, 0, expr_arg)); return symb_id; } @@ -1157,12 +1157,12 @@ SymbolTable::writeJuliaOutput(ostream &output) const throw (NotYetFrozenExceptio case avEndoLag: case avExoLag: case avVarModel: + case avUnaryOp: output << getTypeSpecificID(aux_vars[i].get_orig_symb_id()) + 1 << ", " << aux_vars[i].get_orig_lead_lag() << ", typemin(Int), string()"; break; case avDiff: case avDiffLag: - case avUnaryOpInsideDiff: if (aux_vars[i].get_orig_symb_id() >= 0) output << getTypeSpecificID(aux_vars[i].get_orig_symb_id()) + 1 << ", " << aux_vars[i].get_orig_lead_lag() << ", typemin(Int), string(), " << aux_vars[i].get_unary_op_handle(); diff --git a/src/SymbolTable.hh b/src/SymbolTable.hh index b1f41c1fea0389df8924e7704eb6326cf12e9ecf..1649f96349cc70f3a2eb1858db3ce26ae5f5b0cf 100644 --- a/src/SymbolTable.hh +++ b/src/SymbolTable.hh @@ -36,17 +36,17 @@ typedef class ExprNode *expr_t; //! Types of auxiliary variables enum aux_var_t { - avEndoLead = 0, //!< Substitute for endo leads >= 2 - avEndoLag = 1, //!< Substitute for endo lags >= 2 - avExoLead = 2, //!< Substitute for exo leads >= 1 - avExoLag = 3, //!< Substitute for exo lags >= 1 - avExpectation = 4, //!< Substitute for Expectation Operator - avDiffForward = 5, //!< Substitute for the differentiate of a forward variable - avMultiplier = 6, //!< Multipliers for FOC of Ramsey Problem - avVarModel = 7, //!< Variable for var_model with order > abs(min_lag()) present in model - avDiff = 8, //!< Variable for Diff operator - avDiffLag = 9, //!< Variable for timing between Diff operators - avUnaryOpInsideDiff = 10 //!< Variable for allowing the undiff operator to work when diff was taken of unary op, eg diff(log(x)) + avEndoLead = 0, //!< Substitute for endo leads >= 2 + avEndoLag = 1, //!< Substitute for endo lags >= 2 + avExoLead = 2, //!< Substitute for exo leads >= 1 + avExoLag = 3, //!< Substitute for exo lags >= 1 + avExpectation = 4, //!< Substitute for Expectation Operator + avDiffForward = 5, //!< Substitute for the differentiate of a forward variable + avMultiplier = 6, //!< Multipliers for FOC of Ramsey Problem + avVarModel = 7, //!< Variable for var_model with order > abs(min_lag()) present in model + avDiff = 8, //!< Variable for Diff operator + avDiffLag = 9, //!< Variable for timing between Diff operators + avUnaryOp = 10 //!< Variable for allowing the undiff operator to work when diff was taken of unary op, eg diff(log(x)) }; //! Information on some auxiliary variables @@ -301,8 +301,8 @@ public: int addDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag, string &unary_op_handle) throw (FrozenException); //! Takes care of timing between diff statements int addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) throw (FrozenException); - //! An Auxiliary variable for a unary op that was substituted because it was inside a diff node - int addUnaryOpInsideDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) throw (FrozenException); + //! An Auxiliary variable for a unary op + int addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) throw (FrozenException); //! Returns the number of auxiliary variables int AuxVarsSize() const