ModelTree.hh 24.1 KB
Newer Older
1
/*
Houtan Bastani's avatar
Houtan Bastani committed
2
 * Copyright (C) 2003-2018 Dynare Team
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * This file is part of Dynare.
 *
 * Dynare is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Dynare is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _MODELTREE_HH
#define _MODELTREE_HH

using namespace std;

#include <string>
#include <vector>
sebastien's avatar
sebastien committed
27
#include <deque>
28
29
30
31
#include <map>
#include <ostream>

#include "DataTree.hh"
32
#include "ExtendedPreprocessorTypes.hh"
33

34
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
35
using equation_type_and_normalized_equation_t = vector<pair<EquationType, expr_t >>;
36
37

//! Vector describing variables: max_lag in the block, max_lead in the block
38
using lag_lead_vector_t = vector<pair< int, int>>;
39

40
//! for each block contains pair< pair<Simulation_Type, first_equation>, pair < Block_Size, Recursive_part_Size >>
41
using block_type_firstequation_size_mfs_t = vector<pair< pair< BlockSimulationType, int>, pair<int, int>>>;
42

43
//! for a block contains derivatives pair< pair<block_equation_number, block_variable_number> , pair<lead_lag, expr_t>>
44
using block_derivatives_equation_variable_laglead_nodeid_t = vector< pair<pair<int, int>, pair< int, expr_t >>>;
45
46

//! for all blocks derivatives description
47
using blocks_derivatives_t = vector<block_derivatives_equation_variable_laglead_nodeid_t>;
48

sebastien's avatar
sebastien committed
49
//! Shared code for static and dynamic models
50
51
class ModelTree : public DataTree
{
52
53
  friend class DynamicModel;
  friend class StaticModel;
sebastien's avatar
sebastien committed
54
protected:
sebastien's avatar
sebastien committed
55
  //! Stores declared and generated auxiliary equations
56
57
  vector<BinaryOpNode *> equations;

58
59
60
  //! Stores line numbers of declared equations; -1 means undefined
  vector<int> equations_lineno;

sebastien's avatar
sebastien committed
61
  //! Only stores generated auxiliary equations, in an order meaningful for evaluation
62
63
64
65
66
67
68
69
70
  /*! These equations only contain the definition of auxiliary variables, and
      may diverge from those in the main model (equations), if other model
      transformations applied subsequently. This is not a problem, since
      aux_equations is only used for regenerating the values of auxiliaries
      given the others.

      For example, such a divergence appears when there is an expectation
      operator in a ramsey model, see
      tests/optimal_policy/nk_ramsey_expectation.mod */
sebastien's avatar
sebastien committed
71
72
  deque<BinaryOpNode *> aux_equations;

73
  //! Stores equation tags
74
  vector<pair<int, pair<string, string>>> equation_tags;
75

76
77
78
  //! Number of non-zero derivatives
  int NNZDerivatives[3];

79
  using first_derivatives_t = map<pair<int, int>, expr_t>;
80
81
82
  //! First order derivatives
  /*! First index is equation number, second is variable w.r. to which is computed the derivative.
    Only non-null derivatives are stored in the map.
83
    Variable indices are those of the getDerivID() method.
84
  */
85
  first_derivatives_t first_derivatives;
86

87
  using second_derivatives_t = map<tuple<int, int, int>, expr_t>;
88
89
90
91
  //! Second order derivatives
  /*! First index is equation number, second and third are variables w.r. to which is computed the derivative.
    Only non-null derivatives are stored in the map.
    Contains only second order derivatives where var1 >= var2 (for obvious symmetry reasons).
92
    Variable indices are those of the getDerivID() method.
93
  */
94
  second_derivatives_t second_derivatives;
95

96
  using third_derivatives_t = map<tuple<int, int, int, int>, expr_t>;
97
98
99
100
  //! Third order derivatives
  /*! First index is equation number, second, third and fourth are variables w.r. to which is computed the derivative.
    Only non-null derivatives are stored in the map.
    Contains only third order derivatives where var1 >= var2 >= var3 (for obvious symmetry reasons).
101
    Variable indices are those of the getDerivID() method.
102
  */
103
  third_derivatives_t third_derivatives;
