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 _DYNAMICMODEL_HH
21 #define _DYNAMICMODEL_HH
22 
23 using namespace std;
24 
25 #include <fstream>
26 #include <filesystem>
27 
28 #include "StaticModel.hh"
29 
30 //! Stores a dynamic model
31 class DynamicModel : public ModelTree
32 {
33 public:
34   //! A reference to the trend component model table
35   TrendComponentModelTable &trend_component_model_table;
36   //! A reference to the VAR model table
37   VarModelTable &var_model_table;
38   /* Used in the balanced growth test, for determining whether the
39      cross-derivative of a given equation, w.r.t. an endogenous and a trend
40      variable is zero. Controlled by option “balanced_growth_test_tol” of the
41      “model” block. The default should not be too small (see dynare#1389). */
42   double balanced_growth_test_tol{1e-6};
43 private:
44   /* Used in the balanced growth test, for skipping equations where the test
45      cannot be performed (i.e. when LHS=RHS at the initial values). Should not
46      be too large, otherwise the test becomes less powerful. */
47   constexpr static double zero_band{1e-8};
48 
49   //! Stores equations declared as [static]
50   /*! They will be used in the conversion to StaticModel to replace equations marked as [dynamic] */
51   vector<BinaryOpNode *> static_only_equations;
52 
53   //! Stores line numbers of equations declared as [static]
54   vector<int> static_only_equations_lineno;
55 
56   //! Stores the equation tags of equations declared as [static]
57   vector<vector<pair<string, string>>> static_only_equations_equation_tags;
58 
59   //! Stores mapping from equation tags to equation number
60   multimap<pair<string, string>, int> static_only_equation_tags_xref;
61 
62   using deriv_id_table_t = map<pair<int, int>, int>;
63   //! Maps a pair (symbol_id, lag) to a deriv ID
64   deriv_id_table_t deriv_id_table;
65   //! Maps a deriv ID to a pair (symbol_id, lag)
66   vector<pair<int, int>> inv_deriv_id_table;
67 
68   //! Maps a deriv_id to the column index of the dynamic Jacobian
69   /*! Contains only endogenous, exogenous and exogenous deterministic */
70   map<int, int> dyn_jacobian_cols_table;
71 
72   //! Maximum lag and lead over all types of variables (positive values)
73   /*! Set by computeDerivIDs() */
74   int max_lag{0}, max_lead{0};
75   //! Maximum lag and lead over endogenous variables (positive values)
76   /*! Set by computeDerivIDs() */
77   int max_endo_lag{0}, max_endo_lead{0};
78   //! Maximum lag and lead over exogenous variables (positive values)
79   /*! Set by computeDerivIDs() */
80   int max_exo_lag{0}, max_exo_lead{0};
81   //! Maximum lag and lead over deterministic exogenous variables (positive values)
82   /*! Set by computeDerivIDs() */
83   int max_exo_det_lag{0}, max_exo_det_lead{0};
84   //! Maximum lag and lead over all types of variables (positive values) of original model
85   int max_lag_orig{0}, max_lead_orig{0}, max_lag_with_diffs_expanded_orig{0};
86   //! Maximum lag and lead over endogenous variables (positive values) of original model
87   int max_endo_lag_orig{0}, max_endo_lead_orig{0};
88   //! Maximum lag and lead over exogenous variables (positive values) of original model
89   int max_exo_lag_orig{0}, max_exo_lead_orig{0};
90   //! Maximum lag and lead over deterministic exogenous variables (positive values) of original model
91   int max_exo_det_lag_orig{0}, max_exo_det_lead_orig{0};
92 
93   //! Cross reference information
94   map<int, ExprNode::EquationInfo> xrefs;
95   map<pair<int, int>, set<int>> xref_param;
96   map<pair<int, int>, set<int>> xref_endo;
97   map<pair<int, int>, set<int>> xref_exo;
98   map<pair<int, int>, set<int>> xref_exo_det;
99 
100   //! Nonzero equations in the Hessian
101   set<int> nonzero_hessian_eqs;
102 
103   //! Number of columns of dynamic jacobian
104   /*! Set by computeDerivID()s and computeDynJacobianCols() */
105   int dynJacobianColsNbr{0};
106   //! Temporary terms for block decomposed models
107   vector<vector<temporary_terms_t>> v_temporary_terms;
108 
109   vector<temporary_terms_inuse_t> v_temporary_terms_inuse;
110 
111   //! Creates mapping for variables and equations they are present in
112   map<int, set<int>> variableMapping;
113 
114   //! Store the derivatives or the chainrule derivatives:map<tuple<equation, variable, lead_lag>, expr_t>
115   using first_chain_rule_derivatives_t = map<tuple<int, int, int>, expr_t>;
116   first_chain_rule_derivatives_t first_chain_rule_derivatives;
117 
118   //! Writes dynamic model file (Matlab version)
119   void writeDynamicMFile(const string &basename) const;
120   //! Writes dynamic model file (Julia version)
121   void writeDynamicJuliaFile(const string &dynamic_basename) const;
122   //! Writes dynamic model file (C version)
123   /*! \todo add third derivatives handling */
124   void writeDynamicCFile(const string &basename) const;
125   //! Writes dynamic model file when SparseDLL option is on
126   void writeSparseDynamicMFile(const string &basename) const;
127   //! Writes the dynamic model equations and its derivatives
128   /*! \todo add third derivatives handling in C output */
129   void writeDynamicModel(ostream &DynamicOutput, bool use_dll, bool julia) const;
130   void writeDynamicModel(const string &basename, bool use_dll, bool julia) const;
131   void writeDynamicModel(const string &basename, ostream &DynamicOutput, bool use_dll, bool julia) const;
132   //! Writes the Block reordred structure of the model in M output
133   void writeModelEquationsOrdered_M(const string &basename) const;
134   //! Writes the code of the Block reordred structure of the model in virtual machine bytecode
135   void writeModelEquationsCode_Block(const string &basename, const map_idx_t &map_idx, bool linear_decomposition) const;
136   //! Writes the code of the model in virtual machine bytecode
137   void writeModelEquationsCode(const string &basename, const map_idx_t &map_idx) const;
138 
139   void writeSetAuxiliaryVariables(const string &basename, bool julia) const;
140   void writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputType output_type) const;
141 
142   //! Computes jacobian and prepares for equation normalization
143   /*! Using values from initval/endval blocks and parameter initializations:
144     - computes the jacobian for the model w.r. to contemporaneous variables
145     - removes edges of the incidence matrix when derivative w.r. to the corresponding variable is too close to zero (below the cutoff)
146   */
147   //void evaluateJacobian(const eval_context_t &eval_context, jacob_map *j_m, bool dynamic);
148 
149   //! return a map on the block jacobian
150   map<tuple<int, int, int, int, int>, int> get_Derivatives(int block);
151   //! Computes chain rule derivatives of the Jacobian w.r. to endogenous variables
152   void computeChainRuleJacobian(blocks_derivatives_t &blocks_derivatives);
153 
154   string reform(const string &name) const;
155   map_idx_t map_idx;
156 
157   //! sorts the temporary terms in the blocks order
158   void computeTemporaryTermsOrdered();
159 
160   //! creates a mapping from the index of temporary terms to a natural index
161   void computeTemporaryTermsMapping();
162   //! Write derivative code of an equation w.r. to a variable
163   void compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, int lag, const map_idx_t &map_idx) const;
164   //! Write chain rule derivative code of an equation w.r. to a variable
165   void compileChainRuleDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int var, int lag, const map_idx_t &map_idx) const;
166 
167   //! Get the type corresponding to a derivation ID
168   SymbolType getTypeByDerivID(int deriv_id) const noexcept(false) override;
169   //! Get the lag corresponding to a derivation ID
170   int getLagByDerivID(int deriv_id) const noexcept(false) override;
171   //! Get the symbol ID corresponding to a derivation ID
172   int getSymbIDByDerivID(int deriv_id) const noexcept(false) override;
173   //! Compute the column indices of the dynamic Jacobian
174   void computeDynJacobianCols(bool jacobianExo);
175   //! Computes derivatives of the Jacobian w.r. to trend vars and tests that they are equal to zero
176   void testTrendDerivativesEqualToZero(const eval_context_t &eval_context);
177   //! Collect only the first derivatives
178   map<tuple<int, int, int>, expr_t> collect_first_order_derivatives_endogenous();
179 
180   //! Allocates the derivation IDs for all dynamic variables of the model
181   /*! Also computes max_{endo,exo}_{lead_lag}, and initializes dynJacobianColsNbr to the number of dynamic endos */
182   void computeDerivIDs();
183 
184   //! Collecte the derivatives w.r. to endogenous of the block, to endogenous of previouys blocks and to exogenous
185   void collect_block_first_order_derivatives();
186 
187   //! Collecte the informations about exogenous, deterministic exogenous and endogenous from the previous block for each block
188   void collectBlockVariables();
189 
190   //! Factorized code for substitutions of leads/lags
191   /*! \param[in] type determines which type of variables is concerned
192     \param[in] deterministic_model whether we are in a deterministic model (only for exogenous leads/lags)
193     \param[in] subset variables to which to apply the transformation (only for diff of forward vars)
194   */
195   void substituteLeadLagInternal(AuxVarType type, bool deterministic_model, const vector<string> &subset);
196 
197   //! Indicate if the temporary terms are computed for the overall model (true) or not (false). Default value true
198   bool global_temporary_terms{true};
199 
200   //! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
201   equation_type_and_normalized_equation_t equation_type_and_normalized_equation;
202 
203   //! for each block contains pair< Simulation_Type, pair < Block_Size, Recursive_part_Size >>
204   block_type_firstequation_size_mfs_t block_type_firstequation_size_mfs;
205 
206   //! for all blocks derivatives description
207   blocks_derivatives_t blocks_derivatives;
208 
209   //! The jacobian without the elements below the cutoff
210   dynamic_jacob_map_t dynamic_jacobian;
211 
212   //! Vector indicating if the block is linear in endogenous variable (true) or not (false)
213   vector<bool> blocks_linear;
214 
215   //! Map the derivatives for a block tuple<lag, eq, var>
216   using derivative_t = map<tuple<int, int, int>, expr_t>;
217   //! Vector of derivative for each blocks
218   vector<derivative_t> derivative_endo, derivative_other_endo, derivative_exo, derivative_exo_det;
219 
220   //!List for each block and for each lag-lead all the other endogenous variables and exogenous variables
221   using var_t = set<int>;
222   using lag_var_t = map<int, var_t>;
223   vector<lag_var_t> other_endo_block, exo_block, exo_det_block;
224 
225   //!List for each block the exogenous variables
226   vector<pair<var_t, int>> block_var_exo;
227 
228   map< int, map<int, int>> block_exo_index, block_det_exo_index, block_other_endo_index;
229 
230   //! for each block described the number of static, forward, backward and mixed variables in the block
231   /*! tuple<static, forward, backward, mixed> */
232   vector<tuple<int, int, int, int>> block_col_type;
233 
234   //! Help computeXrefs to compute the reverse references (i.e. param->eqs, endo->eqs, etc)
235   void computeRevXref(map<pair<int, int>, set<int>> &xrefset, const set<pair<int, int>> &eiref, int eqn);
236 
237   //! Write reverse cross references
238   void writeRevXrefs(ostream &output, const map<pair<int, int>, set<int>> &xrefmap, const string &type) const;
239 
240   //! List for each variable its block number and its maximum lag and lead inside the block
241   vector<tuple<int, int, int>> variable_block_lead_lag;
242   //! List for each equation its block number
243   vector<int> equation_block;
244 
245   //! Used for var_expectation and var_model
246   map<string, set<int>> var_expectation_functions_to_write;
247 
248   //!Maximum lead and lag for each block on endogenous of the block, endogenous of the previous blocks, exogenous and deterministic exogenous
249   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;
250 
251   void writeWrapperFunctions(const string &name, const string &ending) const;
252   void writeDynamicModelHelper(const string &basename,
253                                const string &name, const string &retvalname,
254                                const string &name_tt, size_t ttlen,
255                                const string &previous_tt_name,
256                                const ostringstream &init_s,
257                                const ostringstream &end_s,
258                                const ostringstream &s, const ostringstream &s_tt) const;
259 
260   //! Create a legacy *_dynamic.m file for Matlab/Octave not yet using the temporary terms array interface
261   void writeDynamicMatlabCompatLayer(const string &basename) const;
262 
263   vector<int> getEquationNumbersFromTags(const set<string> &eqtags) const;
264 
265   void findPacExpectationEquationNumbers(vector<int> &eqnumber) const;
266 
267   //! Internal helper for the copy constructor and assignment operator
268   /*! Copies all the structures that contain ExprNode*, by the converting the
269       pointers into their equivalent in the new tree */
270   void copyHelper(const DynamicModel &m);
271 
272   // Internal helper functions for includeExcludeEquations()
273   /*! Handles parsing of argument passed to exclude_eqs/include_eqs*/
274   /*
275     Expects command line arguments of the form:
276       * filename.txt
277       * eq1
278       * ['eq 1', 'eq 2']
279       * [tagname='eq 1']
280       * [tagname=('eq 1', 'eq 2')]
281     If argument is a file, the file should be formatted as:
282         eq 1
283         eq 2
284     OR
285         tagname=
286         X
287         Y
288    */
289   void parseIncludeExcludeEquations(const string &inc_exc_eq_tags, set<pair<string, string>> &eq_tag_set, bool exclude_eqs);
290 
291   // General function that removes leading/trailing whitespace from a string
292   inline void
removeLeadingTrailingWhitespace(string & str)293   removeLeadingTrailingWhitespace(string &str)
294   {
295     str.erase(0, str.find_first_not_of("\t\n\v\f\r "));
296     str.erase(str.find_last_not_of("\t\n\v\f\r ") + 1);
297   }
298 
299 public:
300   DynamicModel(SymbolTable &symbol_table_arg,
301                NumericalConstants &num_constants_arg,
302                ExternalFunctionsTable &external_functions_table_arg,
303                TrendComponentModelTable &trend_component_model_table_arg,
304                VarModelTable &var_model_table_arg);
305 
306   DynamicModel(const DynamicModel &m);
307   DynamicModel(DynamicModel &&) = delete;
308   DynamicModel &operator=(const DynamicModel &m);
309   DynamicModel &operator=(DynamicModel &&) = delete;
310 
311   //! Compute cross references
312   void computeXrefs();
313 
314   //! Write cross references
315   void writeXrefs(ostream &output) const;
316 
317   //! Execute computations (variable sorting + derivation)
318   /*!
319     \param jacobianExo whether derivatives w.r. to exo and exo_det should be in the Jacobian (derivatives w.r. to endo are always computed)
320     \param derivsOrder order of derivatives w.r. to exo, exo_det and endo should be computed (implies jacobianExo = true when order >= 2)
321     \param paramsDerivsOrder order of derivatives w.r. to a pair (endo/exo/exo_det, parameter) to be computed (>0 implies jacobianExo = true)
322     \param eval_context evaluation context for normalization
323     \param no_tmp_terms if true, no temporary terms will be computed in the dynamic files
324   */
325   void computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsOrder,
326                      const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode, bool linear_decomposition);
327   //! Writes model initialization and lead/lag incidence matrix to output
328   void writeOutput(ostream &output, const string &basename, bool block, bool linear_decomposition, bool byte_code, bool use_dll, bool estimation_present, bool compute_xrefs, bool julia) const;
329 
330   //! Write JSON AST
331   void writeJsonAST(ostream &output) const;
332 
333   //! Write JSON variable mapping
334   void writeJsonVariableMapping(ostream &output) const;
335 
336   //! Write JSON Output
337   void writeJsonOutput(ostream &output) const;
338 
339   //! Write JSON Output representation of original dynamic model
340   void writeJsonOriginalModelOutput(ostream &output) const;
341 
342   //! Write JSON Output representation of model info (useful stuff from M_)
343   void writeJsonDynamicModelInfo(ostream &output) const;
344 
345   //! Write JSON Output representation of dynamic model after computing pass
346   void writeJsonComputingPassOutput(ostream &output, bool writeDetails) const;
347 
348   //! Write JSON prams derivatives file
349   void writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const;
350 
351   //! Write cross reference output if the xref maps have been filed
352   void writeJsonXrefs(ostream &output) const;
353   void writeJsonXrefsHelper(ostream &output, const map<pair<int, int>, set<int>> &xrefs) const;
354 
355   //! Print equations that have non-zero second derivatives
356   void printNonZeroHessianEquations(ostream &output) const;
357 
358   //! Tells whether Hessian has been computed
359   /*! This is needed to know whether no non-zero equation in Hessian means a
360     zero Hessian or Hessian not computed */
361   inline bool
isHessianComputed() const362   isHessianComputed() const
363   {
364     return computed_derivs_order >= 2;
365   }
366   //! Returns equations that have non-zero second derivatives
367   inline set<int>
getNonZeroHessianEquations() const368   getNonZeroHessianEquations() const
369   {
370     return nonzero_hessian_eqs;
371   }
372 
373   //! Fill Autoregressive Matrix for var_model
374   map<string, map<tuple<int, int, int>, expr_t>> fillAutoregressiveMatrix(bool is_var) const;
375 
376   //! Fill Error Component Matrix for trend_component_model
377   /*! Returns a pair (A0r, A0starr) */
378   pair<map<string, map<tuple<int, int, int>, expr_t>>, map<string, map<tuple<int, int, int>, expr_t>>> fillErrorComponentMatrix(const ExprNode::subst_table_t &diff_subst_table) const;
379 
380   //! Fill the Trend Component Model Table
381   void fillTrendComponentModelTable() const;
382   void fillTrendComponentModelTableFromOrigModel() const;
383   void fillTrendComponentmodelTableAREC(const ExprNode::subst_table_t &diff_subst_table) const;
384 
385   //! Fill the Var Model Table
386   void fillVarModelTable() const;
387   void fillVarModelTableFromOrigModel() const;
388 
389   //! Update the rhs references in the var model and trend component tables
390   //! after substitution of auxiliary variables and find the trend variables
391   //! in the trend_component model
392   void updateVarAndTrendModel() const;
393 
394   //! Add aux equations (and aux variables) for variables declared in var_model
395   //! at max order if they don't already exist
396   void addEquationsForVar();
397 
398   //! Get Pac equation parameter info
399   map<pair<string, string>, pair<string, int>> walkPacParameters(const string &name);
400   //! Add var_model info to pac_expectation nodes
401   void fillPacModelInfo(const string &pac_model_name,
402                         vector<int> lhs,
403                         int max_lag,
404                         string aux_model_type,
405                         const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
406                         const vector<bool> &nonstationary,
407                         expr_t growth);
408 
409   //! Substitutes pac_expectation operator with expectation based on auxiliary model
410   void substitutePacExpectation(const string &pac_model_name);
411 
412   //! Adds informations for simulation in a binary file
413   void Write_Inf_To_Bin_File_Block(const string &basename,
414                                    int num, int &u_count_int, bool &file_open, bool is_two_boundaries, bool linear_decomposition) const;
415   //! Writes dynamic model file
416   void writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const;
417   //! Writes file containing parameters derivatives
418   void writeParamsDerivativesFile(const string &basename, bool julia) const;
419 
420   //! Writes file containing coordinates of non-zero elements in the Jacobian
421   /*! Used by the perfect_foresight_problem MEX */
422   void writeDynamicJacobianNonZeroElts(const string &basename) const;
423 
424   //! Converts to nonlinear model (only the equations)
425   /*! It assumes that the nonlinear model given in argument has just been allocated */
426   void toNonlinearPart(DynamicModel &non_linear_equations_dynamic_model) const;
427 
428   //! Creates mapping for variables and equations they are present in
429   void createVariableMapping(int orig_eq_nbr);
430 
431   //! Expands equation tags with default equation names (available "name" tag or LHS variable or equation ID)
432   void expandEqTags();
433 
434   //! Find endogenous variables not used in model
435   set<int> findUnusedEndogenous();
436   //! Find exogenous variables not used in model
437   set<int> findUnusedExogenous();
438 
439   //! Set the max leads/lags of the original model
440   void setLeadsLagsOrig();
441 
442   //! Removes equations from the model according to name tags
443   void includeExcludeEquations(const string &eqs, bool exclude_eqs);
444 
445   //! Replaces model equations with derivatives of Lagrangian w.r.t. endogenous
446   void computeRamseyPolicyFOCs(const StaticModel &static_model);
447 
448   //! Clears all equations
449   void clearEquations();
450 
451   //! Replaces the model equations in dynamic_model with those in this model
452   void replaceMyEquations(DynamicModel &dynamic_model) const;
453 
454   //! Adds an equation marked as [static]
455   void addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
456 
457   //! Returns number of static only equations
458   size_t staticOnlyEquationsNbr() const;
459 
460   //! Returns number of dynamic only equations
461   size_t dynamicOnlyEquationsNbr() const;
462 
463   //! Writes LaTeX file with the equations of the dynamic model
464   void writeLatexFile(const string &basename, bool write_equation_tags) const;
465 
466   //! Writes LaTeX file with the equations of the dynamic model (for the original model)
467   void writeLatexOriginalFile(const string &basename, bool write_equation_tags) const;
468 
469   int getDerivID(int symb_id, int lag) const noexcept(false) override;
470   int getDynJacobianCol(int deriv_id) const noexcept(false) override;
471   void addAllParamDerivId(set<int> &deriv_id_set) override;
472 
473   //! Returns true indicating that this is a dynamic model
474   bool
isDynamic() const475   isDynamic() const override
476   {
477     return true;
478   };
479 
480   //! Drive test of detrended equations
481   void runTrendTest(const eval_context_t &eval_context);
482 
483   //! Transforms the model by removing all leads greater or equal than 2 on endos
484   /*! Note that this can create new lags on endos and exos */
485   void substituteEndoLeadGreaterThanTwo(bool deterministic_model);
486 
487   //! Transforms the model by removing all lags greater or equal than 2 on endos
488   void substituteEndoLagGreaterThanTwo(bool deterministic_model);
489 
490   //! Transforms the model by removing all leads on exos
491   /*! Note that this can create new lags on endos and exos */
492   void substituteExoLead(bool deterministic_model);
493 
494   //! Transforms the model by removing all lags on exos
495   void substituteExoLag(bool deterministic_model);
496 
497   //! Transforms the model by removing all UnaryOpcode::expectation
498   void substituteExpectation(bool partial_information_model);
499 
500   //! Transforms the model by decreasing the lead/lag of predetermined variables in model equations by one
501   void transformPredeterminedVariables();
502 
503   //! Transforms the model by removing trends specified by the user
504   void detrendEquations();
505 
506   inline const nonstationary_symbols_map_t &
getNonstationarySymbolsMap() const507   getNonstationarySymbolsMap() const
508   {
509     return nonstationary_symbols_map;
510   }
511 
512   inline const map<int, expr_t> &
getTrendSymbolsMap() const513   getTrendSymbolsMap() const
514   {
515     return trend_symbols_map;
516   }
517 
518   //! Substitutes adl operator
519   void substituteAdl();
520 
521   //! Creates aux vars for all unary operators
522   pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteUnaryOps();
523 
524   //! Creates aux vars for unary operators in certain equations: originally implemented for support of VARs
525   pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteUnaryOps(const set<string> &eq_tags);
526 
527   //! Creates aux vars for unary operators in certain equations: originally implemented for support of VARs
528   pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteUnaryOps(const vector<int> &eqnumbers);
529 
530   //! Substitutes diff operator
531   pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteDiff(vector<expr_t> &pac_growth);
532 
533   //! Substitute VarExpectation operators
534   void substituteVarExpectation(const map<string, expr_t> &subst_table);
535 
536   //! Return max lag of pac equation
537   void getPacMaxLag(const string &pac_model_name, map<pair<string, string>, pair<string, int>> &eqtag_and_lag) const;
538 
539   //! Return target of the pac equation
540   int getPacTargetSymbId(const string &pac_model_name) const;
541 
542   //! Declare Z1 variables before creating aux vars so it comes right after the endo names declared by the user
543   void declarePacModelConsistentExpectationEndogs(const string &name);
544 
545   //! Add model consistent expectation equation for pac model
546   void addPacModelConsistentExpectationEquation(const string &name, int discount,
547                                                 const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
548                                                 ExprNode::subst_table_t &diff_subst_table);
549 
550   //! store symb_ids for alphas created in addPacModelConsistentExpectationEquation
551   //! (pac_model_name, standardized_eqtag) -> mce_alpha_symb_id
552   map<pair<string, string>, vector<int>> pac_mce_alpha_symb_ids;
553   //! store symb_ids for h0, h1 parameters
554   //! (pac_model_name, standardized_eqtag) -> parameter symb_ids
555   map<pair<string, string>, vector<int>> pac_h0_indices, pac_h1_indices;
556   //! store symb_ids for z1s created in addPacModelConsistentExpectationEquation
557   //! (pac_model_name, standardized_eqtag) -> mce_z1_symb_id
558   map<pair<string, string>, int> pac_mce_z1_symb_ids;
559   //! Store lag info for pac equations
560   //! (pac_model_name, equation_tag) -> (standardized_eqtag, lag)
561   map<pair<string, string>, pair<string, int>> pac_eqtag_and_lag;
562 
563   //! (pac_model_name, equation_tag) -> expr_t
564   map<pair<string, string>, expr_t> pac_expectation_substitution;
565 
566   //! Store info about pac models:
567   //! pac_model_name -> (lhsvars, growth_param_index, aux_model_type)
568   map<string, tuple<vector<int>, int, string>> pac_model_info;
569 
570   //! Store info about pac models specific to the equation they appear in
571   //! (pac_model_name, standardized_eqtag) ->
572   //!     (lhs, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants, additive_vars_params_and_constants, optim_additive_vars_params_and_constants)
573   map<pair<string, string>,
574       tuple<pair<int, int>, int, set<pair<int, pair<int, int>>>, pair<int, vector<tuple<int, bool, int>>>, vector<tuple<int, int, int, double>>, vector<tuple<int, int, int, double>>, vector<tuple<int, int, int, double>>>> pac_equation_info;
575 
576   //! Table to undiff LHS variables for pac vector z
577   vector<int> getUndiffLHSForPac(const string &aux_model_name,
578                                  const ExprNode::subst_table_t &diff_subst_table) const;
579 
580   //! Transforms the model by replacing trend variables with a 1
581   void removeTrendVariableFromEquations();
582 
583   //! Transforms the model by creating aux vars for the diff of forward vars
584   /*! If subset is empty, does the transformation for all fwrd vars; otherwise
585     restrict it to the vars in subset */
586   void differentiateForwardVars(const vector<string> &subset);
587 
588   //! Fills eval context with values of model local variables and auxiliary variables
589   void fillEvalContext(eval_context_t &eval_context) const;
590 
591   auto
getStaticOnlyEquationsInfo() const592   getStaticOnlyEquationsInfo() const
593   {
594     return tuple(static_only_equations, static_only_equations_lineno, static_only_equations_equation_tags);
595   };
596 
597   //! Return the number of blocks
598   unsigned int
getNbBlocks() const599   getNbBlocks() const override
600   {
601     return block_type_firstequation_size_mfs.size();
602   };
603   //! Determine the simulation type of each block
604   BlockSimulationType
getBlockSimulationType(int block_number) const605   getBlockSimulationType(int block_number) const override
606   {
607     return get<0>(block_type_firstequation_size_mfs[block_number]);
608   };
609   //! Return the first equation number of a block
610   unsigned int
getBlockFirstEquation(int block_number) const611   getBlockFirstEquation(int block_number) const override
612   {
613     return get<1>(block_type_firstequation_size_mfs[block_number]);
614   };
615   //! Return the size of the block block_number
616   unsigned int
getBlockSize(int block_number) const617   getBlockSize(int block_number) const override
618   {
619     return get<2>(block_type_firstequation_size_mfs[block_number]);
620   };
621   //! Return the number of exogenous variable in the block block_number
622   unsigned int
getBlockExoSize(int block_number) const623   getBlockExoSize(int block_number) const override
624   {
625     return block_var_exo[block_number].first.size();
626   };
627   //! Return the number of colums in the jacobian matrix for exogenous variable in the block block_number
628   unsigned int
getBlockExoColSize(int block_number) const629   getBlockExoColSize(int block_number) const override
630   {
631     return block_var_exo[block_number].second;
632   };
633   //! Return the number of feedback variable of the block block_number
634   unsigned int
getBlockMfs(int block_number) const635   getBlockMfs(int block_number) const override
636   {
637     return get<3>(block_type_firstequation_size_mfs[block_number]);
638   };
639   //! Return the maximum lag in a block
640   unsigned int
getBlockMaxLag(int block_number) const641   getBlockMaxLag(int block_number) const override
642   {
643     return block_lag_lead[block_number].first;
644   };
645   //! Return the maximum lead in a block
646   unsigned int
getBlockMaxLead(int block_number) const647   getBlockMaxLead(int block_number) const override
648   {
649     return block_lag_lead[block_number].second;
650   };
651   //! Return the type of equation (equation_number) belonging to the block block_number
652   EquationType
getBlockEquationType(int block_number,int equation_number) const653   getBlockEquationType(int block_number, int equation_number) const override
654   {
655     return equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].first;
656   };
657   //! Return true if the equation has been normalized
658   bool
isBlockEquationRenormalized(int block_number,int equation_number) const659   isBlockEquationRenormalized(int block_number, int equation_number) const override
660   {
661     return equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].first == E_EVALUATE_S;
662   };
663   //! Return the expr_t of the equation equation_number belonging to the block block_number
664   expr_t
getBlockEquationExpr(int block_number,int equation_number) const665   getBlockEquationExpr(int block_number, int equation_number) const override
666   {
667     return equations[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]];
668   };
669   //! Return the expr_t of the renormalized equation equation_number belonging to the block block_number
670   expr_t
getBlockEquationRenormalizedExpr(int block_number,int equation_number) const671   getBlockEquationRenormalizedExpr(int block_number, int equation_number) const override
672   {
673     return equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].second;
674   };
675   //! Return the original number of equation equation_number belonging to the block block_number
676   int
getBlockEquationID(int block_number,int equation_number) const677   getBlockEquationID(int block_number, int equation_number) const override
678   {
679     return equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number];
680   };
681   //! Return the original number of variable variable_number belonging to the block block_number
682   int
getBlockVariableID(int block_number,int variable_number) const683   getBlockVariableID(int block_number, int variable_number) const override
684   {
685     return variable_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+variable_number];
686   };
687   //! Return the original number of the exogenous variable varexo_number belonging to the block block_number
688   int
getBlockVariableExoID(int block_number,int variable_number) const689   getBlockVariableExoID(int block_number, int variable_number) const override
690   {
691     return exo_block[block_number].find(variable_number)->first;
692   };
693   //! Return the position of equation_number in the block number belonging to the block block_number
694   int
getBlockInitialEquationID(int block_number,int equation_number) const695   getBlockInitialEquationID(int block_number, int equation_number) const override
696   {
697     return static_cast<int>(inv_equation_reordered[equation_number]) - static_cast<int>(get<1>(block_type_firstequation_size_mfs[block_number]));
698   };
699   //! Return the position of variable_number in the block number belonging to the block block_number
700   int
getBlockInitialVariableID(int block_number,int variable_number) const701   getBlockInitialVariableID(int block_number, int variable_number) const override
702   {
703     return static_cast<int>(inv_variable_reordered[variable_number]) - static_cast<int>(get<1>(block_type_firstequation_size_mfs[block_number]));
704   };
705   //! Return the block number containing the endogenous variable variable_number
706   int
getBlockVariableID(int variable_number) const707   getBlockVariableID(int variable_number) const
708   {
709     return get<0>(variable_block_lead_lag[variable_number]);
710   };
711   //! Return the position of the exogenous variable_number in the block number belonging to the block block_number
712   int
getBlockInitialExogenousID(int block_number,int variable_number) const713   getBlockInitialExogenousID(int block_number, int variable_number) const override
714   {
715     if (auto it = block_exo_index.find(block_number);
716         it != block_exo_index.end())
717       {
718         if (auto it1 = it->second.find(variable_number);
719             it1 != it->second.end())
720           return it1->second;
721         else
722           return -1;
723       }
724     else
725       return -1;
726   };
727   //! Return the position of the deterministic exogenous variable_number in the block number belonging to the block block_number
728   int
getBlockInitialDetExogenousID(int block_number,int variable_number) const729   getBlockInitialDetExogenousID(int block_number, int variable_number) const override
730   {
731     if (auto it = block_det_exo_index.find(block_number);
732         it != block_det_exo_index.end())
733       {
734         if (auto it1 = it->second.find(variable_number);
735             it1 != it->second.end())
736           return it1->second;
737         else
738           return -1;
739       }
740     else
741       return -1;
742   };
743   //! Return the position of the other endogenous variable_number in the block number belonging to the block block_number
744   int
getBlockInitialOtherEndogenousID(int block_number,int variable_number) const745   getBlockInitialOtherEndogenousID(int block_number, int variable_number) const override
746   {
747     if (auto it = block_other_endo_index.find(block_number);
748         it != block_other_endo_index.end())
749       {
750         if (auto it1 = it->second.find(variable_number);
751             it1 != it->second.end())
752           return it1->second;
753         else
754           return -1;
755       }
756     else
757       return -1;
758   };
759   bool isModelLocalVariableUsed() const;
760 
761   //! Returns true if a parameter was used in the model block with a lead or lag
762   bool ParamUsedWithLeadLag() const;
763 
764   bool isChecksumMatching(const string &basename, bool block) const;
765 };
766 
767 //! Classes to re-order derivatives for various sparse storage formats
768 class derivative
769 {
770 public:
771   long unsigned int linear_address;
772   long unsigned int col_nbr;
773   unsigned int row_nbr;
774   expr_t value;
derivative(long unsigned int arg1,long unsigned int arg2,int arg3,expr_t arg4)775   derivative(long unsigned int arg1, long unsigned int arg2, int arg3, expr_t arg4) :
776     linear_address(arg1), col_nbr(arg2), row_nbr(arg3), value(arg4)
777   {
778   };
779 };
780 
781 class derivative_less_than
782 {
783 public:
784   bool
operator ()(const derivative & d1,const derivative & d2) const785   operator()(const derivative &d1, const derivative &d2) const
786   {
787     return d1.linear_address < d2.linear_address;
788   }
789 };
790 #endif
791