1 /* 2 * Copyright © 2003-2019 Dynare Team 3 * 4 * This file is part of Dynare. 5 * 6 * Dynare is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Dynare is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Dynare. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef _STATIC_MODEL_HH 21 #define _STATIC_MODEL_HH 22 23 using namespace std; 24 25 #include <fstream> 26 #include <filesystem> 27 28 #include "ModelTree.hh" 29 30 class DynamicModel; 31 32 //! Stores a static model, as derived from the "model" block when leads and lags have been removed 33 class StaticModel : public ModelTree 34 { 35 private: 36 //! global temporary terms for block decomposed models 37 vector<vector<temporary_terms_t>> v_temporary_terms; 38 39 //! local temporary terms for block decomposed models 40 vector<vector<temporary_terms_t>> v_temporary_terms_local; 41 42 vector<temporary_terms_inuse_t> v_temporary_terms_inuse; 43 44 using first_chain_rule_derivatives_t = map<tuple<int, int, int>, expr_t>; 45 first_chain_rule_derivatives_t first_chain_rule_derivatives; 46 47 //! Writes static model file (standard Matlab version) 48 void writeStaticMFile(const string &basename) const; 49 50 //! Writes static model file (C version) 51 void writeStaticCFile(const string &basename) const; 52 53 //! Writes static model file (Julia version) 54 void writeStaticJuliaFile(const string &basename) const; 55 56 //! Writes the static model equations and its derivatives 57 void writeStaticModel(const string &basename, ostream &StaticOutput, bool use_dll, bool julia) const; 58 59 //! Writes the static function calling the block to solve (Matlab version) 60 void writeStaticBlockMFSFile(const string &basename) const; 61 62 //! Writes the Block reordred structure of the model in M output 63 void writeModelEquationsOrdered_M(const string &basename) const; 64 65 //! Writes the code of the Block reordred structure of the model in virtual machine bytecode 66 void writeModelEquationsCode_Block(const string &basename, map_idx_t map_idx, vector<map_idx_t> map_idx2) const; 67 68 //! Writes the code of the model in virtual machine bytecode 69 void writeModelEquationsCode(const string &basename, map_idx_t map_idx) const; 70 71 //! Computes jacobian and prepares for equation normalization 72 /*! Using values from initval/endval blocks and parameter initializations: 73 - computes the jacobian for the model w.r. to contemporaneous variables 74 - removes edges of the incidence matrix when derivative w.r. to the corresponding variable is too close to zero (below the cutoff) 75 */ 76 void evaluateJacobian(const eval_context_t &eval_context, jacob_map_t *j_m, bool dynamic); 77 78 map_idx_t map_idx; 79 80 vector<map_idx_t> map_idx2; 81 82 //! sorts the temporary terms in the blocks order 83 void computeTemporaryTermsOrdered(); 84 //! creates a mapping from the index of temporary terms to a natural index 85 void computeTemporaryTermsMapping(temporary_terms_t &temporary_terms, map_idx_t &map_idx); 86 87 //! Write derivative code of an equation w.r. to a variable 88 void compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, map_idx_t &map_idx, temporary_terms_t temporary_terms) const; 89 //! Write chain rule derivative code of an equation w.r. to a variable 90 void compileChainRuleDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int var, int lag, map_idx_t &map_idx, temporary_terms_t temporary_terms) const; 91 92 //! Get the type corresponding to a derivation ID 93 SymbolType getTypeByDerivID(int deriv_id) const noexcept(false) override; 94 //! Get the lag corresponding to a derivation ID 95 int getLagByDerivID(int deriv_id) const noexcept(false) override; 96 //! Get the symbol ID corresponding to a derivation ID 97 int getSymbIDByDerivID(int deriv_id) const noexcept(false) override; 98 //! Compute the column indices of the static Jacobian 99 void computeStatJacobianCols(); 100 //! return a map on the block jacobian 101 map<tuple<int, int, int, int, int>, int> get_Derivatives(int block); 102 //! Computes chain rule derivatives of the Jacobian w.r. to endogenous variables 103 void computeChainRuleJacobian(blocks_derivatives_t &blocks_derivatives); 104 //! Collect only the first derivatives 105 map<tuple<int, int, int>, expr_t> collect_first_order_derivatives_endogenous(); 106 107 //! Collecte the derivatives w.r. to endogenous of the block, to endogenous of previouys blocks and to exogenous 108 void collect_block_first_order_derivatives(); 109 110 //! Indicate if the temporary terms are computed for the overall model (true) or not (false). Default value true 111 bool global_temporary_terms{true}; 112 113 //! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation 114 equation_type_and_normalized_equation_t equation_type_and_normalized_equation; 115 116 //! for each block contains pair< Simulation_Type, pair < Block_Size, Recursive_part_Size >> 117 block_type_firstequation_size_mfs_t block_type_firstequation_size_mfs; 118 119 //! for all blocks derivatives description 120 blocks_derivatives_t blocks_derivatives; 121 122 //! The jacobian without the elements below the cutoff 123 dynamic_jacob_map_t dynamic_jacobian; 124 125 //! Vector indicating if the block is linear in endogenous variable (true) or not (false) 126 vector<bool> blocks_linear; 127 128 //! Map the derivatives for a block tuple<lag, eq, var> 129 using derivative_t = map<tuple<int, int, int>, expr_t>; 130 //! Vector of derivative for each blocks 131 vector<derivative_t> derivative_endo, derivative_other_endo, derivative_exo, derivative_exo_det; 132 133 //!List for each block and for each lag-leag all the other endogenous variables and exogenous variables 134 using var_t = set<int>; 135 using lag_var_t = map<int, var_t>; 136 137 //! for each block described the number of static, forward, backward and mixed variables in the block 138 /*! tuple<static, forward, backward, mixed> */ 139 vector<tuple<int, int, int, int>> block_col_type; 140 141 //!Maximum lead and lag for each block on endogenous of the block, endogenous of the previous blocks, exogenous and deterministic exogenous 142 vector<pair<int, int>> endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block; 143 144 //! Helper functions for writeStaticModel 145 void writeStaticModelHelper(const string &basename, 146 const string &name, const string &retvalname, 147 const string &name_tt, size_t ttlen, 148 const string &previous_tt_name, 149 const ostringstream &init_s, const ostringstream &end_s, 150 const ostringstream &s, const ostringstream &s_tt) const; 151 void writeWrapperFunctions(const string &basename, const string &ending) const; 152 153 //! Create a legacy *_static.m file for Matlab/Octave not yet using the temporary terms array interface 154 void writeStaticMatlabCompatLayer(const string &name) const; 155 156 void writeStaticModel(ostream &DynamicOutput, bool use_dll, bool julia) const; 157 void writeStaticModel(const string &dynamic_basename, bool use_dll, bool julia) const; 158 159 //! Internal helper for the copy constructor and assignment operator 160 /*! Copies all the structures that contain ExprNode*, by the converting the 161 pointers into their equivalent in the new tree */ 162 void copyHelper(const StaticModel &m); 163 164 public: 165 StaticModel(SymbolTable &symbol_table_arg, 166 NumericalConstants &num_constants, 167 ExternalFunctionsTable &external_functions_table_arg); 168 169 StaticModel(const StaticModel &m); 170 StaticModel(StaticModel &&) = delete; 171 StaticModel &operator=(const StaticModel &m); 172 /* The move assignment operator is not explicitly deleted, otherwise the 173 static_cast from DynamicModel does not work. However it looks like this 174 operator will not be used in the end. See 175 https://en.cppreference.com/w/cpp/language/copy_initialization 176 With C++17, it should be possible to explicitly delete it */ 177 //StaticModel & operator=(StaticModel &&) = delete; 178 179 //! Creates the static version of a dynamic model 180 explicit StaticModel(const DynamicModel &m); 181 182 //! Writes information on block decomposition when relevant 183 void writeOutput(ostream &output, bool block) const; 184 185 //! Execute computations (variable sorting + derivation) 186 /*! 187 \param eval_context evaluation context for normalization 188 \param no_tmp_terms if true, no temporary terms will be computed in the static files 189 \param derivsOrder order of derivation with respect to endogenous 190 \param paramsDerivsOrder order of derivatives w.r. to a pair (endogenous, parameter) to be computed 191 */ 192 void computingPass(int derivsOrder, int paramsDerivsOrder, const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool bytecode); 193 194 //! Adds informations for simulation in a binary file for a block decomposed model 195 void Write_Inf_To_Bin_File_Block(const string &basename, int num, 196 int &u_count_int, bool &file_open) const; 197 198 //! Writes static model file 199 void writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const; 200 201 //! Write JSON Output (used by PlannerObjectiveStatement) 202 void writeJsonOutput(ostream &output) const; 203 204 //! Write JSON representation of static model 205 void writeJsonComputingPassOutput(ostream &output, bool writeDetails) const; 206 207 //! Writes file containing static parameters derivatives 208 void writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const; 209 210 //! Writes file containing static parameters derivatives 211 void writeParamsDerivativesFile(const string &basename, bool julia) const; 212 213 //! Writes LaTeX file with the equations of the static model 214 void writeLatexFile(const string &basename, bool write_equation_tags) const; 215 216 //! Writes initializations in oo_.steady_state or steady state file for the auxiliary variables 217 void writeAuxVarInitval(ostream &output, ExprNodeOutputType output_type) const; 218 219 //! Writes definition of the auxiliary variables in a .m or .jl file 220 void writeSetAuxiliaryVariables(const string &basename, bool julia) const; 221 void writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputType output_type) const; 222 void writeLatexAuxVarRecursiveDefinitions(ostream &output) const; 223 void writeJsonAuxVarRecursiveDefinitions(ostream &output) const; 224 225 //! To ensure that no exogenous is present in the planner objective 226 //! See #1264 227 bool exoPresentInEqs() const; 228 229 int getDerivID(int symb_id, int lag) const noexcept(false) override; 230 void addAllParamDerivId(set<int> &deriv_id_set) override; 231 232 //! Return the number of blocks 233 unsigned int getNbBlocks() const234 getNbBlocks() const override 235 { 236 return (block_type_firstequation_size_mfs.size()); 237 }; 238 //! Determine the simulation type of each block 239 BlockSimulationType getBlockSimulationType(int block_number) const240 getBlockSimulationType(int block_number) const override 241 { 242 return (get<0>(block_type_firstequation_size_mfs[block_number])); 243 }; 244 //! Return the first equation number of a block 245 unsigned int getBlockFirstEquation(int block_number) const246 getBlockFirstEquation(int block_number) const override 247 { 248 return (get<1>(block_type_firstequation_size_mfs[block_number])); 249 }; 250 //! Return the size of the block block_number 251 unsigned int getBlockSize(int block_number) const252 getBlockSize(int block_number) const override 253 { 254 return (get<2>(block_type_firstequation_size_mfs[block_number])); 255 }; 256 //! Return the number of exogenous variable in the block block_number 257 unsigned int getBlockExoSize(int block_number) const258 getBlockExoSize(int block_number) const override 259 { 260 return 0; 261 }; 262 //! Return the number of colums in the jacobian matrix for exogenous variable in the block block_number 263 unsigned int getBlockExoColSize(int block_number) const264 getBlockExoColSize(int block_number) const override 265 { 266 return 0; 267 } 268 //! Return the number of feedback variable of the block block_number 269 unsigned int getBlockMfs(int block_number) const270 getBlockMfs(int block_number) const override 271 { 272 return (get<3>(block_type_firstequation_size_mfs[block_number])); 273 }; 274 //! Return the maximum lag in a block 275 unsigned int getBlockMaxLag(int block_number) const276 getBlockMaxLag(int block_number) const override 277 { 278 return (block_lag_lead[block_number].first); 279 }; 280 //! Return the maximum lead in a block 281 unsigned int getBlockMaxLead(int block_number) const282 getBlockMaxLead(int block_number) const override 283 { 284 return (block_lag_lead[block_number].second); 285 }; 286 //! Return the type of equation (equation_number) belonging to the block block_number 287 EquationType getBlockEquationType(int block_number,int equation_number) const288 getBlockEquationType(int block_number, int equation_number) const override 289 { 290 return (equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].first); 291 }; 292 //! Return true if the equation has been normalized 293 bool isBlockEquationRenormalized(int block_number,int equation_number) const294 isBlockEquationRenormalized(int block_number, int equation_number) const override 295 { 296 return (equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].first == E_EVALUATE_S); 297 }; 298 //! Return the expr_t of the equation equation_number belonging to the block block_number 299 expr_t getBlockEquationExpr(int block_number,int equation_number) const300 getBlockEquationExpr(int block_number, int equation_number) const override 301 { 302 return (equations[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]]); 303 }; 304 //! Return the expr_t of the renormalized equation equation_number belonging to the block block_number 305 expr_t getBlockEquationRenormalizedExpr(int block_number,int equation_number) const306 getBlockEquationRenormalizedExpr(int block_number, int equation_number) const override 307 { 308 return (equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].second); 309 }; 310 //! Return the original number of equation equation_number belonging to the block block_number 311 int getBlockEquationID(int block_number,int equation_number) const312 getBlockEquationID(int block_number, int equation_number) const override 313 { 314 return (equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]); 315 }; 316 //! Return the original number of variable variable_number belonging to the block block_number 317 int getBlockVariableID(int block_number,int variable_number) const318 getBlockVariableID(int block_number, int variable_number) const override 319 { 320 return (variable_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+variable_number]); 321 }; 322 //! Return the original number of the exogenous variable varexo_number belonging to the block block_number 323 int getBlockVariableExoID(int block_number,int variable_number) const324 getBlockVariableExoID(int block_number, int variable_number) const override 325 { 326 return 0; 327 }; 328 //! Return the position of equation_number in the block number belonging to the block block_number 329 int getBlockInitialEquationID(int block_number,int equation_number) const330 getBlockInitialEquationID(int block_number, int equation_number) const override 331 { 332 return (static_cast<int>(inv_equation_reordered[equation_number]) - static_cast<int>(get<1>(block_type_firstequation_size_mfs[block_number]))); 333 }; 334 //! Return the position of variable_number in the block number belonging to the block block_number 335 int getBlockInitialVariableID(int block_number,int variable_number) const336 getBlockInitialVariableID(int block_number, int variable_number) const override 337 { 338 return (static_cast<int>(inv_variable_reordered[variable_number]) - static_cast<int>(get<1>(block_type_firstequation_size_mfs[block_number]))); 339 }; 340 //! Return the position of variable_number in the block number belonging to the block block_number 341 int getBlockInitialExogenousID(int block_number,int variable_number) const342 getBlockInitialExogenousID(int block_number, int variable_number) const override 343 { 344 return -1; 345 }; 346 //! Return the position of the deterministic exogenous variable_number in the block number belonging to the block block_number 347 int getBlockInitialDetExogenousID(int block_number,int variable_number) const348 getBlockInitialDetExogenousID(int block_number, int variable_number) const override 349 { 350 return -1; 351 }; 352 //! Return the position of the other endogenous variable_number in the block number belonging to the block block_number 353 int getBlockInitialOtherEndogenousID(int block_number,int variable_number) const354 getBlockInitialOtherEndogenousID(int block_number, int variable_number) const override 355 { 356 return -1; 357 }; 358 }; 359 360 #endif 361