104

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  //! Derivatives of the residuals w.r. to parameters
  /*! First index is equation number, second is parameter.
    Only non-null derivatives are stored in the map.
    Parameter indices are those of the getDerivID() method.
  */
  first_derivatives_t residuals_params_derivatives;

  //! Second derivatives of the residuals w.r. to parameters
  /*! First index is equation number, second and third indeces are parameters.
    Only non-null derivatives are stored in the map.
    Parameter indices are those of the getDerivID() method.
  */
  second_derivatives_t residuals_params_second_derivatives;

  //! Derivatives of the jacobian w.r. to parameters
  /*! First index is equation number, second is endo/exo/exo_det variable, and third is parameter.
    Only non-null derivatives are stored in the map.
    Variable and parameter indices are those of the getDerivID() method.
  */
  second_derivatives_t jacobian_params_derivatives;

  //! Second derivatives of the jacobian w.r. to parameters
  /*! First index is equation number, second is endo/exo/exo_det variable, and third and fourth are parameters.
    Only non-null derivatives are stored in the map.
    Variable and parameter indices are those of the getDerivID() method.
  */
  third_derivatives_t jacobian_params_second_derivatives;

  //! Derivatives of the hessian w.r. to parameters
  /*! First index is equation number, first and second are endo/exo/exo_det variable, and third is parameter.
    Only non-null derivatives are stored in the map.
    Variable and parameter indices are those of the getDerivID() method.
  */
  third_derivatives_t hessian_params_derivatives;

Houtan Bastani's avatar
Houtan Bastani committed
140
  //! Temporary terms for the static/dynamic file (those which will be noted T[x])
141
  temporary_terms_t temporary_terms;
142
  map<expr_t, expr_t, ExprNodeLess> temporary_terms_mlv;
143
144
145
146
  temporary_terms_t temporary_terms_res;
  temporary_terms_t temporary_terms_g1;
  temporary_terms_t temporary_terms_g2;
  temporary_terms_t temporary_terms_g3;
147

Houtan Bastani's avatar
Houtan Bastani committed
148
149
  temporary_terms_idxs_t temporary_terms_idxs;

150
151
  //! Temporary terms for the file containing parameters derivatives
  temporary_terms_t params_derivs_temporary_terms;
152
153
154
155
156
  temporary_terms_t params_derivs_temporary_terms_res;
  temporary_terms_t params_derivs_temporary_terms_g1;
  temporary_terms_t params_derivs_temporary_terms_res2;
  temporary_terms_t params_derivs_temporary_terms_g12;
  temporary_terms_t params_derivs_temporary_terms_g2;
157

158
159
  temporary_terms_idxs_t params_derivs_temporary_terms_idxs;

160
  //! Trend variables and their growth factors
161
162
163
  map<int, expr_t> trend_symbols_map;

  //! for all trends; the boolean is true if this is a log-trend, false otherwise
164
  using nonstationary_symbols_map_t = map<int, pair<bool, expr_t>>;
165

166
  //! Nonstationary variables and their deflators
167
  nonstationary_symbols_map_t nonstationary_symbols_map;
168

169
170
171
172
173
  //! vector of block reordered variables and equations
  vector<int> equation_reordered, variable_reordered, inv_equation_reordered, inv_variable_reordered;

  //! the file containing the model and the derivatives code
  ofstream code_file;
174
175
176
  
  //! Vector indicating if the equation is linear in endogenous variable (true) or not (false)
  vector<bool> is_equation_linear;
177

178
179
180
181
182
183
184
185
186
  //! Computes 1st derivatives
  /*! \param vars the derivation IDs w.r. to which compute the derivatives */
  void computeJacobian(const set<int> &vars);
  //! Computes 2nd derivatives
  /*! \param vars the derivation IDs w.r. to which derive the 1st derivatives */
  void computeHessian(const set<int> &vars);
  //! Computes 3rd derivatives
  /*! \param vars the derivation IDs w.r. to which derive the 2nd derivatives */
  void computeThirdDerivatives(const set<int> &vars);
187
  //! Computes derivatives of the Jacobian and Hessian w.r. to parameters
188
  void computeParamsDerivatives(int paramsDerivsOrder);
189
  //! Write derivative of an equation w.r. to a variable
190
  void writeDerivative(ostream &output, int eq, int symb_id, int lag, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
191
  //! Computes temporary terms (for all equations and derivatives)
192
  void computeTemporaryTerms(bool is_matlab, bool no_tmp_terms);
193
194
  //! Computes temporary terms for the file containing parameters derivatives
  void computeParamsDerivativesTemporaryTerms();
Stéphane Adjemian's avatar
Stéphane Adjemian committed
195
  //! Writes temporary terms
196
  void writeTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, const temporary_terms_idxs_t &tt_idxs, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
197
  void writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, deriv_node_temp_terms_t &tef_terms, string &concat) const;
