From 915bea91a101ba009f30387d02cc3c1cbd0d9698 Mon Sep 17 00:00:00 2001 From: Houtan Bastani Date: Mon, 20 Feb 2017 12:18:11 +0100 Subject: [PATCH] preprocessor: output JSON after different steps, write static, dynamic, params derivs files in JSON. #1387 --- ComputingTasks.cc | 36 ++-- DynamicModel.cc | 302 +++++++++++++++++++++++++++++- DynamicModel.hh | 6 + DynareMain.cc | 29 ++- DynareMain2.cc | 17 +- ExprNode.cc | 350 +++++++++++++++++++++++++++++++---- ExprNode.hh | 52 ++++-- ExtendedPreprocessorTypes.hh | 9 + ModFile.cc | 141 +++++++++++++- ModFile.hh | 5 +- ModelTree.cc | 177 ++++++++++++++++-- ModelTree.hh | 6 +- NumericalInitialization.cc | 10 +- Shocks.cc | 10 +- StaticModel.cc | 284 ++++++++++++++++++++++++++++ StaticModel.hh | 8 +- SymbolTable.cc | 2 +- 17 files changed, 1328 insertions(+), 116 deletions(-) diff --git a/ComputingTasks.cc b/ComputingTasks.cc index db2ac624..f750b9b6 100644 --- a/ComputingTasks.cc +++ b/ComputingTasks.cc @@ -509,7 +509,7 @@ RamseyConstraintsStatement::writeJsonOutput(ostream &output) const exit(1); } output << " "; - it->expression->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->expression->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}" << endl; } output << "]" << endl; @@ -1170,23 +1170,23 @@ EstimatedParamsStatement::writeJsonOutput(ostream &output) const } output << ", \"init_val\": \""; - it->init_val->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->init_val->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"lower_bound\": \""; - it->low_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"upper_bound\": \""; - it->up_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"prior_distribution\": " << it->prior << ", \"mean\": \""; - it->mean->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->mean->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"std\": \""; - it->std->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->std->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"p3\": \""; - it->p3->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->p3->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"p4\": \""; - it->p4->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->p4->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \"jscale\": \""; - it->jscale->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->jscale->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}" << endl; } output << "]" @@ -1297,7 +1297,7 @@ EstimatedParamsInitStatement::writeJsonOutput(ostream &output) const break; } output << ", \"init_val\": \""; - it->init_val->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->init_val->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" @@ -1417,9 +1417,9 @@ EstimatedParamsBoundsStatement::writeJsonOutput(ostream &output) const break; } output << ", \"lower_bound\": "; - it->low_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << ", \"upper_bound\": "; - it->up_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "}"; } output << "]" @@ -1470,7 +1470,7 @@ ObservationTrendsStatement::writeJsonOutput(ostream &output) const if (printed) output << ", "; output << "\"" << it->first << "\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"" << endl; printed = true; } @@ -1571,9 +1571,9 @@ OsrParamsBoundsStatement::writeJsonOutput(ostream &output) const output << ", "; output << "{\"parameter\": \"" << it->name << "\"," << "\"bounds\": [\""; - it->low_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\", \""; - it->up_bound->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"]" << "}"; } @@ -1699,7 +1699,7 @@ OptimWeightsStatement::writeJsonOutput(ostream &output) const output << ", "; output << "{\"name\": \"" << it->first << "\"" << ", \"value\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } @@ -1711,7 +1711,7 @@ OptimWeightsStatement::writeJsonOutput(ostream &output) const output << "{\"name1\": \"" << it->first.first << "\"" << ", \"name2\": \"" << it->first.second << "\"" << ", \"value\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" @@ -3504,7 +3504,7 @@ BasicPriorStatement::writeJsonPriorOutput(ostream &output) const { deriv_node_temp_terms_t tef_terms; output << ", \"variance\": \""; - variance->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + variance->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\""; } if (options_list.getNumberOfOptions()) diff --git a/DynamicModel.cc b/DynamicModel.cc index 704592da..edcc5f3a 100644 --- a/DynamicModel.cc +++ b/DynamicModel.cc @@ -5341,5 +5341,305 @@ DynamicModel::writeCCOutput(ostream &output, const string &basename, bool block_ void DynamicModel::writeJsonOutput(ostream &output) const { - writeJsonModelEquations(output); + writeJsonModelEquations(output, false); +} + +void +DynamicModel::writeJsonComputingPassOutput(ostream &output) const +{ + ostringstream model_local_vars_output; // Used for storing model local vars + ostringstream model_output; // Used for storing model temp vars and equations + ostringstream jacobian_output; // Used for storing jacobian equations + ostringstream hessian_output; // Used for storing Hessian equations + ostringstream third_derivatives_output; // Used for storing third order derivatives equations + + deriv_node_temp_terms_t tef_terms; + temporary_terms_t temp_term_empty; + temporary_terms_t temp_term_union = temporary_terms_res; + temporary_terms_t temp_term_union_m_1; + + string concat = ""; + int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr; + + writeJsonModelLocalVariables(model_local_vars_output, tef_terms); + + writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat); + + writeJsonModelEquations(model_output, true); + + // Writing Jacobian + temp_term_union_m_1 = temp_term_union; + temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end()); + concat = "jacobian"; + writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat); + jacobian_output << ", \"jacobian\": {" + << " \"nrows\": " << equations.size() + << ", \"ncols\": " << dynJacobianColsNbr + << ", \"entries\": ["; + for (first_derivatives_t::const_iterator it = first_derivatives.begin(); + it != first_derivatives.end(); it++) + { + if (it != first_derivatives.begin()) + jacobian_output << ", "; + + int eq = it->first.first; + string var = symbol_table.getName(getSymbIDByDerivID(it->first.second)); + int lag = getLagByDerivID(it->first.second); + expr_t d1 = it->second; + + jacobian_output << "{\"eq\": " << eq + << ", \"var\": \"" << var << "\"" + << ", \"lag\": " << lag + << ", \"val\": \""; + d1->writeJsonOutput(jacobian_output, temp_term_union, tef_terms); + jacobian_output << "\"}" << endl; + } + jacobian_output << "]}"; + + // Writing Hessian + temp_term_union_m_1 = temp_term_union; + temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end()); + concat = "hessian"; + writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat); + hessian_output << ", \"hessian\": {" + << " \"nrows\": " << equations.size() + << ", \"ncols\": " << hessianColsNbr + << ", \"entries\": ["; + for (second_derivatives_t::const_iterator it = second_derivatives.begin(); + it != second_derivatives.end(); it++) + { + if (it != second_derivatives.begin()) + hessian_output << ", "; + + int eq = it->first.first; + string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + int lag1 = getLagByDerivID(it->first.second.first); + string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second)); + int lag2 = getLagByDerivID(it->first.second.second); + expr_t d2 = it->second; + + hessian_output << "{\"eq\": " << eq + << ", \"var1\": \"" << var1 << "\"" + << ", \"lag1\": " << lag1 + << ", \"var2\": \"" << var2 << "\"" + << ", \"lag2\": " << lag2 + << ", \"val\": \""; + d2->writeJsonOutput(hessian_output, temp_term_union, tef_terms); + hessian_output << "\"}" << endl; + } + hessian_output << "]}"; + + // Writing third derivatives + temp_term_union_m_1 = temp_term_union; + temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end()); + concat = "third_derivatives"; + writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat); + third_derivatives_output << ", \"third_derivative\": {" + << " \"nrows\": " << equations.size() + << ", \"ncols\": " << hessianColsNbr * dynJacobianColsNbr + << ", \"entries\": ["; + for (third_derivatives_t::const_iterator it = third_derivatives.begin(); + it != third_derivatives.end(); it++) + { + if (it != third_derivatives.begin()) + third_derivatives_output << ", "; + + int eq = it->first.first; + string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + int lag1 = getLagByDerivID(it->first.second.first); + string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first)); + int lag2 = getLagByDerivID(it->first.second.second.first); + string var3 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second)); + int lag3 = getLagByDerivID(it->first.second.second.second); + expr_t d3 = it->second; + + third_derivatives_output << "{\"eq\": " << eq + << ", \"var1\": \"" << var1 << "\"" + << ", \"lag1\": " << lag1 + << ", \"var2\": \"" << var2 << "\"" + << ", \"lag2\": " << lag2 + << ", \"var3\": \"" << var3 << "\"" + << ", \"lag3\": " << lag3 + << ", \"val\": \""; + d3->writeJsonOutput(third_derivatives_output, temp_term_union, tef_terms); + third_derivatives_output << "\"}" << endl; + } + third_derivatives_output << "]}"; + + output << "\"dynamic_model_derivatives\": {" + << model_local_vars_output.str() + << ", " << model_output.str() + << ", " << jacobian_output.str() + << ", " << hessian_output.str() + << ", " << third_derivatives_output.str() + << "}"; +} + +void +DynamicModel::writeJsonParamsDerivativesFile(ostream &output) const +{ + if (!residuals_params_derivatives.size() + && !residuals_params_second_derivatives.size() + && !jacobian_params_derivatives.size() + && !jacobian_params_second_derivatives.size() + && !hessian_params_derivatives.size()) + return; + + ostringstream model_local_vars_output; // Used for storing model local vars + ostringstream model_output; // Used for storing model temp vars and equations + ostringstream jacobian_output; // Used for storing jacobian equations + ostringstream hessian_output; // Used for storing Hessian equations + ostringstream hessian1_output; // Used for storing Hessian equations + ostringstream third_derivs_output; // Used for storing third order derivatives equations + ostringstream third_derivs1_output; // Used for storing third order derivatives equations + + deriv_node_temp_terms_t tef_terms; + writeJsonModelLocalVariables(model_local_vars_output, tef_terms); + + temporary_terms_t temp_terms_empty; + string concat = "all"; + writeJsonTemporaryTerms(params_derivs_temporary_terms, temp_terms_empty, model_output, tef_terms, concat); + jacobian_output << "\"deriv_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nparamcols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (first_derivatives_t::const_iterator it = residuals_params_derivatives.begin(); + it != residuals_params_derivatives.end(); it++) + { + if (it != residuals_params_derivatives.begin()) + jacobian_output << ", "; + + int eq = it->first.first; + string param = symbol_table.getName(getSymbIDByDerivID(it->first.second)); + expr_t d1 = it->second; + + jacobian_output << "{\"eq\": " << eq + << ", \"param\": \"" << param << "\"" + << ", \"val\": \""; + d1->writeJsonOutput(jacobian_output, params_derivs_temporary_terms, tef_terms); + jacobian_output << "\"}" << endl; + } + jacobian_output << "]}"; + hessian_output << "\"deriv_jacobian_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nvarcols\": " << dynJacobianColsNbr + << ", \"nparamcols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (second_derivatives_t::const_iterator it = jacobian_params_derivatives.begin(); + it != jacobian_params_derivatives.end(); it++) + { + if (it != jacobian_params_derivatives.begin()) + hessian_output << ", "; + + int eq = it->first.first; + string var = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + int lag = getLagByDerivID(it->first.second.first); + string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second)); + expr_t d2 = it->second; + + hessian_output << "{\"eq\": " << eq + << ", \"var\": \"" << var << "\"" + << ", \"lag\": " << lag + << ", \"param\": \"" << param << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(hessian_output, params_derivs_temporary_terms, tef_terms); + hessian_output << "\"}" << endl; + } + hessian_output << "]}"; + + hessian1_output << "\"second_deriv_residuals_wrt_params\": {" + << " \"nrows\": " << equations.size() + << ", \"nparam1cols\": " << symbol_table.param_nbr() + << ", \"nparam2cols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin(); + it != residuals_params_second_derivatives.end(); ++it) + { + if (it != residuals_params_second_derivatives.begin()) + hessian1_output << ", "; + + int eq = it->first.first; + string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second)); + expr_t d2 = it->second; + + hessian1_output << "{\"eq\": " << eq + << ", \"param1\": \"" << param1 << "\"" + << ", \"param2\": \"" << param2 << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(hessian1_output, params_derivs_temporary_terms, tef_terms); + hessian1_output << "\"}" << endl; + } + hessian1_output << "]}"; + third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nvarcols\": " << dynJacobianColsNbr + << ", \"nparam1cols\": " << symbol_table.param_nbr() + << ", \"nparam2cols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin(); + it != jacobian_params_second_derivatives.end(); ++it) + { + if (it != jacobian_params_second_derivatives.begin()) + third_derivs_output << ", "; + + int eq = it->first.first; + string var = symbol_table.getName(it->first.second.first); + int lag = getLagByDerivID(it->first.second.first); + string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first)); + string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second)); + expr_t d2 = it->second; + + third_derivs_output << "{\"eq\": " << eq + << ", \"var\": \"" << var << "\"" + << ", \"lag\": " << lag + << ", \"param1\": \"" << param1 << "\"" + << ", \"param2\": \"" << param2 << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(third_derivs_output, params_derivs_temporary_terms, tef_terms); + third_derivs_output << "\"}" << endl; + } + third_derivs_output << "]}" << endl; + + third_derivs1_output << "\"derivative_hessian_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nvar1cols\": " << dynJacobianColsNbr + << ", \"nvar2cols\": " << dynJacobianColsNbr + << ", \"nparamcols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin(); + it != hessian_params_derivatives.end(); ++it) + { + if (it != hessian_params_derivatives.begin()) + third_derivs1_output << ", "; + + int eq = it->first.first; + string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + int lag1 = getLagByDerivID(it->first.second.first); + string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first)); + int lag2 = getLagByDerivID(it->first.second.second.first); + string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second)); + expr_t d2 = it->second; + + third_derivs1_output << "{\"eq\": " << eq + << ", \"var1\": \"" << var1 << "\"" + << ", \"lag1\": " << lag1 + << ", \"var2\": \"" << var2 << "\"" + << ", \"lag2\": " << lag2 + << ", \"param1\": \"" << param << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(third_derivs1_output, params_derivs_temporary_terms, tef_terms); + third_derivs1_output << "\"}" << endl; + } + third_derivs1_output << "]}" << endl; + + output << "\"dynamic_model_params_derivatives\": {" + << model_local_vars_output.str() + << ", " << model_output.str() + << ", " << jacobian_output.str() + << ", " << hessian_output.str() + << ", " << hessian1_output.str() + << ", " << third_derivs_output.str() + << ", " << third_derivs1_output.str() + << "}"; } diff --git a/DynamicModel.hh b/DynamicModel.hh index e79ac7f4..87e41e38 100644 --- a/DynamicModel.hh +++ b/DynamicModel.hh @@ -220,6 +220,12 @@ public: //! Write JSON Output void writeJsonOutput(ostream &output) const; + //! Write JSON Output representation of dynamic model after computing pass + void writeJsonComputingPassOutput(ostream &output) const; + + //! Write JSON prams derivatives file + void writeJsonParamsDerivativesFile(ostream &output) const; + //! Return true if the hessian is equal to zero inline bool checkHessianZero() const; diff --git a/DynareMain.cc b/DynareMain.cc index c5650926..cd62325c 100644 --- a/DynareMain.cc +++ b/DynareMain.cc @@ -45,7 +45,7 @@ void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) , bool cygwin, bool msvc, bool mingw #endif - , bool json, JsonFileOutputType json_output_mode + , JsonOutputPointType json, JsonFileOutputType json_output_mode ); void main1(char *modfile, string &basename, bool debug, bool save_macro, string &save_macro_file, @@ -62,7 +62,7 @@ usage() #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) << " [cygwin] [msvc] [mingw]" #endif - << "[json] [jsonstdout]" + << "[json=parse|check|transform|compute] [jsonstdout]" << endl; exit(EXIT_FAILURE); } @@ -115,7 +115,7 @@ main(int argc, char **argv) map defines; vector path; FileOutputType output_mode = none; - bool json = false; + JsonOutputPointType json = nojson; JsonFileOutputType json_output_mode = file; LanguageOutputType language = matlab; @@ -297,8 +297,27 @@ main(int argc, char **argv) } else if (!strcmp(argv[arg], "jsonstdout")) json_output_mode = standardout; - else if (!strcmp(argv[arg], "json")) - json = true; + else if (strlen(argv[arg]) >= 4 && !strncmp(argv[arg], "json", 4)) + { + if (strlen(argv[arg]) <= 5 || argv[arg][4] != '=') + { + cerr << "Incorrect syntax for json option" << endl; + usage(); + } + if (strlen(argv[arg]) == 10 && !strncmp(argv[arg] + 5, "parse", 5)) + json = parsing; + else if (strlen(argv[arg]) == 10 && !strncmp(argv[arg] + 5, "check", 5)) + json = checkpass; + else if (strlen(argv[arg]) == 14 && !strncmp(argv[arg] + 5, "transform", 9)) + json = transformpass; + else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 5, "compute", 7)) + json = computingpass; + else + { + cerr << "Incorrect syntax for json option" << endl; + usage(); + } + } else { cerr << "Unknown option: " << argv[arg] << endl; diff --git a/DynareMain2.cc b/DynareMain2.cc index 3bbc4b4f..bc2d34ff 100644 --- a/DynareMain2.cc +++ b/DynareMain2.cc @@ -34,32 +34,33 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) , bool cygwin, bool msvc, bool mingw #endif - , bool json, JsonFileOutputType json_output_mode + , JsonOutputPointType json, JsonFileOutputType json_output_mode ) { ParsingDriver p(warnings, nostrict); // Do parsing and construct internal representation of mod file ModFile *mod_file = p.parse(in, debug); - if (json) - { - mod_file->symbol_table.freeze(); - mod_file->writeJsonOutput(basename, json_output_mode); - mod_file->symbol_table.unfreeze(); - cout << "JSON file written after Parsing step." << endl; - } + if (json == parsing) + mod_file->writeJsonOutput(basename, json, json_output_mode); // Run checking pass mod_file->checkPass(nostrict); + if (json == checkpass) + mod_file->writeJsonOutput(basename, json, json_output_mode); // Perform transformations on the model (creation of auxiliary vars and equations) mod_file->transformPass(nostrict); + if (json == transformpass) + mod_file->writeJsonOutput(basename, json, json_output_mode); // Evaluate parameters initialization, initval, endval and pounds mod_file->evalAllExpressions(warn_uninit); // Do computations mod_file->computingPass(no_tmp_terms, output_mode, compute_xrefs, params_derivs_order); + if (json == computingpass) + mod_file->writeJsonOutput(basename, json, json_output_mode); // Write outputs if (output_mode != none) diff --git a/ExprNode.cc b/ExprNode.cc index ccba75c2..b5b9d4dd 100644 --- a/ExprNode.cc +++ b/ExprNode.cc @@ -73,6 +73,13 @@ ExprNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t &te return 100; } +int +ExprNode::precedenceJson(const temporary_terms_t &temporary_terms) const +{ + // For a constant, a variable, or a unary op, the precedence is maximal + return 100; +} + int ExprNode::cost(int cost, bool is_matlab) const { @@ -185,6 +192,14 @@ ExprNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output // Nothing to do } +void +ExprNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + // Nothing to do +} + void ExprNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, @@ -323,7 +338,7 @@ NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type, } void -NumConstNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +NumConstNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { @@ -624,10 +639,17 @@ VariableNode::containsExternalFunction() const } void -VariableNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +VariableNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + output << datatree.symbol_table.getName(symb_id); if (lag != 0) output << "(" << lag << ")"; @@ -1869,13 +1891,20 @@ UnaryOpNode::containsExternalFunction() const } void -UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +UnaryOpNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + // Always put parenthesis around uminus nodes if (op_code == oUminus) - output << LEFT_PAR(output_type); + output << "("; switch (op_code) { @@ -1938,7 +1967,7 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, break; case oSteadyState: output << "("; - arg->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg->writeJsonOutput(output, temporary_terms, tef_terms); output << ")"; return; case oSteadyStateParamDeriv: @@ -1949,7 +1978,6 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, assert(datatree.symbol_table.getType(param1_symb_id) == eParameter); int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id); int tsid_param = datatree.symbol_table.getTypeSpecificID(param1_symb_id); - assert(IS_MATLAB(output_type)); output << "ss_param_deriv(" << tsid_endo+1 << "," << tsid_param+1 << ")"; } return; @@ -1963,7 +1991,6 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id); int tsid_param1 = datatree.symbol_table.getTypeSpecificID(param1_symb_id); int tsid_param2 = datatree.symbol_table.getTypeSpecificID(param2_symb_id); - assert(IS_MATLAB(output_type)); output << "ss_param_2nd_deriv(" << tsid_endo+1 << "," << tsid_param1+1 << "," << tsid_param2+1 << ")"; } @@ -1984,23 +2011,21 @@ UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, */ if (op_code != oUminus || (op_code == oUminus - && arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms))) + && arg->precedenceJson(temporary_terms) < precedenceJson(temporary_terms))) { - output << LEFT_PAR(output_type); - if (op_code == oSign && (output_type == oCDynamicModel || output_type == oCStaticModel)) - output << "1.0,"; + output << "("; close_parenthesis = true; } // Write argument - arg->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg->writeJsonOutput(output, temporary_terms, tef_terms); if (close_parenthesis) - output << RIGHT_PAR(output_type); + output << ")"; // Close parenthesis for uminus if (op_code == oUminus) - output << RIGHT_PAR(output_type); + output << ")"; } void @@ -2197,6 +2222,14 @@ UnaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType out arg->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms); } +void +UnaryOpNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + arg->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); +} + void UnaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, @@ -2963,6 +2996,43 @@ BinaryOpNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t exit(EXIT_FAILURE); } +int +BinaryOpNode::precedenceJson(const temporary_terms_t &temporary_terms) const +{ + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + // A temporary term behaves as a variable + if (it != temporary_terms.end()) + return 100; + + switch (op_code) + { + case oEqual: + return 0; + case oEqualEqual: + case oDifferent: + return 1; + case oLessEqual: + case oGreaterEqual: + case oLess: + case oGreater: + return 2; + case oPlus: + case oMinus: + return 3; + case oTimes: + case oDivide: + return 4; + case oPower: + case oPowerDeriv: + return 5; + case oMin: + case oMax: + return 100; + } + // Suppress GCC warning + exit(EXIT_FAILURE); +} + int BinaryOpNode::cost(const map &temp_terms_map, bool is_matlab) const { @@ -3226,10 +3296,18 @@ BinaryOpNode::containsExternalFunction() const } void -BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +BinaryOpNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + // If current node is a temporary term + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + if (op_code == oMax || op_code == oMin) { switch (op_code) @@ -3243,32 +3321,32 @@ BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, default: ; } - arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg1->writeJsonOutput(output, temporary_terms, tef_terms); output << ","; - arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg2->writeJsonOutput(output, temporary_terms, tef_terms); output << ")"; return; } - int prec = precedence(output_type, temporary_terms); + int prec = precedenceJson(temporary_terms); bool close_parenthesis = false; // If left argument has a lower precedence, or if current and left argument are both power operators, // add parenthesis around left argument BinaryOpNode *barg1 = dynamic_cast(arg1); - if (arg1->precedence(output_type, temporary_terms) < prec + if (arg1->precedenceJson(temporary_terms) < prec || (op_code == oPower && barg1 != NULL && barg1->op_code == oPower)) { - output << LEFT_PAR(output_type); + output << "("; close_parenthesis = true; } // Write left argument - arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg1->writeJsonOutput(output, temporary_terms, tef_terms); if (close_parenthesis) - output << RIGHT_PAR(output_type); + output << ")"; // Write current operator symbol switch (op_code) @@ -3321,21 +3399,21 @@ BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, - it is a minus operator with same precedence than current operator - it is a divide operator with same precedence than current operator */ BinaryOpNode *barg2 = dynamic_cast(arg2); - int arg2_prec = arg2->precedence(output_type, temporary_terms); + int arg2_prec = arg2->precedenceJson(temporary_terms); if (arg2_prec < prec - || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower && !IS_LATEX(output_type)) + || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower) || (op_code == oMinus && arg2_prec == prec) - || (op_code == oDivide && arg2_prec == prec && !IS_LATEX(output_type))) + || (op_code == oDivide && arg2_prec == prec)) { - output << LEFT_PAR(output_type); + output << "("; close_parenthesis = true; } // Write right argument - arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg2->writeJsonOutput(output, temporary_terms, tef_terms); if (close_parenthesis) - output << RIGHT_PAR(output_type); + output << ")"; } void @@ -3527,6 +3605,15 @@ BinaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType ou arg2->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms); } +void +BinaryOpNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + arg1->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); + arg2->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); +} + void BinaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, @@ -4478,10 +4565,18 @@ TrinaryOpNode::containsExternalFunction() const } void -TrinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +TrinaryOpNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + // If current node is a temporary term + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + switch (op_code) { case oNormcdf: @@ -4492,11 +4587,11 @@ TrinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, break; } - arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg1->writeJsonOutput(output, temporary_terms, tef_terms); output << ","; - arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg2->writeJsonOutput(output, temporary_terms, tef_terms); output << ","; - arg3->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + arg3->writeJsonOutput(output, temporary_terms, tef_terms); output << ")"; } @@ -4576,6 +4671,16 @@ TrinaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType o arg3->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms); } +void +TrinaryOpNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + arg1->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); + arg2->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); + arg3->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); +} + void TrinaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, @@ -5181,7 +5286,7 @@ AbstractExternalFunctionNode::writeExternalFunctionArguments(ostream &output, Ex } void -AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, +AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { @@ -5191,7 +5296,7 @@ AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output if (it != arguments.begin()) output << ","; - (*it)->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + (*it)->writeJsonOutput(output, temporary_terms, tef_terms); } } @@ -5359,12 +5464,19 @@ ExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsign } void -ExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +ExternalFunctionNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + output << datatree.symbol_table.getName(symb_id) << "("; - writeJsonExternalFunctionArguments(output, output_type, temporary_terms, tef_terms); + writeJsonExternalFunctionArguments(output, temporary_terms, tef_terms); output << ")"; } @@ -5477,6 +5589,42 @@ ExternalFunctionNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutpu } } +void +ExternalFunctionNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id); + assert(first_deriv_symb_id != eExtFunSetButNoNameProvided); + + for (vector::const_iterator it = arguments.begin(); + it != arguments.end(); it++) + (*it)->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); + + if (!alreadyWrittenAsTefTerm(symb_id, tef_terms)) + { + tef_terms[make_pair(symb_id, arguments)] = (int) tef_terms.size(); + int indx = getIndxInTefTerms(symb_id, tef_terms); + int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id); + assert(second_deriv_symb_id != eExtFunSetButNoNameProvided); + + stringstream ef; + ef << "{\"external_function\": {" + << "\"output\": \"TEF_" << indx << "\""; + + if (symb_id == first_deriv_symb_id) + ef << ", \"output_d\": \"TEFD_" << indx << "\""; + + if (symb_id == second_deriv_symb_id) + ef << ", \"output_dd\": \"TEFDD_" << indx << "\""; + + ef << ", \"function\": \"" << datatree.symbol_table.getName(symb_id) << "("; + writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms); + ef << ")\"}}"; + efout.push_back(ef.str()); + } +} + expr_t ExternalFunctionNode::toStatic(DataTree &static_datatree) const { @@ -5559,10 +5707,31 @@ FirstDerivExternalFunctionNode::composeDerivatives(const vector &dargs) } void -FirstDerivExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +FirstDerivExternalFunctionNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + // If current node is a temporary term + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + + const int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id); + assert(first_deriv_symb_id != eExtFunSetButNoNameProvided); + + const int tmpIndx = inputIndex - 1; + + if (first_deriv_symb_id == symb_id) + output << "TEFD_" << getIndxInTefTerms(symb_id, tef_terms) + << "[" << tmpIndx << "]"; + else if (first_deriv_symb_id == eExtFunNotSet) + output << "TEFD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex; + else + output << "TEFD_def_" << getIndxInTefTerms(first_deriv_symb_id, tef_terms) + << "[" << tmpIndx << "]"; } void @@ -5752,6 +5921,47 @@ FirstDerivExternalFunctionNode::writeExternalFunctionOutput(ostream &output, Exp } } +void +FirstDerivExternalFunctionNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id); + assert(first_deriv_symb_id != eExtFunSetButNoNameProvided); + + /* For a node with derivs provided by the user function, call the method + on the non-derived node */ + if (first_deriv_symb_id == symb_id) + { + expr_t parent = datatree.AddExternalFunction(symb_id, arguments); + parent->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); + return; + } + + if (alreadyWrittenAsTefTerm(first_deriv_symb_id, tef_terms)) + return; + + stringstream ef; + if (first_deriv_symb_id == eExtFunNotSet) + ef << "{\"first_deriv_external_function\": {" + << "\"output\": \"TEFD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex << "\"" + << ", \"analytic_derivative\": false" + << ", \"wrt\": " << inputIndex + << ", \"function\": \"" << datatree.symbol_table.getName(symb_id) << "("; + else + { + tef_terms[make_pair(first_deriv_symb_id, arguments)] = (int) tef_terms.size(); + ef << "{\"first_deriv_external_function\": {" + << "\"output\": \"TEFD_def_" << getIndxInTefTerms(first_deriv_symb_id, tef_terms) + << ", \"analytic_derivative\": true" + << ", \"function\": \"" << datatree.symbol_table.getName(first_deriv_symb_id) << "("; + } + + writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms); + ef << ")\"}}"; + efout.push_back(ef.str()); +} + void FirstDerivExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, @@ -5878,10 +6088,32 @@ SecondDerivExternalFunctionNode::composeDerivatives(const vector &dargs) } void -SecondDerivExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, +SecondDerivExternalFunctionNode::writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const { + // If current node is a temporary term + temporary_terms_t::const_iterator it = temporary_terms.find(const_cast(this)); + if (it != temporary_terms.end()) + { + output << "T" << idx; + return; + } + + const int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id); + assert(second_deriv_symb_id != eExtFunSetButNoNameProvided); + + const int tmpIndex1 = inputIndex1 - 1; + const int tmpIndex2 = inputIndex2 - 1; + + if (second_deriv_symb_id == symb_id) + output << "TEFDD_" << getIndxInTefTerms(symb_id, tef_terms) + << "[" << tmpIndex1 << "," << tmpIndex2 << "]"; + else if (second_deriv_symb_id == eExtFunNotSet) + output << "TEFDD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex1 << "_" << inputIndex2; + else + output << "TEFDD_def_" << getIndxInTefTerms(second_deriv_symb_id, tef_terms) + << "[" << tmpIndex1 << "," << tmpIndex2 << "]"; } void @@ -6048,6 +6280,48 @@ SecondDerivExternalFunctionNode::writeExternalFunctionOutput(ostream &output, Ex } } +void +SecondDerivExternalFunctionNode::writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id); + assert(second_deriv_symb_id != eExtFunSetButNoNameProvided); + + /* For a node with derivs provided by the user function, call the method + on the non-derived node */ + if (second_deriv_symb_id == symb_id) + { + expr_t parent = datatree.AddExternalFunction(symb_id, arguments); + parent->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms); + return; + } + + if (alreadyWrittenAsTefTerm(second_deriv_symb_id, tef_terms)) + return; + + stringstream ef; + if (second_deriv_symb_id == eExtFunNotSet) + ef << "{\"second_deriv_external_function\": {" + << "\"output\": \"TEFDD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex1 << "_" << inputIndex2 << "\"" + << ", \"analytic_derivative\": false" + << ", \"wrt1\": " << inputIndex1 + << ", \"wrt2\": " << inputIndex2 + << ", \"function\": \"" << datatree.symbol_table.getName(symb_id) << "("; + else + { + tef_terms[make_pair(second_deriv_symb_id, arguments)] = (int) tef_terms.size(); + ef << "{\"second_deriv_external_function\": {" + << "\"output\": \"TEFDD_def_" << getIndxInTefTerms(second_deriv_symb_id, tef_terms) + << ", \"analytic_derivative\": true" + << ", \"function\": \"" << datatree.symbol_table.getName(second_deriv_symb_id) << "("; + } + + writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms); + ef << ")\"}}" << endl; + efout.push_back(ef.str()); +} + expr_t SecondDerivExternalFunctionNode::cloneDynamic(DataTree &dynamic_datatree) const { diff --git a/ExprNode.hh b/ExprNode.hh index 32654071..e4e5d9bc 100644 --- a/ExprNode.hh +++ b/ExprNode.hh @@ -222,13 +222,21 @@ public: void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const; //! Writes output of node in JSON syntax - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0; + + virtual int precedenceJson(const temporary_terms_t &temporary_terms) const; //! Writes the output for an external function, ensuring that the external function is called as few times as possible using temporary terms virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + //! Write the JSON output of an external function in a string vector + //! Allows the insertion of commas if necessary + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; + virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -481,7 +489,7 @@ public: }; virtual void prepareForDerivation(); virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual bool containsExternalFunction() const; virtual void collectDynamicVariables(SymbolType type_arg, set > &result) const; virtual void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const; @@ -531,7 +539,7 @@ public: VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg); virtual void prepareForDerivation(); virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual bool containsExternalFunction() const; virtual void collectDynamicVariables(SymbolType type_arg, set > &result) const; virtual void computeTemporaryTerms(map &reference_count, @@ -607,11 +615,14 @@ public: map &temp_terms_map, bool is_matlab, NodeTreeReference tr) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -690,16 +701,20 @@ public: BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg, BinaryOpcode op_code_arg, const expr_t arg2_arg, int powerDerivOrder); virtual void prepareForDerivation(); + virtual int precedenceJson(const temporary_terms_t &temporary_terms) const; virtual int precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const; virtual void computeTemporaryTerms(map > &reference_count, map &temp_terms_map, bool is_matlab, NodeTreeReference tr) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -801,11 +816,14 @@ public: map &temp_terms_map, bool is_matlab, NodeTreeReference tr) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -872,7 +890,7 @@ protected: int getIndxInTefTerms(int the_symb_id, deriv_node_temp_terms_t &tef_terms) const throw (UnknownFunctionNameAndArgs); //! Helper function to write output arguments of any given external function void writeExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - void writeJsonExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + void writeJsonExternalFunctionArguments(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; public: AbstractExternalFunctionNode(DataTree &datatree_arg, int symb_id_arg, const vector &arguments_arg); @@ -881,11 +899,14 @@ public: map &temp_terms_map, bool is_matlab, NodeTreeReference tr) const = 0; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0; virtual bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const = 0; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -948,10 +969,13 @@ public: map &temp_terms_map, bool is_matlab, NodeTreeReference tr) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -989,7 +1013,7 @@ public: vector< vector > &v_temporary_terms, int equation) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -997,6 +1021,9 @@ public: virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -1029,7 +1056,7 @@ public: vector< vector > &v_temporary_terms, int equation) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; - virtual void writeJsonOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; virtual void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, @@ -1037,6 +1064,9 @@ public: virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; + virtual void writeJsonExternalFunctionOutput(vector &efout, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const; virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, diff --git a/ExtendedPreprocessorTypes.hh b/ExtendedPreprocessorTypes.hh index 1388cafc..26c8ac19 100644 --- a/ExtendedPreprocessorTypes.hh +++ b/ExtendedPreprocessorTypes.hh @@ -44,4 +44,13 @@ enum JsonFileOutputType file, // output JSON files to file standardout, // output JSON files to stdout }; + +enum JsonOutputPointType + { + nojson, // don't output JSON + parsing, // output JSON after the parsing step + checkpass, // output JSON after the check pass + transformpass, // output JSON after the transform pass + computingpass // output JSON after the computing pass + }; #endif diff --git a/ModFile.cc b/ModFile.cc index 78ae952a..4cf0ba1b 100644 --- a/ModFile.cc +++ b/ModFile.cc @@ -1248,7 +1248,44 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output) } void -ModFile::writeJsonOutput(const string &basename, JsonFileOutputType json_output_mode) const +ModFile::writeJsonOutput(const string &basename, JsonOutputPointType json, JsonFileOutputType json_output_mode) +{ + if (json == nojson) + return; + + if (json == parsing || json == checkpass) + symbol_table.freeze(); + + writeJsonOutputParsingCheck(basename, json_output_mode); + + if (json == parsing || json == checkpass) + symbol_table.unfreeze(); + + if (json == computingpass) + writeJsonComputingPassOutput(basename, json_output_mode); + + switch (json) + { + case parsing: + cout << "JSON written after Parsing step." << endl; + break; + case checkpass: + cout << "JSON written after Check step." << endl; + break; + case transformpass: + cout << "JSON written after Transform step." << endl; + break; + case computingpass: + cout << "JSON written after Computing step." << endl; + break; + case nojson: + cerr << "ModFile::writeJsonOutput: should not arrive here." << endl; + exit(EXIT_FAILURE); + } +} + +void +ModFile::writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode) const { ostringstream output; output << "{" << endl; @@ -1298,3 +1335,105 @@ ModFile::writeJsonOutput(const string &basename, JsonFileOutputType json_output_ jsonOutputFile.close(); } } + +void +ModFile::writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode) const +{ + ostringstream static_output; + static_output << "{"; + static_model.writeJsonComputingPassOutput(static_output); + static_output << "}" << endl; + + ostringstream dynamic_output; + dynamic_output << "{"; + dynamic_model.writeJsonComputingPassOutput(dynamic_output); + dynamic_output << "}" << endl; + + ostringstream tmp_out, static_paramsd_output; + tmp_out << ""; + static_paramsd_output << ""; + static_model.writeJsonParamsDerivativesFile(tmp_out); + if (!tmp_out.str().empty()) + static_paramsd_output << "{" << tmp_out.str() << "}" << endl; + + ostringstream tmp1_out, dynamic_paramsd_output; + tmp1_out << ""; + dynamic_paramsd_output << ""; + dynamic_model.writeJsonParamsDerivativesFile(tmp1_out); + if (!tmp1_out.str().empty()) + dynamic_paramsd_output << "{" << tmp1_out.str() << "}" << endl; + + if (json_output_mode == standardout) + { + cout << static_output.str() << endl; + cout << dynamic_output.str() << endl; + if (!dynamic_paramsd_output.str().empty()) + cout << dynamic_paramsd_output.str() << endl; + if (!static_paramsd_output.str().empty()) + cout << static_paramsd_output.str() << endl; + } + else + { + if (basename.empty()) + { + cerr << "ERROR: Missing file name" << endl; + exit(EXIT_FAILURE); + } + + string fname_static, fname_dynamic; + fname_static = basename + "_static.json"; + fname_dynamic = basename + "_dynamic.json"; + + ofstream jsonOutputFileStatic, jsonOutputFileDynamic; + jsonOutputFileStatic.open(fname_static.c_str(), ios::out | ios::binary); + if (!jsonOutputFileStatic.is_open()) + { + cerr << "ERROR: Can't open file " << fname_static << " for writing" << endl; + exit(EXIT_FAILURE); + } + + jsonOutputFileDynamic.open(fname_dynamic.c_str(), ios::out | ios::binary); + if (!jsonOutputFileDynamic.is_open()) + { + cerr << "ERROR: Can't open file " << fname_dynamic << " for writing" << endl; + exit(EXIT_FAILURE); + } + + jsonOutputFileStatic << static_output.str(); + jsonOutputFileStatic.close(); + jsonOutputFileDynamic << dynamic_output.str(); + jsonOutputFileDynamic.close(); + + if (!static_paramsd_output.str().empty()) + { + string fname_static_params; + fname_static_params = basename + "_static_params_derivs.json"; + ofstream jsonOutputFileStaticParamsDerivs; + jsonOutputFileStaticParamsDerivs.open(fname_static_params.c_str(), ios::out | ios::binary); + if (!jsonOutputFileStaticParamsDerivs.is_open()) + { + cerr << "ERROR: Can't open file " << fname_static_params << " for writing" << endl; + exit(EXIT_FAILURE); + } + + jsonOutputFileStaticParamsDerivs << static_paramsd_output.str(); + jsonOutputFileStaticParamsDerivs.close(); + } + + if (!dynamic_paramsd_output.str().empty()) + { + string fname_dynamic_params; + fname_dynamic_params = basename + "_params_derivs.json"; + ofstream jsonOutputFileDynamicParamsDerivs; + jsonOutputFileDynamicParamsDerivs.open(fname_dynamic_params.c_str(), ios::out | ios::binary); + if (!jsonOutputFileDynamicParamsDerivs.is_open()) + { + cerr << "ERROR: Can't open file " << fname_dynamic_params << " for writing" << endl; + exit(EXIT_FAILURE); + } + + jsonOutputFileDynamicParamsDerivs << dynamic_paramsd_output.str(); + jsonOutputFileDynamicParamsDerivs.close(); + } + } +} diff --git a/ModFile.hh b/ModFile.hh index b83f984d..684d592e 100644 --- a/ModFile.hh +++ b/ModFile.hh @@ -117,6 +117,9 @@ private: ModFileStructure mod_file_struct; //! Warnings Encountered WarningConsolidation &warnings; + //! Functions used in writing of JSON outut. See writeJsonOutput + void writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode) const; + void writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode) const; public: //! Add a statement @@ -171,7 +174,7 @@ public: //! Initially created to enable Julia to work with .mod files //! Potentially outputs ModFile after the various parts of processing (parsing, checkPass, transformPass, computingPass) //! Allows user of other host language platforms (python, fortran, etc) to provide support for dynare .mod files - void writeJsonOutput(const string &basename, JsonFileOutputType json_output_mode) const; + void writeJsonOutput(const string &basename, JsonOutputPointType json, JsonFileOutputType json_output_mode); }; #endif // ! MOD_FILE_HH diff --git a/ModelTree.cc b/ModelTree.cc index 444aec2b..3e2b7395 100644 --- a/ModelTree.cc +++ b/ModelTree.cc @@ -1292,6 +1292,59 @@ ModelTree::writeTemporaryTerms(const temporary_terms_t &tt, const temporary_term } } +void +ModelTree::writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, + deriv_node_temp_terms_t &tef_terms, string &concat) const +{ + // Local var used to keep track of temp nodes already written + bool wrote_term = false; + temporary_terms_t tt2 = ttm1; + + output << "\"external_functions_temporary_terms_" << concat << "\": ["; + for (temporary_terms_t::const_iterator it = tt.begin(); + it != tt.end(); it++) + if (ttm1.find(*it) == ttm1.end()) + { + if (dynamic_cast(*it) != NULL) + { + if (wrote_term) + output << ", "; + vector efout; + (*it)->writeJsonExternalFunctionOutput(efout, tt2, tef_terms); + for (vector::const_iterator it1 = efout.begin(); it1 != efout.end(); it1++) + { + if (it1 != efout.begin()) + output << ", "; + output << *it1; + } + wrote_term = true; + } + tt2.insert(*it); + } + + tt2 = ttm1; + wrote_term = false; + output << "]" + << ", \"temporary_terms_" << concat << "\": ["; + for (temporary_terms_t::const_iterator it = tt.begin(); + it != tt.end(); it++) + if (ttm1.find(*it) == ttm1.end()) + { + if (wrote_term) + output << ", "; + output << "{\"temporary_term\": \""; + (*it)->writeJsonOutput(output, tt, tef_terms); + output << " = "; + (*it)->writeJsonOutput(output, tt2, tef_terms); + output << "\"}" << endl; + wrote_term = true; + + // Insert current node into tt2 + tt2.insert(*it); + } + output << "]"; +} + void ModelTree::fixNestedParenthesis(ostringstream &output, map &tmp_paren_vars, bool &message_printed) const { @@ -1481,6 +1534,51 @@ ModelTree::writeModelLocalVariables(ostream &output, ExprNodeOutputType output_t } } +void +ModelTree::writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const +{ + /* Collect all model local variables appearing in equations, and print only + them. Printing unused model local variables can lead to a crash (see + ticket #101). */ + set used_local_vars; + + // Use an empty set for the temporary terms + const temporary_terms_t tt; + + for (size_t i = 0; i < equations.size(); i++) + equations[i]->collectVariables(eModelLocalVariable, used_local_vars); + + output << "\"external_functions_model_local_variables\": ["; + for (set::const_iterator it = used_local_vars.begin(); + it != used_local_vars.end(); ++it) + { + vector efout; + expr_t value = local_variables_table.find(*it)->second; + value->writeJsonExternalFunctionOutput(efout, tt, tef_terms); + for (vector::const_iterator it1 = efout.begin(); it1 != efout.end(); it1++) + { + if (it1 != efout.begin()) + output << ", "; + output << *it1; + } + } + output << "]" + << ", \"model_local_variables\": ["; + for (set::const_iterator it = used_local_vars.begin(); + it != used_local_vars.end(); ++it) + { + int id = *it; + expr_t value = local_variables_table.find(id)->second; + + /* We append underscores to avoid name clashes with "g1" or "oo_" (see + also VariableNode::writeOutput) */ + output << "{\"" << symbol_table.getName(id) << "__ = "; + value->writeJsonOutput(output, tt, tef_terms); + output << "\"}" << endl; + } + output << "]"; +} + void ModelTree::writeModelEquations(ostream &output, ExprNodeOutputType output_type) const { @@ -1920,37 +2018,76 @@ bool ModelTree::isNonstationary(int symb_id) const } void -ModelTree::writeJsonModelEquations(ostream &output) const +ModelTree::writeJsonModelEquations(ostream &output, bool residuals) const { deriv_node_temp_terms_t tef_terms; vector > eqtags; - output << endl << ",\"model\":[" << endl; + temporary_terms_t tt_empty; + if (residuals) + output << endl << ",\"residuals\":[" << endl; + else + output << endl << ",\"model\":[" << endl; for (int eq = 0; eq < (int) equations.size(); eq++) { - output << "{ \"equation\": \""; - equations[eq]->writeJsonOutput(output, oMatlabDynamicModel, temporary_terms, tef_terms); - output << "\", \"line\": " << equations_lineno[eq]; - for (vector > >::const_iterator it = equation_tags.begin(); - it != equation_tags.end(); it++) - if (it->first == eq) - eqtags.push_back(it->second); + if (eq > 0) + output << ", "; - if (!eqtags.empty()) + if (residuals) { - output << ", \"tags\": {"; - int i = 0; - for (vector >:: const_iterator it = eqtags.begin(); it != eqtags.end(); it++, i++) + BinaryOpNode *eq_node = equations[eq]; + expr_t lhs = eq_node->get_arg1(); + expr_t rhs = eq_node->get_arg2(); + + output << "{\"residual\": {" + << "\"lhs\": \""; + lhs->writeJsonOutput(output, temporary_terms, tef_terms); + output << "\""; + + output << ", \"rhs\": \""; + rhs->writeJsonOutput(output, temporary_terms, tef_terms); + output << "\""; + try + { + // Test if the right hand side of the equation is empty. + if (rhs->eval(eval_context_t()) != 0) + { + output << ", \"rhs\": \""; + rhs->writeJsonOutput(output, temporary_terms, tef_terms); + output << "\""; + } + } + catch (ExprNode::EvalException &e) { - if (i != 0) - output << ", "; - output << "\"" << it->first << "\": \"" << it->second << "\""; } output << "}"; - eqtags.clear(); } - output << "}"; - if (eq < (int) equations.size() - 1) - output << "," << endl; + else + { + output << "{\"equation\": \""; + equations[eq]->writeJsonOutput(output, tt_empty, tef_terms); + output << "\"" + << ", \"line\": " << equations_lineno[eq]; + + for (vector > >::const_iterator it = equation_tags.begin(); + it != equation_tags.end(); it++) + if (it->first == eq) + eqtags.push_back(it->second); + + if (!eqtags.empty()) + { + output << ", \"tags\": {"; + int i = 0; + for (vector >:: const_iterator it = eqtags.begin(); it != eqtags.end(); it++, i++) + { + if (i != 0) + output << ", "; + output << "\"" << it->first << "\": \"" << it->second << "\""; + } + output << "}"; + eqtags.clear(); + } + } + output << "}" << endl; } output << endl << "]" << endl; } diff --git a/ModelTree.hh b/ModelTree.hh index d74598d8..ac6bfca8 100644 --- a/ModelTree.hh +++ b/ModelTree.hh @@ -186,6 +186,7 @@ protected: void computeParamsDerivativesTemporaryTerms(); //! Writes temporary terms void writeTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const; + void writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, deriv_node_temp_terms_t &tef_terms, string &concat) const; //! Compiles temporary terms void compileTemporaryTerms(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, map_idx_t map_idx, bool dynamic, bool steady_dynamic) const; //! Adds informations for simulation in a binary file @@ -200,7 +201,10 @@ protected: //! Writes model equations void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const; //! Writes JSON model equations - void writeJsonModelEquations(ostream &output) const; + //! if residuals = true, we are writing the dynamic/static model. + //! Otherwise, just the model equations (with line numbers, no tmp terms) + void writeJsonModelEquations(ostream &output, bool residuals) const; + void writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const; //! Compiles model equations void compileModelEquations(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const; diff --git a/NumericalInitialization.cc b/NumericalInitialization.cc index 22c013b3..59ef96ad 100644 --- a/NumericalInitialization.cc +++ b/NumericalInitialization.cc @@ -68,7 +68,7 @@ InitParamStatement::writeJsonOutput(ostream &output) const { deriv_node_temp_terms_t tef_terms; output << "{\"statementName\": \"param_init\", \"name\": \"" << symbol_table.getName(symb_id) << "\", " << "\"value\": \""; - param_value->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + param_value->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } @@ -184,7 +184,7 @@ InitOrEndValStatement::writeJsonInitValues(ostream &output) const if (it != init_values.begin()) output << ", "; output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", " << "\"value\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } } @@ -428,7 +428,7 @@ HistValStatement::writeJsonOutput(ostream &output) const output << "{ \"name\": \"" << symbol_table.getName(it->first.first) << "\"" << ", \"lag\": " << it->first.second << ", \"value\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]}"; @@ -526,11 +526,11 @@ HomotopyStatement::writeJsonOutput(ostream &output) const output << "{\"name\": \"" << symbol_table.getName(it->first) << "\"" << ", \"initial_value\": \""; if (it->second.first != NULL) - it->second.first->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second.first->writeJsonOutput(output, temporary_terms_t(), tef_terms); else output << "NaN"; output << "\", \"final_value\": \""; - it->second.second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second.second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" diff --git a/Shocks.cc b/Shocks.cc index 95391092..4835b370 100644 --- a/Shocks.cc +++ b/Shocks.cc @@ -87,7 +87,7 @@ AbstractShocksStatement::writeJsonDetShocks(ostream &output) const output << "{\"period1\": " << it1->period1 << ", " << "\"period2\": " << it1->period2 << ", " << "\"value\": \""; - it1->value->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it1->value->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]}"; @@ -174,7 +174,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const output << ", "; output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", " << "\"variance\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" @@ -185,7 +185,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const output << ", "; output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", " << "\"stderr\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" @@ -198,7 +198,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const << "\"name\": \"" << symbol_table.getName(it->first.first) << "\", " << "\"name2\": \"" << symbol_table.getName(it->first.second) << "\", " << "\"covariance\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" @@ -211,7 +211,7 @@ ShocksStatement::writeJsonOutput(ostream &output) const << "\"name\": \"" << symbol_table.getName(it->first.first) << "\", " << "\"name2\": \"" << symbol_table.getName(it->first.second) << "\", " << "\"correlation\": \""; - it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms); output << "\"}"; } output << "]" diff --git a/StaticModel.cc b/StaticModel.cc index a7652f9b..4516a886 100644 --- a/StaticModel.cc +++ b/StaticModel.cc @@ -2414,3 +2414,287 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons paramsDerivsFile.close(); } + +void +StaticModel::writeJsonComputingPassOutput(ostream &output) const +{ + ostringstream model_local_vars_output; // Used for storing model local vars + ostringstream model_output; // Used for storing model + ostringstream jacobian_output; // Used for storing jacobian equations + ostringstream hessian_output; // Used for storing Hessian equations + ostringstream third_derivatives_output; // Used for storing third order derivatives equations + + deriv_node_temp_terms_t tef_terms; + temporary_terms_t temp_term_empty; + temporary_terms_t temp_term_union = temporary_terms_res; + temporary_terms_t temp_term_union_m_1; + + string concat = ""; + + writeJsonModelLocalVariables(model_local_vars_output, tef_terms); + + writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat); + + writeJsonModelEquations(model_output, true); + + int nrows = equations.size(); + int JacobianColsNbr = symbol_table.endo_nbr(); + int hessianColsNbr = JacobianColsNbr*JacobianColsNbr; + + // Write Jacobian w.r. to endogenous only + temp_term_union_m_1 = temp_term_union; + temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end()); + concat = "jacobian"; + writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat); + jacobian_output << ", \"jacobian\": {" + << " \"nrows\": " << nrows + << ", \"ncols\": " << JacobianColsNbr + << ", \"entries\": ["; + for (first_derivatives_t::const_iterator it = first_derivatives.begin(); + it != first_derivatives.end(); it++) + { + if (it != first_derivatives.begin()) + jacobian_output << ", "; + + int eq = it->first.first; + string var = symbol_table.getName(getSymbIDByDerivID(it->first.second)); + expr_t d1 = it->second; + + jacobian_output << "{\"eq\": " << eq + << ", \"var\": \"" << var << "\"" + << ", \"val\": \""; + d1->writeJsonOutput(jacobian_output, temp_term_union, tef_terms); + jacobian_output << "\"}" << endl; + } + jacobian_output << "]}"; + + int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr(); + // Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed) + temp_term_union_m_1 = temp_term_union; + temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end()); + concat = "hessian"; + writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat); + hessian_output << ", \"hessian\": {" + << " \"nrows\": " << equations.size() + << ", \"ncols\": " << g2ncols + << ", \"entries\": ["; + for (second_derivatives_t::const_iterator it = second_derivatives.begin(); + it != second_derivatives.end(); it++) + { + if (it != second_derivatives.begin()) + hessian_output << ", "; + + int eq = it->first.first; + string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second)); + expr_t d2 = it->second; + + hessian_output << "{\"eq\": " << eq + << ", \"var1\": \"" << var1 << "\"" + << ", \"var2\": \"" << var2 << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(hessian_output, temp_term_union, tef_terms); + hessian_output << "\"}" << endl; + } + hessian_output << "]}"; + + // Writing third derivatives + temp_term_union_m_1 = temp_term_union; + temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end()); + concat = "third_derivatives"; + writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat); + third_derivatives_output << ", \"third_derivative\": {" + << " \"nrows\": " << equations.size() + << ", \"ncols\": " << hessianColsNbr * JacobianColsNbr + << ", \"entries\": ["; + for (third_derivatives_t::const_iterator it = third_derivatives.begin(); + it != third_derivatives.end(); it++) + { + if (it != third_derivatives.begin()) + third_derivatives_output << ", "; + + int eq = it->first.first; + string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first)); + string var3 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second)); + expr_t d3 = it->second; + + third_derivatives_output << "{\"eq\": " << eq + << ", \"var1\": \"" << var1 << "\"" + << ", \"var2\": \"" << var2 << "\"" + << ", \"var3\": \"" << var3 << "\"" + << ", \"val\": \""; + d3->writeJsonOutput(third_derivatives_output, temp_term_union, tef_terms); + third_derivatives_output << "\"}" << endl; + } + third_derivatives_output << "]}"; + + output << "\"static_model_derivatives\": {" + << model_local_vars_output.str() + << ", " << model_output.str() + << ", " << jacobian_output.str() + << ", " << hessian_output.str() + << ", " << third_derivatives_output.str() + << "}"; +} + +void +StaticModel::writeJsonParamsDerivativesFile(ostream &output) const +{ + if (!residuals_params_derivatives.size() + && !residuals_params_second_derivatives.size() + && !jacobian_params_derivatives.size() + && !jacobian_params_second_derivatives.size() + && !hessian_params_derivatives.size()) + return; + + ostringstream model_local_vars_output; // Used for storing model local vars + ostringstream model_output; // Used for storing model temp vars and equations + ostringstream jacobian_output; // Used for storing jacobian equations + ostringstream hessian_output; // Used for storing Hessian equations + ostringstream hessian1_output; // Used for storing Hessian equations + ostringstream third_derivs_output; // Used for storing third order derivatives equations + ostringstream third_derivs1_output; // Used for storing third order derivatives equations + + deriv_node_temp_terms_t tef_terms; + writeJsonModelLocalVariables(model_local_vars_output, tef_terms); + + temporary_terms_t temp_terms_empty; + string concat = "all"; + writeJsonTemporaryTerms(params_derivs_temporary_terms, temp_terms_empty, model_output, tef_terms, concat); + jacobian_output << "\"deriv_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nparamcols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (first_derivatives_t::const_iterator it = residuals_params_derivatives.begin(); + it != residuals_params_derivatives.end(); it++) + { + if (it != residuals_params_derivatives.begin()) + jacobian_output << ", "; + + int eq = it->first.first; + string param = symbol_table.getName(getSymbIDByDerivID(it->first.second)); + expr_t d1 = it->second; + + jacobian_output << "{\"eq\": " << eq + << ", \"param\": \"" << param << "\"" + << ", \"val\": \""; + d1->writeJsonOutput(jacobian_output, params_derivs_temporary_terms, tef_terms); + jacobian_output << "\"}" << endl; + } + jacobian_output << "]}"; + hessian_output << "\"deriv_jacobian_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nvarcols\": " << symbol_table.endo_nbr() + << ", \"nparamcols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (second_derivatives_t::const_iterator it = jacobian_params_derivatives.begin(); + it != jacobian_params_derivatives.end(); it++) + { + if (it != jacobian_params_derivatives.begin()) + hessian_output << ", "; + + int eq = it->first.first; + string var = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second)); + expr_t d2 = it->second; + + hessian_output << "{\"eq\": " << eq + << ", \"var\": \"" << var << "\"" + << ", \"param\": \"" << param << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(hessian_output, params_derivs_temporary_terms, tef_terms); + hessian_output << "\"}" << endl; + } + hessian_output << "]}"; + + hessian1_output << "\"second_deriv_residuals_wrt_params\": {" + << " \"nrows\": " << equations.size() + << ", \"nparam1cols\": " << symbol_table.param_nbr() + << ", \"nparam2cols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin(); + it != residuals_params_second_derivatives.end(); ++it) + { + if (it != residuals_params_second_derivatives.begin()) + hessian1_output << ", "; + + int eq = it->first.first; + string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second)); + expr_t d2 = it->second; + + hessian1_output << "{\"eq\": " << eq + << ", \"param1\": \"" << param1 << "\"" + << ", \"param2\": \"" << param2 << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(hessian1_output, params_derivs_temporary_terms, tef_terms); + hessian1_output << "\"}" << endl; + } + hessian1_output << "]}"; + third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nvarcols\": " << symbol_table.endo_nbr() + << ", \"nparam1cols\": " << symbol_table.param_nbr() + << ", \"nparam2cols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin(); + it != jacobian_params_second_derivatives.end(); ++it) + { + if (it != jacobian_params_second_derivatives.begin()) + third_derivs_output << ", "; + + int eq = it->first.first; + string var = symbol_table.getName(it->first.second.first); + string param1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first)); + string param2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second)); + expr_t d2 = it->second; + + third_derivs_output << "{\"eq\": " << eq + << ", \"var\": \"" << var << "\"" + << ", \"param1\": \"" << param1 << "\"" + << ", \"param2\": \"" << param2 << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(third_derivs_output, params_derivs_temporary_terms, tef_terms); + third_derivs_output << "\"}" << endl; + } + third_derivs_output << "]}" << endl; + + third_derivs1_output << "\"derivative_hessian_wrt_params\": {" + << " \"neqs\": " << equations.size() + << ", \"nvar1cols\": " << symbol_table.endo_nbr() + << ", \"nvar2cols\": " << symbol_table.endo_nbr() + << ", \"nparamcols\": " << symbol_table.param_nbr() + << ", \"entries\": ["; + for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin(); + it != hessian_params_derivatives.end(); ++it) + { + if (it != hessian_params_derivatives.begin()) + third_derivs1_output << ", "; + + int eq = it->first.first; + string var1 = symbol_table.getName(getSymbIDByDerivID(it->first.second.first)); + string var2 = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.first)); + string param = symbol_table.getName(getSymbIDByDerivID(it->first.second.second.second)); + expr_t d2 = it->second; + + third_derivs1_output << "{\"eq\": " << eq + << ", \"var1\": \"" << var1 << "\"" + << ", \"var2\": \"" << var2 << "\"" + << ", \"param1\": \"" << param << "\"" + << ", \"val\": \""; + d2->writeJsonOutput(third_derivs1_output, params_derivs_temporary_terms, tef_terms); + third_derivs1_output << "\"}" << endl; + } + third_derivs1_output << "]}" << endl; + + output << "\"static_model_params_derivatives\": {" + << model_local_vars_output.str() + << ", " << model_output.str() + << ", " << jacobian_output.str() + << ", " << hessian_output.str() + << ", " << hessian1_output.str() + << ", " << third_derivs_output.str() + << ", " << third_derivs1_output.str() + << "}"; +} diff --git a/StaticModel.hh b/StaticModel.hh index bf6cad6f..04d41e14 100644 --- a/StaticModel.hh +++ b/StaticModel.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -173,6 +173,12 @@ public: //! Writes static model file void writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, bool julia) const; + //! Write JSON representation of static model + void writeJsonComputingPassOutput(ostream &output) const; + + //! Writes file containing static parameters derivatives + void writeJsonParamsDerivativesFile(ostream &output) const; + //! Writes file containing static parameters derivatives void writeParamsDerivativesFile(const string &basename, bool julia) const; diff --git a/SymbolTable.cc b/SymbolTable.cc index 04b46de0..d6150183 100644 --- a/SymbolTable.cc +++ b/SymbolTable.cc @@ -1022,7 +1022,7 @@ void SymbolTable::writeJsonVarVector(ostream &output, const vector &varvec) const { output << "["; - for (int i = 0; i < varvec.size(); i++) + for (size_t i = 0; i < varvec.size(); i++) { output << endl << "{" << "\"name\":\"" << getName(varvec[i]) << "\", "