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