198
  //! Compiles temporary terms
199
  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;
200
  //! Adds informations for simulation in a binary file
201
  void Write_Inf_To_Bin_File(const string &filename, int &u_count_int, bool &file_open, bool is_two_boundaries, int block_mfs) const;
202
  //! Fixes output when there are more than 32 nested parens, Issue #1201
203
  void fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const;
204
205
  //! Tests if string contains more than 32 nested parens, Issue #1201
  bool testNestedParenthesis(const string &str) const;
206
  void writeModelLocalVariableTemporaryTerms(const temporary_terms_t &tto, const map<expr_t, expr_t, ExprNodeLess> &tt,
Houtan Bastani's avatar
Houtan Bastani committed
207
208
                                             ostream &output, ExprNodeOutputType output_type,
                                             deriv_node_temp_terms_t &tef_terms) const;
209
210
  //! Writes model equations
  void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
Houtan Bastani's avatar
Houtan Bastani committed
211
  void writeModelEquations(ostream &output, ExprNodeOutputType output_type,
212
                           const temporary_terms_t &temporary_terms) const;
213
  //! Writes JSON model equations
214
215
216
217
  //! if residuals = true, we are writing the dynamic/static model.
  //! Otherwise, just the model equations (with line numbers, no tmp terms)
  void writeJsonModelEquations(ostream &output, bool residuals) const;
  void writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const;
218
  //! Compiles model equations
219
  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;
220

221
  //! Writes LaTeX model file
222
  void writeLatexModelFile(const string &basename, ExprNodeOutputType output_type, const bool write_equation_tags) const;
223

224
225
  //! Sparse matrix of double to store the values of the Jacobian
  /*! First index is equation number, second index is endogenous type specific ID */
226
  using jacob_map_t = map<pair<int, int>, double>;
227
228
229

  //! Sparse matrix of double to store the values of the Jacobian
  /*! First index is lag, second index is equation number, third index is endogenous type specific ID */
230
  using dynamic_jacob_map_t = map<pair<int, pair<int, int>>, expr_t>;
231
232
233
234
235
236
237
238
239

  //! Normalization of equations
  /*! Maps endogenous type specific IDs to equation numbers */
  vector<int> endo2eq;

  //! number of equation in the prologue and in the epilogue
  unsigned int epilogue, prologue;

  //! for each block contains pair< max_lag, max_lead>
240
  lag_lead_vector_t block_lag_lead;
241
242

  //! Compute the matching between endogenous and variable using the jacobian contemporaneous_jacobian
sebastien's avatar
sebastien committed
243
244
245
246
  /*!
    \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
    \return True if a complete normalization has been achieved
  */
247
  bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose);
sebastien's avatar
sebastien committed
248

249
  //! Try to compute the matching between endogenous and variable using a decreasing cutoff
sebastien's avatar
sebastien committed
250
251
252
253
254
  /*!
    Applied to the jacobian contemporaneous_jacobian and stop when a matching is found.
    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.
    If no matching is found with a zero cutoff close to zero an error message is printout.
  */
255
  void computeNonSingularNormalization(jacob_map_t &contemporaneous_jacobian, double cutoff, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian);
256
257
  //! Try to find a natural normalization if all equations are matched to an endogenous variable on the LHS
  bool computeNaturalNormalization();
258
259
260
  //! Try to normalized each unnormalized equation (matched endogenous variable only on the LHS)
  void computeNormalizedEquations(multimap<int, int> &endo2eqs) const;
  //! Evaluate the jacobian and suppress all the elements below the cutoff
261
  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);
262
263
264
265
266
  //! Select and reorder the non linear equations of the model
  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,
                                                                    vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered,
                                                                    lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead,
                                                                    vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed);
267
  //! Search the equations and variables belonging to the prologue and the epilogue of the model
268
  void computePrologueAndEpilogue(const jacob_map_t &static_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered);
269
  //! Determine the type of each equation of model and try to normalized the unnormalized equation using computeNormalizedEquations
