/*
* Copyright © 2003-2019 Dynare Team
*
* 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 .
*/
#ifndef _DYNAMICMODEL_HH
#define _DYNAMICMODEL_HH
using namespace std;
#include
#include
#include "StaticModel.hh"
//! Stores a dynamic model
class DynamicModel : public ModelTree
{
public:
//! A reference to the trend component model table
TrendComponentModelTable &trend_component_model_table;
//! A reference to the VAR model table
VarModelTable &var_model_table;
/* Used in the balanced growth test, for determining whether the
cross-derivative of a given equation, w.r.t. an endogenous and a trend
variable is zero. Controlled by option “balanced_growth_test_tol” of the
“model” block. The default should not be too small (see dynare#1389). */
double balanced_growth_test_tol{1e-6};
private:
/* Used in the balanced growth test, for skipping equations where the test
cannot be performed (i.e. when LHS=RHS at the initial values). Should not
be too large, otherwise the test becomes less powerful. */
constexpr static double zero_band{1e-8};
//! Stores equations declared as [static]
/*! They will be used in the conversion to StaticModel to replace equations marked as [dynamic] */
vector static_only_equations;
//! Stores line numbers of equations declared as [static]
vector static_only_equations_lineno;
//! Stores the equation tags of equations declared as [static]
vector>> static_only_equations_equation_tags;
using deriv_id_table_t = map, int>;
//! Maps a pair (symbol_id, lag) to a deriv ID
deriv_id_table_t deriv_id_table;
//! Maps a deriv ID to a pair (symbol_id, lag)
vector> inv_deriv_id_table;
//! Maps a deriv_id to the column index of the dynamic Jacobian
/*! Contains only endogenous, exogenous and exogenous deterministic */
map dyn_jacobian_cols_table;
//! Maximum lag and lead over all types of variables (positive values)
/*! Set by computeDerivIDs() */
int max_lag{0}, max_lead{0};
//! Maximum lag and lead over endogenous variables (positive values)
/*! Set by computeDerivIDs() */
int max_endo_lag{0}, max_endo_lead{0};
//! Maximum lag and lead over exogenous variables (positive values)
/*! Set by computeDerivIDs() */
int max_exo_lag{0}, max_exo_lead{0};
//! Maximum lag and lead over deterministic exogenous variables (positive values)
/*! Set by computeDerivIDs() */
int max_exo_det_lag{0}, max_exo_det_lead{0};
//! Maximum lag and lead over all types of variables (positive values) of original model
int max_lag_orig{0}, max_lead_orig{0}, max_lag_with_diffs_expanded_orig{0};
//! Maximum lag and lead over endogenous variables (positive values) of original model
int max_endo_lag_orig{0}, max_endo_lead_orig{0};
//! Maximum lag and lead over exogenous variables (positive values) of original model
int max_exo_lag_orig{0}, max_exo_lead_orig{0};
//! Maximum lag and lead over deterministic exogenous variables (positive values) of original model
int max_exo_det_lag_orig{0}, max_exo_det_lead_orig{0};
//! Cross reference information
map xrefs;
map, set> xref_param;
map, set> xref_endo;
map, set> xref_exo;
map, set> xref_exo_det;
//! Nonzero equations in the Hessian
map nonzero_hessian_eqs;
//! Number of columns of dynamic jacobian
/*! Set by computeDerivID()s and computeDynJacobianCols() */
int dynJacobianColsNbr{0};
//! Temporary terms for block decomposed models
vector< vector> v_temporary_terms;
vector v_temporary_terms_inuse;
//! Creates mapping for variables and equations they are present in
map> variableMapping;
//! Store the derivatives or the chainrule derivatives:map, expr_t>
using first_chain_rule_derivatives_t = map, expr_t>;
first_chain_rule_derivatives_t first_chain_rule_derivatives;
//! Writes dynamic model file (Matlab version)
void writeDynamicMFile(const string &basename) const;
//! Writes dynamic model file (Julia version)
void writeDynamicJuliaFile(const string &dynamic_basename) const;
//! Writes dynamic model file (C version)
/*! \todo add third derivatives handling */
void writeDynamicCFile(const string &basename, const int order) const;
//! Writes dynamic model file when SparseDLL option is on
void writeSparseDynamicMFile(const string &basename) const;
//! Writes the dynamic model equations and its derivatives
/*! \todo add third derivatives handling in C output */
void writeDynamicModel(ostream &DynamicOutput, bool use_dll, bool julia) const;
void writeDynamicModel(const string &basename, bool use_dll, bool julia) const;
void writeDynamicModel(const string &basename, ostream &DynamicOutput, bool use_dll, bool julia) const;
//! Writes the Block reordred structure of the model in M output
void writeModelEquationsOrdered_M(const string &basename) const;
//! Writes the code of the Block reordred structure of the model in virtual machine bytecode
void writeModelEquationsCode_Block(const string &basename, const map_idx_t &map_idx, const bool linear_decomposition) const;
//! Writes the code of the model in virtual machine bytecode
void writeModelEquationsCode(const string &basename, const map_idx_t &map_idx) const;
void writeSetAuxiliaryVariables(const string &basename, const bool julia) const;
void writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputType output_type) const;
//! Computes jacobian and prepares for equation normalization
/*! Using values from initval/endval blocks and parameter initializations:
- computes the jacobian for the model w.r. to contemporaneous variables
- removes edges of the incidence matrix when derivative w.r. to the corresponding variable is too close to zero (below the cutoff)
*/
//void evaluateJacobian(const eval_context_t &eval_context, jacob_map *j_m, bool dynamic);
//! return a map on the block jacobian
map, int> get_Derivatives(int block);
//! Computes chain rule derivatives of the Jacobian w.r. to endogenous variables
void computeChainRuleJacobian(blocks_derivatives_t &blocks_derivatives);
string reform(string name) const;
map_idx_t map_idx;
//! sorts the temporary terms in the blocks order
void computeTemporaryTermsOrdered();
//! creates a mapping from the index of temporary terms to a natural index
void computeTemporaryTermsMapping();
//! Write derivative code of an equation w.r. to a variable
void compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, int lag, const map_idx_t &map_idx) const;
//! Write chain rule derivative code of an equation w.r. to a variable
void compileChainRuleDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int var, int lag, const map_idx_t &map_idx) const;
//! Get the type corresponding to a derivation ID
SymbolType getTypeByDerivID(int deriv_id) const noexcept(false) override;
//! Get the lag corresponding to a derivation ID
int getLagByDerivID(int deriv_id) const noexcept(false) override;
//! Get the symbol ID corresponding to a derivation ID
int getSymbIDByDerivID(int deriv_id) const noexcept(false) override;
//! Compute the column indices of the dynamic Jacobian
void computeDynJacobianCols(bool jacobianExo);
//! Computes derivatives of the Jacobian w.r. to trend vars and tests that they are equal to zero
void testTrendDerivativesEqualToZero(const eval_context_t &eval_context);
//! Collect only the first derivatives
map, expr_t> collect_first_order_derivatives_endogenous();
//! Allocates the derivation IDs for all dynamic variables of the model
/*! Also computes max_{endo,exo}_{lead_lag}, and initializes dynJacobianColsNbr to the number of dynamic endos */
void computeDerivIDs();
//! Collecte the derivatives w.r. to endogenous of the block, to endogenous of previouys blocks and to exogenous
void collect_block_first_order_derivatives();
//! Collecte the informations about exogenous, deterministic exogenous and endogenous from the previous block for each block
void collectBlockVariables();
//! Factorized code for substitutions of leads/lags
/*! \param[in] type determines which type of variables is concerned
\param[in] deterministic_model whether we are in a deterministic model (only for exogenous leads/lags)
\param[in] subset variables to which to apply the transformation (only for diff of forward vars)
*/
void substituteLeadLagInternal(AuxVarType type, bool deterministic_model, const vector &subset);
//! Indicate if the temporary terms are computed for the overall model (true) or not (false). Default value true
bool global_temporary_terms{true};
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
equation_type_and_normalized_equation_t equation_type_and_normalized_equation;
//! for each block contains pair< Simulation_Type, pair < Block_Size, Recursive_part_Size >>
block_type_firstequation_size_mfs_t block_type_firstequation_size_mfs;
//! for all blocks derivatives description
blocks_derivatives_t blocks_derivatives;
//! The jacobian without the elements below the cutoff
dynamic_jacob_map_t dynamic_jacobian;
//! Vector indicating if the block is linear in endogenous variable (true) or not (false)
vector blocks_linear;
//! Map the derivatives for a block tuple
using derivative_t = map, expr_t>;
//! Vector of derivative for each blocks
vector derivative_endo, derivative_other_endo, derivative_exo, derivative_exo_det;
//!List for each block and for each lag-lead all the other endogenous variables and exogenous variables
using var_t = set;
using lag_var_t = map;
vector other_endo_block, exo_block, exo_det_block;
//!List for each block the exogenous variables
vector> block_var_exo;
map< int, map> block_exo_index, block_det_exo_index, block_other_endo_index;
//! for each block described the number of static, forward, backward and mixed variables in the block
/*! tuple */
vector> block_col_type;
//! Help computeXrefs to compute the reverse references (i.e. param->eqs, endo->eqs, etc)
void computeRevXref(map, set> &xrefset, const set> &eiref, int eqn);
//! Write reverse cross references
void writeRevXrefs(ostream &output, const map, set> &xrefmap, const string &type) const;
//! List for each variable its block number and its maximum lag and lead inside the block
vector> variable_block_lead_lag;
//! List for each equation its block number
vector equation_block;
//! Used for var_expectation and var_model
map> var_expectation_functions_to_write;
//!Maximum lead and lag for each block on endogenous of the block, endogenous of the previous blocks, exogenous and deterministic exogenous
vector> endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block;
void writeWrapperFunctions(const string &name, const string &ending) const;
void writeDynamicModelHelper(const string &basename,
const string &name, const string &retvalname,
const string &name_tt, size_t ttlen,
const string &previous_tt_name,
const ostringstream &init_s,
const ostringstream &end_s,
const ostringstream &s, const ostringstream &s_tt) const;
//! Create a legacy *_dynamic.m file for Matlab/Octave not yet using the temporary terms array interface
void writeDynamicMatlabCompatLayer(const string &basename) const;
vector getEquationNumbersFromTags(const set &eqtags) const;
void findPacExpectationEquationNumbers(vector &eqnumber) const;
//! Internal helper for the copy constructor and assignment operator
/*! Copies all the structures that contain ExprNode*, by the converting the
pointers into their equivalent in the new tree */
void copyHelper(const DynamicModel &m);
public:
DynamicModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg,
TrendComponentModelTable &trend_component_model_table_arg,
VarModelTable &var_model_table_arg);
DynamicModel(const DynamicModel &m);
DynamicModel(DynamicModel &&) = delete;
DynamicModel & operator=(const DynamicModel &m);
DynamicModel & operator=(DynamicModel &&) = delete;
//! Compute cross references
void computeXrefs();
//! Write cross references
void writeXrefs(ostream &output) const;
//! Execute computations (variable sorting + derivation)
/*!
\param jacobianExo whether derivatives w.r. to exo and exo_det should be in the Jacobian (derivatives w.r. to endo are always computed)
\param derivsOrder order of derivatives w.r. to exo, exo_det and endo should be computed (implies jacobianExo = true when order >= 2)
\param paramsDerivsOrder order of derivatives w.r. to a pair (endo/exo/exo_det, parameter) to be computed (>0 implies jacobianExo = true)
\param eval_context evaluation context for normalization
\param no_tmp_terms if true, no temporary terms will be computed in the dynamic files
*/
void computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsOrder,
const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode, bool linear_decomposition);
//! Writes model initialization and lead/lag incidence matrix to output
void writeOutput(ostream &output, const string &basename, bool block, bool linear_decomposition, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const;
//! Write JSON AST
void writeJsonAST(ostream &output) const;
//! Write JSON variable mapping
void writeJsonVariableMapping(ostream &output) const;
//! Write JSON Output
void writeJsonOutput(ostream &output) const;
//! Write JSON Output representation of original dynamic model
void writeJsonOriginalModelOutput(ostream &output) const;
//! Write JSON Output representation of model info (useful stuff from M_)
void writeJsonDynamicModelInfo(ostream &output) const;
//! Write JSON Output representation of dynamic model after computing pass
void writeJsonComputingPassOutput(ostream &output, bool writeDetails) const;
//! Write JSON prams derivatives file
void writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const;
//! Write cross reference output if the xref maps have been filed
void writeJsonXrefs(ostream &output) const;
void writeJsonXrefsHelper(ostream &output, const map, set> &xrefs) const;
//! Print equations that have non-zero second derivatives
void printNonZeroHessianEquations(ostream &output) const;
//! Set the equations that have non-zero second derivatives
void setNonZeroHessianEquations(map &eqs);
//! Fill Autoregressive Matrix for var_model
map, expr_t>> fillAutoregressiveMatrix(bool is_var) const;
//! Fill Error Component Matrix for trend_component_model
/*! Returns a pair (A0r, A0starr) */
pair