1 /*
2  * Copyright © 2003-2020 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 _MODELTREE_HH
21 #define _MODELTREE_HH
22 
23 using namespace std;
24 
25 #include <string>
26 #include <vector>
27 #include <deque>
28 #include <map>
29 #include <ostream>
30 #include <array>
31 #include <filesystem>
32 
33 #include "DataTree.hh"
34 #include "ExtendedPreprocessorTypes.hh"
35 
36 // Helper to convert a vector into a tuple
37 template<typename T, size_t... Indices>
38 auto
vectorToTupleHelper(const vector<T> & v,index_sequence<Indices...>)39 vectorToTupleHelper(const vector<T> &v, index_sequence<Indices...>)
40 {
41   return tuple(v[Indices] ...);
42 }
43 template<size_t N, typename T>
44 auto
vectorToTuple(const vector<T> & v)45 vectorToTuple(const vector<T> &v)
46 {
47   assert(v.size() >= N);
48   return vectorToTupleHelper(v, make_index_sequence<N>());
49 }
50 
51 //! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
52 using equation_type_and_normalized_equation_t = vector<pair<EquationType, expr_t>>;
53 
54 //! Vector describing variables: max_lag in the block, max_lead in the block
55 using lag_lead_vector_t = vector<pair< int, int>>;
56 
57 //! for each block contains tuple<Simulation_Type, first_equation, Block_Size, Recursive_part_Size>
58 using block_type_firstequation_size_mfs_t = vector<tuple<BlockSimulationType, int, int, int>>;
59 
60 //! for a block contains derivatives tuple<block_equation_number, block_variable_number, lead_lag, expr_t>
61 using block_derivatives_equation_variable_laglead_nodeid_t = vector<tuple<int, int, int, expr_t>>;
62 
63 //! for all blocks derivatives description
64 using blocks_derivatives_t = vector<block_derivatives_equation_variable_laglead_nodeid_t>;
65 
66 //! Shared code for static and dynamic models
67 class ModelTree : public DataTree
68 {
69   friend class DynamicModel;
70   friend class StaticModel;
71 public:
72   // Set via the `compiler` command
73   string user_set_add_flags, user_set_subst_flags, user_set_add_libs, user_set_subst_libs, user_set_compiler;
74 protected:
75   /*
76    * ************** BEGIN **************
77    * The following structures keep track of the model equations and must all be updated
78    * when adding or removing an equation. Hence, if a new parallel structure is added
79    * in the future, it must be maintained whereever these structures are updated
80    * See in particular methods clearEquations(), replaceMyEquations() and
81    * computeRamseyPolicyFOCs() of DynamicModel class.
82    * NB: This message added with the introduction of the `exclude_eqs` option, hence
83    *     that's a place to update future structures.
84    */
85   //! Stores declared and generated auxiliary equations
86   vector<BinaryOpNode *> equations;
87   //! Stores line numbers of declared equations; -1 means undefined
88   vector<int> equations_lineno;
89   //! Stores equation tags
90   vector<pair<int, pair<string, string>>> equation_tags;
91   //! Stores mapping from equation tags to equation number
92   multimap<pair<string, string>, int> equation_tags_xref;
93   /*
94    * ************** END **************
95    */
96 
97   //! Only stores generated auxiliary equations, in an order meaningful for evaluation
98   /*! These equations only contain the definition of auxiliary variables, and
99       may diverge from those in the main model (equations), if other model
100       transformations applied subsequently. This is not a problem, since
101       aux_equations is only used for regenerating the values of auxiliaries
102       given the others.
103 
104       For example, such a divergence appears when there is an expectation
105       operator in a ramsey model, see
106       tests/optimal_policy/nk_ramsey_expectation.mod */
107   vector<BinaryOpNode *> aux_equations;
108 
109   //! Maximum order at which (endogenous) derivatives have been computed
110   int computed_derivs_order{0};
111 
112   //! Stores derivatives
113   /*! Index 0 is not used, index 1 contains first derivatives, ...
114      For each derivation order, stores a map whose key is a vector of integer: the
115      first integer is the equation index, the remaining ones are the derivation
116      IDs of variables (in non-decreasing order, to avoid storing symmetric
117      elements several times) */
118   vector<map<vector<int>, expr_t>> derivatives;
119 
120   //! Number of non-zero derivatives
121   /*! Index 0 is not used, index 1 contains number of non-zero first
122     derivatives, ... */
123   vector<int> NNZDerivatives;
124 
125   //! Derivatives with respect to parameters
126   /*! The key of the outer map is a pair (derivation order w.r.t. endogenous,
127   derivation order w.r.t. parameters). For e.g., { 1, 2 } corresponds to the jacobian
128   differentiated twice w.r.t. to parameters.
129   In inner maps, the vector of integers consists of: the equation index, then
130   the derivation IDs of endogenous (in non-decreasing order),
131   then the IDs of parameters (in non-decreasing order)*/
132   map<pair<int,int>, map<vector<int>, expr_t>> params_derivatives;
133 
134   //! Storage for temporary terms in block/bytecode mode
135   temporary_terms_t temporary_terms;
136 
137   //! Used model local variables, that will be treated as temporary terms
138   /*! See the comments in ModelTree::computeTemporaryTerms() */
139   map<VariableNode *, expr_t, ExprNodeLess> temporary_terms_mlv;
140 
141   //! Temporary terms for residuals and derivatives
142   /*! Index 0 is temp. terms of residuals, index 1 for first derivatives, ... */
143   vector<temporary_terms_t> temporary_terms_derivatives;
144 
145   //! Stores, for each temporary term, its index in the MATLAB/Julia vector
146   temporary_terms_idxs_t temporary_terms_idxs;
147 
148   //! Temporary terms for parameter derivatives, under a disaggregated form
149   /*! The pair of integers is to be interpreted as in param_derivatives */
150   map<pair<int, int>, temporary_terms_t> params_derivs_temporary_terms;
151 
152   //! Stores, for each temporary term in param. derivs, its index in the MATLAB/Julia vector
153   temporary_terms_idxs_t params_derivs_temporary_terms_idxs;
154 
155   //! Trend variables and their growth factors
156   map<int, expr_t> trend_symbols_map;
157 
158   //! for all trends; the boolean is true if this is a log-trend, false otherwise
159   using nonstationary_symbols_map_t = map<int, pair<bool, expr_t>>;
160 
161   //! Nonstationary variables and their deflators
162   nonstationary_symbols_map_t nonstationary_symbols_map;
163 
164   //! vector of block reordered variables and equations
165   vector<int> equation_reordered, variable_reordered, inv_equation_reordered, inv_variable_reordered;
166 
167   //! the file containing the model and the derivatives code
168   ofstream code_file;
169 
170   //! Vector indicating if the equation is linear in endogenous variable (true) or not (false)
171   vector<bool> is_equation_linear;
172 
173   //! Computes derivatives
174   /*! \param order the derivation order
175       \param vars the derivation IDs w.r.t. which compute the derivatives */
176   void computeDerivatives(int order, const set<int> &vars);
177   //! Computes derivatives of the Jacobian and Hessian w.r. to parameters
178   void computeParamsDerivatives(int paramsDerivsOrder);
179   //! Write derivative of an equation w.r. to a variable
180   void writeDerivative(ostream &output, int eq, int symb_id, int lag, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
181   //! Computes temporary terms (for all equations and derivatives)
182   void computeTemporaryTerms(bool is_matlab, bool no_tmp_terms);
183   //! Computes temporary terms for the file containing parameters derivatives
184   void computeParamsDerivativesTemporaryTerms();
185   //! Writes temporary terms
186   void writeTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, const temporary_terms_idxs_t &tt_idxs, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
187   void writeJsonTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, ostream &output, deriv_node_temp_terms_t &tef_terms, const string &concat) const;
188   //! Compiles temporary terms
189   void compileTemporaryTerms(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, map_idx_t map_idx, bool dynamic, bool steady_dynamic) const;
190   //! Adds informations for simulation in a binary file
191   void Write_Inf_To_Bin_File(const string &filename, int &u_count_int, bool &file_open, bool is_two_boundaries, int block_mfs) const;
192   //! Fixes output when there are more than 32 nested parens, Issue #1201
193   void fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const;
194   //! Tests if string contains more than 32 nested parens, Issue #1201
195   bool testNestedParenthesis(const string &str) const;
196   void writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union,
197                                              const temporary_terms_idxs_t &tt_idxs,
198                                              ostream &output, ExprNodeOutputType output_type,
199                                              deriv_node_temp_terms_t &tef_terms) const;
200   //! Writes model equations
201   void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
202   void writeModelEquations(ostream &output, ExprNodeOutputType output_type,
203                            const temporary_terms_t &temporary_terms) const;
204   //! Writes JSON model equations
205   //! if residuals = true, we are writing the dynamic/static model.
206   //! Otherwise, just the model equations (with line numbers, no tmp terms)
207   void writeJsonModelEquations(ostream &output, bool residuals) const;
208   /* Writes JSON model local variables.
209      Optionally put the external function variable calls into TEF terms */
210   void writeJsonModelLocalVariables(ostream &output, bool write_tef_terms, deriv_node_temp_terms_t &tef_terms) const;
211   //! Compiles model equations
212   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;
213 
214   //! Writes LaTeX model file
215   void writeLatexModelFile(const string &mod_basename, const string &latex_basename, ExprNodeOutputType output_type, bool write_equation_tags) const;
216 
217   //! Sparse matrix of double to store the values of the Jacobian
218   /*! First index is equation number, second index is endogenous type specific ID */
219   using jacob_map_t = map<pair<int, int>, double>;
220 
221   //! Sparse matrix of double to store the values of the Jacobian
222   /*! First index is lag, second index is equation number, third index is endogenous type specific ID */
223   using dynamic_jacob_map_t = map<tuple<int, int, int>, expr_t>;
224 
225   //! Normalization of equations
226   /*! Maps endogenous type specific IDs to equation numbers */
227   vector<int> endo2eq;
228 
229   //! number of equation in the prologue and in the epilogue
230   unsigned int epilogue, prologue;
231 
232   //! for each block contains pair< max_lag, max_lead>
233   lag_lead_vector_t block_lag_lead;
234 
235   //! Compute the matching between endogenous and variable using the jacobian contemporaneous_jacobian
236   /*!
237     \param contemporaneous_jacobian Jacobian used as an incidence matrix: all elements declared in the map (even if they are zero), are used as vertices of the incidence matrix
238     \return True if a complete normalization has been achieved
239   */
240   bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose);
241 
242   //! Try to compute the matching between endogenous and variable using a decreasing cutoff
243   /*!
244     Applied to the jacobian contemporaneous_jacobian and stop when a matching is found.
245     If no matching is found using a strictly positive cutoff, then a zero cutoff is applied (i.e. use a symbolic normalization); in that case, the method adds zeros in the jacobian matrices to reflect all the edges in the symbolic incidence matrix.
246     If no matching is found with a zero cutoff close to zero an error message is printout.
247   */
248   void computeNonSingularNormalization(jacob_map_t &contemporaneous_jacobian, double cutoff, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian);
249   //! Try to find a natural normalization if all equations are matched to an endogenous variable on the LHS
250   bool computeNaturalNormalization();
251   //! Try to normalized each unnormalized equation (matched endogenous variable only on the LHS)
252   multimap<int, int> computeNormalizedEquations() const;
253   //! Evaluate the jacobian and suppress all the elements below the cutoff
254   void evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_map_t &contemporaneous_jacobian, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian, double cutoff, bool verbose);
255   //! Select and reorder the non linear equations of the model
256   vector<pair<int, int>> select_non_linear_equations_and_variables(vector<bool> is_equation_linear, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered,
257                                                                    vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered,
258                                                                    lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead,
259                                                                    vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed);
260   //! Search the equations and variables belonging to the prologue and the epilogue of the model
261   void computePrologueAndEpilogue(const jacob_map_t &static_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered);
262   //! Determine the type of each equation of model and try to normalized the unnormalized equation using computeNormalizedEquations
263   equation_type_and_normalized_equation_t equationTypeDetermination(const map<tuple<int, int, int>, expr_t> &first_order_endo_derivatives, const vector<int> &Index_Var_IM, const vector<int> &Index_Equ_IM, int mfs) const;
264   //! Compute the block decomposition and for a non-recusive block find the minimum feedback set
265   void computeBlockDecompositionAndFeedbackVariablesForEachBlock(const jacob_map_t &static_jacobian, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, bool verbose_, bool select_feedback_variable, int mfs, vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered, lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead_t, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed) const;
266   //! Reduce the number of block merging the same type equation in the prologue and the epilogue and determine the type of each block
267   block_type_firstequation_size_mfs_t reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_jacobian, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, const vector<int> &variable_reordered, const vector<int> &equation_reordered, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed, vector<tuple<int, int, int, int>> &block_col_type, bool linear_decomposition);
268   //! Determine the maximum number of lead and lag for the endogenous variable in a bloc
269   void getVariableLeadLagByBlock(const dynamic_jacob_map_t &dynamic_jacobian, const vector<int> &components_set, int nb_blck_sim, lag_lead_vector_t &equation_lead_lag, lag_lead_vector_t &variable_lead_lag, const vector<int> &equation_reordered, const vector<int> &variable_reordered) const;
270   //! For each equation determine if it is linear or not
271   vector<bool> equationLinear(map<tuple<int, int, int>, expr_t> first_order_endo_derivatives) const;
272   //! Print an abstract of the block structure of the model
273   void printBlockDecomposition(const vector<pair<int, int>> &blocks) const;
274   //! Determine for each block if it is linear or not
275   vector<bool> BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vector<int> &variable_reordered) const;
276   //! Remove equations specified by exclude_eqs
277   vector<int> includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
278                                       vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
279                                       vector<pair<int, pair<string, string>>> &equation_tags,
280                                       multimap<pair<string, string>, int> &equation_tags_xref, bool static_equations) const;
281 
282   //! Determine the simulation type of each block
283   virtual BlockSimulationType getBlockSimulationType(int block_number) const = 0;
284   //! Return the number of blocks
285   virtual unsigned int getNbBlocks() const = 0;
286   //! Return the first equation number of a block
287   virtual unsigned int getBlockFirstEquation(int block_number) const = 0;
288   //! Return the size of the block block_number
289   virtual unsigned int getBlockSize(int block_number) const = 0;
290   //! Return the number of exogenous variable in the block block_number
291   virtual unsigned int getBlockExoSize(int block_number) const = 0;
292   //! Return the number of colums in the jacobian matrix for exogenous variable in the block block_number
293   virtual unsigned int getBlockExoColSize(int block_number) const = 0;
294   //! Return the number of feedback variable of the block block_number
295   virtual unsigned int getBlockMfs(int block_number) const = 0;
296   //! Return the maximum lag in a block
297   virtual unsigned int getBlockMaxLag(int block_number) const = 0;
298   //! Return the maximum lead in a block
299   virtual unsigned int getBlockMaxLead(int block_number) const = 0;
300   inline void
setBlockLeadLag(int block,int max_lag,int max_lead)301   setBlockLeadLag(int block, int max_lag, int max_lead)
302   {
303     block_lag_lead[block] = { max_lag, max_lead };
304   };
305 
306   //! Return the type of equation (equation_number) belonging to the block block_number
307   virtual EquationType getBlockEquationType(int block_number, int equation_number) const = 0;
308   //! Return true if the equation has been normalized
309   virtual bool isBlockEquationRenormalized(int block_number, int equation_number) const = 0;
310   //! Return the expr_t of the equation equation_number belonging to the block block_number
311   virtual expr_t getBlockEquationExpr(int block_number, int equation_number) const = 0;
312   //! Return the expr_t of the renormalized equation equation_number belonging to the block block_number
313   virtual expr_t getBlockEquationRenormalizedExpr(int block_number, int equation_number) const = 0;
314   //! Return the original number of equation equation_number belonging to the block block_number
315   virtual int getBlockEquationID(int block_number, int equation_number) const = 0;
316   //! Return the original number of variable variable_number belonging to the block block_number
317   virtual int getBlockVariableID(int block_number, int variable_number) const = 0;
318   //! Return the original number of the exogenous variable varexo_number belonging to the block block_number
319   virtual int getBlockVariableExoID(int block_number, int variable_number) const = 0;
320   //! Return the position of equation_number in the block number belonging to the block block_number
321   virtual int getBlockInitialEquationID(int block_number, int equation_number) const = 0;
322   //! Return the position of variable_number in the block number belonging to the block block_number
323   virtual int getBlockInitialVariableID(int block_number, int variable_number) const = 0;
324   //! Return the position of variable_number in the block number belonging to the block block_number
325   virtual int getBlockInitialExogenousID(int block_number, int variable_number) const = 0;
326   //! Return the position of the deterministic exogenous variable_number in the block number belonging to the block block_number
327   virtual int getBlockInitialDetExogenousID(int block_number, int variable_number) const = 0;
328   //! Return the position of the other endogenous variable_number in the block number belonging to the block block_number
329   virtual int getBlockInitialOtherEndogenousID(int block_number, int variable_number) const = 0;
330   //! Initialize equation_reordered & variable_reordered
331   void initializeVariablesAndEquations();
332 
333 private:
334   //! Internal helper for the copy constructor and assignment operator
335   /*! Copies all the structures that contain ExprNode*, by the converting the
336       pointers into their equivalent in the new tree */
337   void copyHelper(const ModelTree &m);
338   //! Returns the name of the MATLAB architecture given the extension used for MEX files
339   static string matlab_arch(const string &mexext);
340   //! Compiles the MEX file
341   void compileDll(const string &basename, const string &static_or_dynamic, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const;
342 
343 public:
344   ModelTree(SymbolTable &symbol_table_arg,
345             NumericalConstants &num_constants_arg,
346             ExternalFunctionsTable &external_functions_table_arg,
347             bool is_dynamic_arg = false);
348 
349   ModelTree(const ModelTree &m);
350   ModelTree(ModelTree &&) = delete;
351   ModelTree &operator=(const ModelTree &m);
352   ModelTree &operator=(ModelTree &&) = delete;
353 
354   //! Absolute value under which a number is considered to be zero
355   double cutoff{1e-15};
356   //! Compute the minimum feedback set
357   /*!   0 : all endogenous variables are considered as feedback variables
358     1 : the variables belonging to non normalized equation are considered as feedback variables
359     2 : the variables belonging to a non linear equation are considered as feedback variables
360     3 : the variables belonging to a non normalizable non linear equation are considered as feedback variables
361     default value = 0 */
362   int mfs{0};
363   //! Declare a node as an equation of the model; also give its line number
364   void addEquation(expr_t eq, int lineno);
365   //! Declare a node as an equation of the model, also giving its tags
366   void addEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
367   //! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations
368   void addAuxEquation(expr_t eq);
369   //! Returns the number of equations in the model
370   int equation_number() const;
371   //! Adds a trend variable with its growth factor
372   void addTrendVariables(const vector<int> &trend_vars, expr_t growth_factor) noexcept(false);
373   //! Adds a nonstationary variables with their (common) deflator
374   void addNonstationaryVariables(const vector<int> &nonstationary_vars, bool log_deflator, expr_t deflator) noexcept(false);
375   //! Is a given variable non-stationary?
376   bool isNonstationary(int symb_id) const;
377   void set_cutoff_to_zero();
378   //! Simplify model equations: if a variable is equal to a constant, replace that variable elsewhere in the model
379   /*! Equations with tags are excluded, in particular because of MCPs, see
380       dynare#1697 */
381   void simplifyEquations();
382   /*! Reorder auxiliary variables so that they appear in recursive order in
383       set_auxiliary_variables.m and dynamic_set_auxiliary_series.m */
384   void reorderAuxiliaryEquations();
385   //! Find equations of the form “variable=constant”, excluding equations with tags
386   void findConstantEquationsWithoutTags(map<VariableNode *, NumConstNode *> &subst_table) const;
387   //! Helper for writing the Jacobian elements in MATLAB and C
388   /*! Writes either (i+1,j+1) or [i+j*no_eq] */
389   void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
390   //! Helper for writing the sparse Hessian or third derivatives in MATLAB and C
391   /*! If order=2, writes either v2(i+1,j+1) or v2[i+j*NNZDerivatives[2]]
392     If order=3, writes either v3(i+1,j+1) or v3[i+j*NNZDerivatives[3]] */
393   void sparseHelper(int order, ostream &output, int row_nb, int col_nb, ExprNodeOutputType output_type) const;
394 
395   //! Returns all the equation tags associated to an equation
396   inline map<string, string>
getEquationTags(int eq) const397   getEquationTags(int eq) const
398   {
399     map<string, string> r;
400     for (auto &[eq2, tagpair] : equation_tags)
401       if (eq2 == eq)
402         r[tagpair.first] = tagpair.second;
403     return r;
404   }
405 
406   inline static string
c_Equation_Type(int type)407   c_Equation_Type(int type)
408   {
409     vector<string> c_Equation_Type =
410       {
411        "E_UNKNOWN   ",
412        "E_EVALUATE  ",
413        "E_EVALUATE_S",
414        "E_SOLVE     "
415       };
416     return c_Equation_Type[type];
417   };
418 
419   inline static string
BlockType0(BlockType type)420   BlockType0(BlockType type)
421   {
422     switch (type)
423       {
424       case SIMULTANS:
425         return "SIMULTANEOUS TIME SEPARABLE  ";
426       case PROLOGUE:
427         return "PROLOGUE                     ";
428       case EPILOGUE:
429         return "EPILOGUE                     ";
430       case SIMULTAN:
431         return "SIMULTANEOUS TIME UNSEPARABLE";
432       default:
433         return "UNKNOWN                      ";
434       }
435   };
436 
437   inline static string
BlockSim(int type)438   BlockSim(int type)
439   {
440     switch (type)
441       {
442       case EVALUATE_FORWARD:
443         return "EVALUATE FORWARD             ";
444       case EVALUATE_BACKWARD:
445         return "EVALUATE BACKWARD            ";
446       case SOLVE_FORWARD_SIMPLE:
447         return "SOLVE FORWARD SIMPLE         ";
448       case SOLVE_BACKWARD_SIMPLE:
449         return "SOLVE BACKWARD SIMPLE        ";
450       case SOLVE_TWO_BOUNDARIES_SIMPLE:
451         return "SOLVE TWO BOUNDARIES SIMPLE  ";
452       case SOLVE_FORWARD_COMPLETE:
453         return "SOLVE FORWARD COMPLETE       ";
454       case SOLVE_BACKWARD_COMPLETE:
455         return "SOLVE BACKWARD COMPLETE      ";
456       case SOLVE_TWO_BOUNDARIES_COMPLETE:
457         return "SOLVE TWO BOUNDARIES COMPLETE";
458       default:
459         return "UNKNOWN                      ";
460       }
461   };
462 };
463 
464 #endif
465