270
  equation_type_and_normalized_equation_t equationTypeDetermination(const map<pair<int, pair<int, int>>, expr_t> &first_order_endo_derivatives, const vector<int> &Index_Var_IM, const vector<int> &Index_Equ_IM, int mfs) const;
271
  //! Compute the block decomposition and for a non-recusive block find the minimum feedback set
272
  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;
273
  //! Reduce the number of block merging the same type equation in the prologue and the epilogue and determine the type of each block
274
  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<pair< pair<int, int>, pair<int, int>>> &block_col_type, bool linear_decomposition);
275
  //! Determine the maximum number of lead and lag for the endogenous variable in a bloc
276
  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;
277
278
  //! For each equation determine if it is linear or not
  vector<bool> equationLinear(map<pair<int, pair<int, int> >, expr_t> first_order_endo_derivatives) const;
279
  //! Print an abstract of the block structure of the model
280
  void printBlockDecomposition(const vector<pair<int, int>> &blocks) const;
281
  //! Determine for each block if it is linear or not
282
  vector<bool> BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vector<int> &variable_reordered) const;
283
284
285
286
287
288
289
290
291

  //! Determine the simulation type of each block
  virtual BlockSimulationType getBlockSimulationType(int block_number) const = 0;
  //! Return the number of blocks
  virtual unsigned int getNbBlocks() const = 0;
  //! Return the first equation number of a block
  virtual unsigned int getBlockFirstEquation(int block_number) const = 0;
  //! Return the size of the block block_number
  virtual unsigned int getBlockSize(int block_number) const = 0;
292
293
294
295
  //! Return the number of exogenous variable in the block block_number
  virtual unsigned int getBlockExoSize(int block_number) const = 0;
  //! Return the number of colums in the jacobian matrix for exogenous variable in the block block_number
  virtual unsigned int getBlockExoColSize(int block_number) const = 0;
296
297
298
299
300
301
  //! Return the number of feedback variable of the block block_number
  virtual unsigned int getBlockMfs(int block_number) const = 0;
  //! Return the maximum lag in a block
  virtual unsigned int getBlockMaxLag(int block_number) const = 0;
  //! Return the maximum lead in a block
  virtual unsigned int getBlockMaxLead(int block_number) const = 0;
Stéphane Adjemian's avatar
Stéphane Adjemian committed
302
303
304
  inline void
  setBlockLeadLag(int block, int max_lag, int max_lead)
  {
305
    block_lag_lead[block] = { max_lag, max_lead };
Stéphane Adjemian's avatar
Stéphane Adjemian committed
306
307
  };

308
309
310
311
  //! Return the type of equation (equation_number) belonging to the block block_number
  virtual EquationType getBlockEquationType(int block_number, int equation_number) const = 0;
  //! Return true if the equation has been normalized
  virtual bool isBlockEquationRenormalized(int block_number, int equation_number) const = 0;
312
313
314
315
  //! Return the expr_t of the equation equation_number belonging to the block block_number
  virtual expr_t getBlockEquationExpr(int block_number, int equation_number) const = 0;
  //! Return the expr_t of the renormalized equation equation_number belonging to the block block_number
  virtual expr_t getBlockEquationRenormalizedExpr(int block_number, int equation_number) const = 0;
316
317
318
319
  //! Return the original number of equation equation_number belonging to the block block_number
  virtual int getBlockEquationID(int block_number, int equation_number) const = 0;
  //! Return the original number of variable variable_number belonging to the block block_number
  virtual int getBlockVariableID(int block_number, int variable_number) const = 0;
320
321
  //! Return the original number of the exogenous variable varexo_number belonging to the block block_number
  virtual int getBlockVariableExoID(int block_number, int variable_number) const = 0;
322
323
324
325
  //! Return the position of equation_number in the block number belonging to the block block_number
  virtual int getBlockInitialEquationID(int block_number, int equation_number) const = 0;
  //! Return the position of variable_number in the block number belonging to the block block_number
  virtual int getBlockInitialVariableID(int block_number, int variable_number) const = 0;
326
327
328
329
330
331
  //! Return the position of variable_number in the block number belonging to the block block_number
  virtual int getBlockInitialExogenousID(int block_number, int variable_number) const = 0;
  //! Return the position of the deterministic exogenous variable_number in the block number belonging to the block block_number
  virtual int getBlockInitialDetExogenousID(int block_number, int variable_number) const = 0;
  //! Return the position of the other endogenous variable_number in the block number belonging to the block block_number
  virtual int getBlockInitialOtherEndogenousID(int block_number, int variable_number) const = 0;
