From 64642d928c49d81ac016501b44b38b7cdb9f2752 Mon Sep 17 00:00:00 2001 From: Houtan Bastani Date: Thu, 2 Feb 2017 15:09:43 +0100 Subject: [PATCH] preprocessor: write JSON output. #1387 --- DynamicModel.cc | 7 + DynamicModel.hh | 5 +- DynareMain.cc | 11 +- DynareMain2.cc | 8 + ExprNode.cc | 330 ++++++++++++++++++++++++++++++++++- ExprNode.hh | 15 +- ExtendedPreprocessorTypes.hh | 8 +- ModFile.cc | 69 ++++++++ ModFile.hh | 5 + ModelTree.cc | 35 ++++ ModelTree.hh | 2 + NumericalInitialization.cc | 62 ++++++- NumericalInitialization.hh | 7 +- Statement.cc | 6 +- Statement.hh | 3 +- SymbolTable.cc | 85 ++++++++- SymbolTable.hh | 10 +- 17 files changed, 656 insertions(+), 12 deletions(-) diff --git a/DynamicModel.cc b/DynamicModel.cc index 08dd2bc4..704592da 100644 --- a/DynamicModel.cc +++ b/DynamicModel.cc @@ -5336,3 +5336,10 @@ DynamicModel::writeCCOutput(ostream &output, const string &basename, bool block_ output << "NNZDerivatives.push_back(-1);" << endl << "NNZDerivatives.push_back(-1);" << endl; } + + +void +DynamicModel::writeJsonOutput(ostream &output) const +{ + writeJsonModelEquations(output); +} diff --git a/DynamicModel.hh b/DynamicModel.hh index 6b99423c..e79ac7f4 100644 --- a/DynamicModel.hh +++ b/DynamicModel.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -217,6 +217,9 @@ public: //! Writes model initialization and lead/lag incidence matrix to output void writeOutput(ostream &output, const string &basename, bool block, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const; + //! Write JSON Output + void writeJsonOutput(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 adbb1b68..c5650926 100644 --- a/DynareMain.cc +++ b/DynareMain.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -45,6 +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 ); void main1(char *modfile, string &basename, bool debug, bool save_macro, string &save_macro_file, @@ -61,6 +62,7 @@ usage() #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) << " [cygwin] [msvc] [mingw]" #endif + << "[json] [jsonstdout]" << endl; exit(EXIT_FAILURE); } @@ -113,6 +115,8 @@ main(int argc, char **argv) map defines; vector path; FileOutputType output_mode = none; + bool json = false; + JsonFileOutputType json_output_mode = file; LanguageOutputType language = matlab; // Parse options @@ -291,6 +295,10 @@ main(int argc, char **argv) } } } + else if (!strcmp(argv[arg], "jsonstdout")) + json_output_mode = standardout; + else if (!strcmp(argv[arg], "json")) + json = true; else { cerr << "Unknown option: " << argv[arg] << endl; @@ -337,6 +345,7 @@ main(int argc, char **argv) #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) , cygwin, msvc, mingw #endif + , json, json_output_mode ); return EXIT_SUCCESS; diff --git a/DynareMain2.cc b/DynareMain2.cc index bc5065b2..3bbc4b4f 100644 --- a/DynareMain2.cc +++ b/DynareMain2.cc @@ -34,12 +34,20 @@ 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 ) { 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; + } // Run checking pass mod_file->checkPass(nostrict); diff --git a/ExprNode.cc b/ExprNode.cc index d7d8374c..ccba75c2 100644 --- a/ExprNode.cc +++ b/ExprNode.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2016 Dynare Team + * Copyright (C) 2007-2017 Dynare Team * * This file is part of Dynare. * @@ -322,6 +322,14 @@ NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type, output << datatree.num_constants.get(id); } +void +NumConstNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + output << datatree.num_constants.get(id); +} + bool NumConstNode::containsExternalFunction() const { @@ -615,6 +623,16 @@ VariableNode::containsExternalFunction() const return false; } +void +VariableNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + output << datatree.symbol_table.getName(symb_id); + if (lag != 0) + output << "(" << lag << ")"; +} + void VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -1850,6 +1868,141 @@ UnaryOpNode::containsExternalFunction() const return arg->containsExternalFunction(); } +void +UnaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + // Always put parenthesis around uminus nodes + if (op_code == oUminus) + output << LEFT_PAR(output_type); + + switch (op_code) + { + case oUminus: + output << "-"; + break; + case oExp: + output << "exp"; + break; + case oLog: + output << "log"; + break; + case oLog10: + output << "log10"; + break; + case oCos: + output << "cos"; + break; + case oSin: + output << "sin"; + break; + case oTan: + output << "tan"; + break; + case oAcos: + output << "acos"; + break; + case oAsin: + output << "asin"; + break; + case oAtan: + output << "atan"; + break; + case oCosh: + output << "cosh"; + break; + case oSinh: + output << "sinh"; + break; + case oTanh: + output << "tanh"; + break; + case oAcosh: + output << "acosh"; + break; + case oAsinh: + output << "asinh"; + break; + case oAtanh: + output << "atanh"; + break; + case oSqrt: + output << "sqrt"; + break; + case oAbs: + output << "abs"; + break; + case oSign: + output << "sign"; + break; + case oSteadyState: + output << "("; + arg->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + output << ")"; + return; + case oSteadyStateParamDeriv: + { + VariableNode *varg = dynamic_cast(arg); + assert(varg != NULL); + assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous); + 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; + case oSteadyStateParam2ndDeriv: + { + VariableNode *varg = dynamic_cast(arg); + assert(varg != NULL); + assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous); + assert(datatree.symbol_table.getType(param1_symb_id) == eParameter); + assert(datatree.symbol_table.getType(param2_symb_id) == eParameter); + 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 << ")"; + } + return; + case oExpectation: + output << "EXPECTATION(" << expectation_information_set << ")"; + break; + case oErf: + output << "erf"; + break; + } + + bool close_parenthesis = false; + + /* Enclose argument with parentheses if: + - current opcode is not uminus, or + - current opcode is uminus and argument has lowest precedence + */ + if (op_code != oUminus + || (op_code == oUminus + && arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms))) + { + output << LEFT_PAR(output_type); + if (op_code == oSign && (output_type == oCDynamicModel || output_type == oCStaticModel)) + output << "1.0,"; + close_parenthesis = true; + } + + // Write argument + arg->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + + if (close_parenthesis) + output << RIGHT_PAR(output_type); + + // Close parenthesis for uminus + if (op_code == oUminus) + output << RIGHT_PAR(output_type); +} + void UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -3072,6 +3225,119 @@ BinaryOpNode::containsExternalFunction() const || arg2->containsExternalFunction(); } +void +BinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + if (op_code == oMax || op_code == oMin) + { + switch (op_code) + { + case oMax: + output << "max("; + break; + case oMin: + output << "min("; + break; + default: + ; + } + arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + output << ","; + arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + output << ")"; + return; + } + + int prec = precedence(output_type, 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 + || (op_code == oPower && barg1 != NULL && barg1->op_code == oPower)) + { + output << LEFT_PAR(output_type); + close_parenthesis = true; + } + + // Write left argument + arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + + if (close_parenthesis) + output << RIGHT_PAR(output_type); + + // Write current operator symbol + switch (op_code) + { + case oPlus: + output << "+"; + break; + case oMinus: + output << "-"; + break; + case oTimes: + output << "*"; + break; + case oDivide: + output << "/"; + break; + case oPower: + output << "^"; + break; + case oLess: + output << "<"; + break; + case oGreater: + output << ">"; + break; + case oLessEqual: + output << "<="; + break; + case oGreaterEqual: + output << ">="; + break; + case oEqualEqual: + output << "=="; + break; + case oDifferent: + output << "!="; + break; + case oEqual: + output << "="; + break; + default: + ; + } + + close_parenthesis = false; + + /* Add parenthesis around right argument if: + - its precedence is lower than those of the current node + - it is a power operator and current operator is also a power operator + - 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); + if (arg2_prec < prec + || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower && !IS_LATEX(output_type)) + || (op_code == oMinus && arg2_prec == prec) + || (op_code == oDivide && arg2_prec == prec && !IS_LATEX(output_type))) + { + output << LEFT_PAR(output_type); + close_parenthesis = true; + } + + // Write right argument + arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + + if (close_parenthesis) + output << RIGHT_PAR(output_type); +} + void BinaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -4211,6 +4477,29 @@ TrinaryOpNode::containsExternalFunction() const || arg3->containsExternalFunction(); } +void +TrinaryOpNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + switch (op_code) + { + case oNormcdf: + output << "normcdf("; + break; + case oNormpdf: + output << "normpdf("; + break; + } + + arg1->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + output << ","; + arg2->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + output << ","; + arg3->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + output << ")"; +} + void TrinaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -4891,6 +5180,21 @@ AbstractExternalFunctionNode::writeExternalFunctionArguments(ostream &output, Ex } } +void +AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + for (vector::const_iterator it = arguments.begin(); + it != arguments.end(); it++) + { + if (it != arguments.begin()) + output << ","; + + (*it)->writeJsonOutput(output, output_type, temporary_terms, tef_terms); + } +} + void AbstractExternalFunctionNode::writePrhs(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -5054,6 +5358,16 @@ ExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsign } } +void +ExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ + output << datatree.symbol_table.getName(symb_id) << "("; + writeJsonExternalFunctionArguments(output, output_type, temporary_terms, tef_terms); + output << ")"; +} + void ExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -5244,6 +5558,13 @@ FirstDerivExternalFunctionNode::composeDerivatives(const vector &dargs) return theDeriv; } +void +FirstDerivExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ +} + void FirstDerivExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -5556,6 +5877,13 @@ SecondDerivExternalFunctionNode::composeDerivatives(const vector &dargs) exit(EXIT_FAILURE); } +void +SecondDerivExternalFunctionNode::writeJsonOutput(ostream &output, ExprNodeOutputType output_type, + const temporary_terms_t &temporary_terms, + deriv_node_temp_terms_t &tef_terms) const +{ +} + void SecondDerivExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, diff --git a/ExprNode.hh b/ExprNode.hh index 0440d807..32654071 100644 --- a/ExprNode.hh +++ b/ExprNode.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2016 Dynare Team + * Copyright (C) 2007-2017 Dynare Team * * This file is part of Dynare. * @@ -221,6 +221,9 @@ public: //! Writes output of node, using a Txxx notation for nodes in temporary_terms 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; + //! 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, @@ -478,6 +481,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 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; @@ -527,6 +531,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 bool containsExternalFunction() const; virtual void collectDynamicVariables(SymbolType type_arg, set > &result) const; virtual void computeTemporaryTerms(map &reference_count, @@ -602,6 +607,7 @@ 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 bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -689,6 +695,7 @@ 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 bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -794,6 +801,7 @@ 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 bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -864,6 +872,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; public: AbstractExternalFunctionNode(DataTree &datatree_arg, int symb_id_arg, const vector &arguments_arg); @@ -872,6 +881,7 @@ 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 bool containsExternalFunction() const; virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, @@ -938,6 +948,7 @@ 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 writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const; @@ -978,6 +989,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 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, @@ -1017,6 +1029,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 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, diff --git a/ExtendedPreprocessorTypes.hh b/ExtendedPreprocessorTypes.hh index e0a955f2..1388cafc 100644 --- a/ExtendedPreprocessorTypes.hh +++ b/ExtendedPreprocessorTypes.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Dynare Team + * Copyright (C) 2014-2017 Dynare Team * * This file is part of Dynare. * @@ -38,4 +38,10 @@ enum LanguageOutputType julia, // outputs files for Julia python, // outputs files for Python (not yet implemented) (not yet implemented) }; + +enum JsonFileOutputType + { + file, // output JSON files to file + standardout, // output JSON files to stdout + }; #endif diff --git a/ModFile.cc b/ModFile.cc index 794f1e46..d2698873 100644 --- a/ModFile.cc +++ b/ModFile.cc @@ -1246,3 +1246,72 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output) jlOutputFile.close(); cout << "done" << endl; } + +void +ModFile::writeJsonOutput(const string &basename, JsonFileOutputType json_output_mode) const +{ + ostringstream output; + output << "{" << endl; + + symbol_table.writeJsonOutput(output); + dynamic_model.writeJsonOutput(output); + + if (!statements.empty()) + { + output << ",\"statements\": ["; + bool printed_statement = false; + for (vector::const_iterator it = statements.begin(); + it != statements.end();) + { + (*it)->writeJsonOutput(output); + + if (dynamic_cast(*it) != NULL || + dynamic_cast(*it) != NULL || + dynamic_cast(*it) != NULL || + dynamic_cast(*it) != NULL) + printed_statement = true; + + if (++it == statements.end()) + break; + + // tests to see if the next statement will be one for which we support writing JSON files + // to be deleted once we support all statements + if (printed_statement && + (dynamic_cast(*it) != NULL || + dynamic_cast(*it) != NULL || + dynamic_cast(*it) != NULL || + dynamic_cast(*it) != NULL)) + output << "," << endl; + } + output << "]" << endl; + } + + output << "}" << endl; + + if (json_output_mode == standardout) + cout << output.str(); + else + { + ofstream jsonOutputFile; + + if (basename.size()) + { + string fname(basename); + fname += ".json"; + jsonOutputFile.open(fname.c_str(), ios::out | ios::binary); + if (!jsonOutputFile.is_open()) + { + cerr << "ERROR: Can't open file " << fname << " for writing" << endl; + exit(EXIT_FAILURE); + } + } + else + { + cerr << "ERROR: Missing file name" << endl; + exit(EXIT_FAILURE); + } + + jsonOutputFile << output.str(); + jsonOutputFile.close(); + } +} diff --git a/ModFile.hh b/ModFile.hh index 6ed24d33..b83f984d 100644 --- a/ModFile.hh +++ b/ModFile.hh @@ -167,6 +167,11 @@ public: void writeModelCC(const string &basename) const; void computeChecksum(); + //! Write JSON representation of ModFile object + //! 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; }; #endif // ! MOD_FILE_HH diff --git a/ModelTree.cc b/ModelTree.cc index 70db28e0..444aec2b 100644 --- a/ModelTree.cc +++ b/ModelTree.cc @@ -1919,3 +1919,38 @@ bool ModelTree::isNonstationary(int symb_id) const != nonstationary_symbols_map.end()); } +void +ModelTree::writeJsonModelEquations(ostream &output) const +{ + deriv_node_temp_terms_t tef_terms; + vector > eqtags; + 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 (!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 << "}"; + if (eq < (int) equations.size() - 1) + output << "," << endl; + } + output << endl << "]" << endl; +} diff --git a/ModelTree.hh b/ModelTree.hh index 9b28fce4..d74598d8 100644 --- a/ModelTree.hh +++ b/ModelTree.hh @@ -199,6 +199,8 @@ protected: void writeModelLocalVariables(ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const; //! Writes model equations void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const; + //! Writes JSON model equations + void writeJsonModelEquations(ostream &output) 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 3bbd803e..6e4dcd26 100644 --- a/NumericalInitialization.cc +++ b/NumericalInitialization.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -63,6 +63,14 @@ InitParamStatement::writeJuliaOutput(ostream &output, const string &basename) // output << symbol_table.getName(symb_id) << " = model_.params[ " << id << " ]" << endl; } +void +InitParamStatement::writeJsonOutput(ostream &output) const +{ + output << "{\"statementName\": \"param_init\", \"name\": \"" << symbol_table.getName(symb_id) << "\", " << "\"value\": "; + param_value->writeOutput(output); + output << "}"; +} + void InitParamStatement::writeCOutput(ostream &output, const string &basename) { @@ -165,6 +173,22 @@ InitOrEndValStatement::writeInitValues(ostream &output) const } } +void +InitOrEndValStatement::writeJsonInitValues(ostream &output) const +{ + int i = 0; + deriv_node_temp_terms_t tef_terms; + for (init_values_t::const_iterator it = init_values.begin(); + it != init_values.end(); it++, i++) + { + output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", " << "\"value\": \""; + it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + output << "\"}"; + if (i < init_values.size() - 1) + output << ", "; + } +} + InitValStatement::InitValStatement(const init_values_t &init_values_arg, const SymbolTable &symbol_table_arg, const bool &all_values_required_arg) : @@ -210,6 +234,14 @@ InitValStatement::writeOutput(ostream &output, const string &basename, bool mini writeInitValues(output); } +void +InitValStatement::writeJsonOutput(ostream &output) const +{ + output << "{\"statementName\": \"init_val\", \"vals\": ["; + writeJsonInitValues(output); + output << "]}"; +} + void InitValStatement::writeOutputPostInit(ostream &output) const { @@ -267,6 +299,14 @@ EndValStatement::writeOutput(ostream &output, const string &basename, bool minim writeInitValues(output); } +void +EndValStatement::writeJsonOutput(ostream &output) const +{ + output << "{\"statementName\": \"end_val\", \"vals\": ["; + writeJsonInitValues(output); + output << "]}"; +} + HistValStatement::HistValStatement(const hist_values_t &hist_values_arg, const SymbolTable &symbol_table_arg, const bool &all_values_required_arg) : @@ -375,6 +415,26 @@ HistValStatement::writeOutput(ostream &output, const string &basename, bool mini } } +void +HistValStatement::writeJsonOutput(ostream &output) const +{ + int i = 0; + deriv_node_temp_terms_t tef_terms; + output << "{\"statementName\": \"hist_val\", \"vals\": ["; + for (hist_values_t::const_iterator it = hist_values.begin(); + it != hist_values.end(); it++) + { + output << "{ \"name\": \"" << symbol_table.getName(it->first.first) << "\"" + << ", \"lag\": " << it->first.second + << ", \"value\": \""; + it->second->writeJsonOutput(output, oMatlabOutsideModel, temporary_terms_t(), tef_terms); + output << "\"}"; + if (i < hist_values.size() - 1) + output << ", "; + } + output << "]}"; +} + InitvalFileStatement::InitvalFileStatement(const string &filename_arg) : filename(filename_arg) { diff --git a/NumericalInitialization.hh b/NumericalInitialization.hh index 2e34677b..e48cb9ee 100644 --- a/NumericalInitialization.hh +++ b/NumericalInitialization.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -43,6 +43,7 @@ public: virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const; virtual void writeJuliaOutput(ostream &output, const string &basename); virtual void writeCOutput(ostream &output, const string &basename); + virtual void writeJsonOutput(ostream &output) const; //! Fill eval context with parameter value void fillEvalContext(eval_context_t &eval_context) const; }; @@ -69,6 +70,7 @@ public: void fillEvalContext(eval_context_t &eval_context) const; protected: void writeInitValues(ostream &output) const; + void writeJsonInitValues(ostream &output) const; }; class InitValStatement : public InitOrEndValStatement @@ -79,6 +81,7 @@ public: const bool &all_values_required_arg); virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings); virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const; + virtual void writeJsonOutput(ostream &output) const; //! Writes initializations for oo_.exo_simul and oo_.exo_det_simul void writeOutputPostInit(ostream &output) const; }; @@ -92,6 +95,7 @@ public: //! Workaround for trac ticket #35 virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings); virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const; + virtual void writeJsonOutput(ostream &output) const; }; class HistValStatement : public Statement @@ -114,6 +118,7 @@ public: //! Workaround for trac ticket #157 virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings); virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const; + virtual void writeJsonOutput(ostream &output) const; }; class InitvalFileStatement : public Statement diff --git a/Statement.cc b/Statement.cc index 887603b6..ee18bbb8 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2015 Dynare Team + * Copyright (C) 2006-2017 Dynare Team * * This file is part of Dynare. * @@ -82,6 +82,10 @@ void Statement::writeJuliaOutput(ostream &output, const string &basename) { } +void Statement::writeJsonOutput(ostream &output) const +{ +} + void Statement::computingPass() { diff --git a/Statement.hh b/Statement.hh index 311260b0..0db8a3c8 100644 --- a/Statement.hh +++ b/Statement.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2015 Dynare Team + * Copyright (C) 2006-2017 Dynare Team * * This file is part of Dynare. * @@ -144,6 +144,7 @@ public: virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const = 0; virtual void writeCOutput(ostream &output, const string &basename); virtual void writeJuliaOutput(ostream &output, const string &basename); + virtual void writeJsonOutput(ostream &output) const; }; class NativeStatement : public Statement diff --git a/SymbolTable.cc b/SymbolTable.cc index 17b63e95..84deb2a5 100644 --- a/SymbolTable.cc +++ b/SymbolTable.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -21,6 +21,7 @@ #include #include #include +#include #include "SymbolTable.hh" @@ -138,6 +139,17 @@ SymbolTable::freeze() throw (FrozenException) } } +void +SymbolTable::unfreeze() +{ + frozen = false; + endo_ids.clear(); + exo_ids.clear(); + exo_det_ids.clear(); + param_ids.clear(); + type_specific_ids.clear(); +} + void SymbolTable::changeType(int id, SymbolType newtype) throw (UnknownSymbolIDException, FrozenException) { @@ -950,3 +962,74 @@ SymbolTable::writeJuliaOutput(ostream &output) const throw (NotYetFrozenExceptio output << " ]" << endl; } } + +void +SymbolTable::writeJsonOutput(ostream &output) const +{/* + vector endos, exos, exo_dets, params; + for (int i = 0; i < size; i++) + { + switch (getType(i)) + { + case eEndogenous: + endos.push_back(i); + break; + case eExogenous: + exos.push_back(i); + break; + case eExogenousDet: + exo_dets.push_back(i); + break; + case eParameter: + params.push_back(i); + break; + default: + break; + } + } + */ + + if (!endo_ids.empty()) + { + output << "\"endogenous\":"; + writeJsonVarVector(output, endo_ids); + output << endl; + } + + if (!exo_ids.empty()) + { + output << ",\"exogenous\":"; + writeJsonVarVector(output, exo_ids); + output << endl; + } + + if (!exo_det_ids.empty()) + { + output << ",\"exogenous_deterministic\":"; + writeJsonVarVector(output, exo_det_ids); + output << endl; + } + + if (!param_ids.empty()) + { + output << ",\"parameters\":"; + writeJsonVarVector(output, param_ids); + cout << endl; + } +} + +void +SymbolTable::writeJsonVarVector(ostream &output, const vector &varvec) const +{ + output << "["; + for (int i = 0; i < varvec.size(); i++) + { + output << endl << "{" + << "\"name\":\" " << getName(varvec[i]) << "\", " + << "\"texName\":\" " << boost::replace_all_copy(getTeXName(varvec[i]), "\\", "\\\\") << "\", " + << "\"longName\":\" " << boost::replace_all_copy(getLongName(varvec[i]), "\\", "\\\\") << "\"}"; + if (i < varvec.size() - 1) + output << ", "; + } + output << endl << "]"; +} diff --git a/SymbolTable.hh b/SymbolTable.hh index c99dd462..370c5e77 100644 --- a/SymbolTable.hh +++ b/SymbolTable.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2016 Dynare Team + * Copyright (C) 2003-2017 Dynare Team * * This file is part of Dynare. * @@ -192,7 +192,8 @@ private: int addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag, expr_t arg) throw (FrozenException); //! Factorized code for adding aux lead variables int addLeadAuxiliaryVarInternal(bool endo, int index, expr_t arg) throw (FrozenException); - + //! Factorized code for Json writing + void writeJsonVarVector(ostream &output, const vector &varvec) const; public: //! Add a symbol /*! Returns the symbol ID */ @@ -274,6 +275,9 @@ public: int getID(SymbolType type, int tsid) const throw (UnknownTypeSpecificIDException, NotYetFrozenException); //! Freeze symbol table void freeze() throw (FrozenException); + //! unreeze symbol table + //! Used after having written JSON files + void unfreeze(); //! Change the type of a symbol void changeType(int id, SymbolType newtype) throw (UnknownSymbolIDException, FrozenException); //! Get type specific ID (by symbol ID) @@ -294,6 +298,8 @@ public: inline int orig_endo_nbr() const throw (NotYetFrozenException); //! Write output of this class void writeOutput(ostream &output) const throw (NotYetFrozenException); + //! Write JSON Output + void writeJsonOutput(ostream &output) const; //! Write Julia output of this class void writeJuliaOutput(ostream &output) const throw (NotYetFrozenException); //! Write C output of this class