332
333
  //! Initialize equation_reordered & variable_reordered
  void initializeVariablesAndEquations();
334
public:
335
336
  ModelTree(SymbolTable &symbol_table_arg,
            NumericalConstants &num_constants_arg,
337
            ExternalFunctionsTable &external_functions_table_arg);
338
  //! Absolute value under which a number is considered to be zero
339
  double cutoff{1e-15};
340
341
342
343
344
345
  //! Compute the minimum feedback set
  /*!   0 : all endogenous variables are considered as feedback variables
    1 : the variables belonging to non normalized equation are considered as feedback variables
    2 : the variables belonging to a non linear equation are considered as feedback variables
    3 : the variables belonging to a non normalizable non linear equation are considered as feedback variables
    default value = 0 */
346
  int mfs{0};
347
348
  //! Declare a node as an equation of the model; also give its line number
  void addEquation(expr_t eq, int lineno);
349
  //! Declare a node as an equation of the model, also giving its tags
350
  void addEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
sebastien's avatar
sebastien committed
351
  //! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations
352
  void addAuxEquation(expr_t eq);
353
  //! Returns the number of equations in the model
354
  int equation_number() const;
355
  //! Adds a trend variable with its growth factor
356
  void addTrendVariables(vector<int> trend_vars, expr_t growth_factor) noexcept(false);
357
  //! Adds a nonstationary variables with their (common) deflator
358
  void addNonstationaryVariables(vector<int> nonstationary_vars, bool log_deflator, expr_t deflator) noexcept(false);
359
360
  //! Is a given variable non-stationary?
  bool isNonstationary(int symb_id) const;
361
  void set_cutoff_to_zero();
362
363
364
365
366
367
368
  //! Helper for writing the Jacobian elements in MATLAB and C
  /*! Writes either (i+1,j+1) or [i+j*no_eq] */
  void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
  //! Helper for writing the sparse Hessian or third derivatives in MATLAB and C
  /*! If order=2, writes either v2(i+1,j+1) or v2[i+j*NNZDerivatives[1]]
    If order=3, writes either v3(i+1,j+1) or v3[i+j*NNZDerivatives[2]] */
  void sparseHelper(int order, ostream &output, int row_nb, int col_nb, ExprNodeOutputType output_type) const;
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  inline static std::string
  c_Equation_Type(int type)
  {
    char c_Equation_Type[4][13] =
      {
        "E_UNKNOWN   ",
        "E_EVALUATE  ",
        "E_EVALUATE_S",
        "E_SOLVE     "
      };
    return (c_Equation_Type[type]);
  };

  inline static std::string
  BlockType0(BlockType type)
  {
    switch (type)
      {
      case SIMULTANS:
        return ("SIMULTANEOUS TIME SEPARABLE  ");
        break;
      case PROLOGUE:
        return ("PROLOGUE                     ");
        break;
      case EPILOGUE:
        return ("EPILOGUE                     ");
        break;
      case SIMULTAN:
        return ("SIMULTANEOUS TIME UNSEPARABLE");
        break;
      default:
        return ("UNKNOWN                      ");
        break;
      }
  };

  inline static std::string
  BlockSim(int type)
  {
    switch (type)
      {
      case EVALUATE_FORWARD:
        return ("EVALUATE FORWARD             ");
        break;
      case EVALUATE_BACKWARD:
        return ("EVALUATE BACKWARD            ");
        break;
      case SOLVE_FORWARD_SIMPLE:
        return ("SOLVE FORWARD SIMPLE         ");
        break;
      case SOLVE_BACKWARD_SIMPLE:
        return ("SOLVE BACKWARD SIMPLE        ");
        break;
      case SOLVE_TWO_BOUNDARIES_SIMPLE:
        return ("SOLVE TWO BOUNDARIES SIMPLE  ");
        break;
      case SOLVE_FORWARD_COMPLETE:
        return ("SOLVE FORWARD COMPLETE       ");
        break;
      case SOLVE_BACKWARD_COMPLETE:
        return ("SOLVE BACKWARD COMPLETE      ");
        break;
      case SOLVE_TWO_BOUNDARIES_COMPLETE:
        return ("SOLVE TWO BOUNDARIES COMPLETE");
        break;
      default:
        return ("UNKNOWN                      ");
        break;
      }
  };
439
440
441
};

#endif