2008-02-03 11:28:36 +01:00
|
|
|
|
/*
|
2021-01-25 18:03:37 +01:00
|
|
|
|
* Copyright © 2003-2021 Dynare Team
|
2008-02-03 11:28:36 +01:00
|
|
|
|
*
|
|
|
|
|
* 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
|
2021-06-09 16:52:20 +02:00
|
|
|
|
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
2008-02-03 11:28:36 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef _MODELTREE_HH
|
|
|
|
|
#define _MODELTREE_HH
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
2009-09-30 17:10:31 +02:00
|
|
|
|
#include <deque>
|
2008-02-03 11:28:36 +01:00
|
|
|
|
#include <map>
|
|
|
|
|
#include <ostream>
|
2018-10-11 11:21:58 +02:00
|
|
|
|
#include <array>
|
2019-04-04 17:01:37 +02:00
|
|
|
|
#include <filesystem>
|
2018-10-26 11:44:26 +02:00
|
|
|
|
|
2008-02-03 11:28:36 +01:00
|
|
|
|
#include "DataTree.hh"
|
2020-02-20 15:29:10 +01:00
|
|
|
|
#include "EquationTags.hh"
|
2016-05-12 12:02:34 +02:00
|
|
|
|
#include "ExtendedPreprocessorTypes.hh"
|
2008-02-03 11:28:36 +01:00
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
// Helper to convert a vector into a tuple
|
2019-12-20 16:59:30 +01:00
|
|
|
|
template<typename T, size_t... Indices>
|
|
|
|
|
auto
|
|
|
|
|
vectorToTupleHelper(const vector<T> &v, index_sequence<Indices...>)
|
|
|
|
|
{
|
|
|
|
|
return tuple(v[Indices] ...);
|
2018-11-15 16:39:53 +01:00
|
|
|
|
}
|
2019-12-20 16:59:30 +01:00
|
|
|
|
template<size_t N, typename T>
|
|
|
|
|
auto
|
|
|
|
|
vectorToTuple(const vector<T> &v)
|
|
|
|
|
{
|
2018-11-15 16:39:53 +01:00
|
|
|
|
assert(v.size() >= N);
|
|
|
|
|
return vectorToTupleHelper(v, make_index_sequence<N>());
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-16 19:18:45 +02:00
|
|
|
|
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
|
2020-05-07 15:20:11 +02:00
|
|
|
|
using equation_type_and_normalized_equation_t = vector<pair<EquationType, BinaryOpNode *>>;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
|
|
|
|
//! Vector describing variables: max_lag in the block, max_lead in the block
|
2020-03-19 17:46:10 +01:00
|
|
|
|
using lag_lead_vector_t = vector<pair<int, int>>;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
2009-04-14 16:39:53 +02:00
|
|
|
|
//! Shared code for static and dynamic models
|
2008-02-03 11:28:36 +01:00
|
|
|
|
class ModelTree : public DataTree
|
|
|
|
|
{
|
2009-12-16 14:21:31 +01:00
|
|
|
|
friend class DynamicModel;
|
|
|
|
|
friend class StaticModel;
|
2019-12-02 19:21:14 +01:00
|
|
|
|
public:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
// Set via the `compiler` command
|
|
|
|
|
string user_set_add_flags, user_set_subst_flags, user_set_add_libs, user_set_subst_libs, user_set_compiler;
|
2009-04-14 16:39:53 +02:00
|
|
|
|
protected:
|
2019-10-29 12:56:53 +01:00
|
|
|
|
/*
|
|
|
|
|
* ************** BEGIN **************
|
|
|
|
|
* The following structures keep track of the model equations and must all be updated
|
|
|
|
|
* when adding or removing an equation. Hence, if a new parallel structure is added
|
|
|
|
|
* in the future, it must be maintained whereever these structures are updated
|
2020-01-06 18:26:35 +01:00
|
|
|
|
* See in particular methods clearEquations(), replaceMyEquations() and
|
|
|
|
|
* computeRamseyPolicyFOCs() of DynamicModel class.
|
2019-10-29 12:56:53 +01:00
|
|
|
|
* NB: This message added with the introduction of the `exclude_eqs` option, hence
|
|
|
|
|
* that's a place to update future structures.
|
|
|
|
|
*/
|
2009-09-30 17:10:31 +02:00
|
|
|
|
//! Stores declared and generated auxiliary equations
|
2008-02-03 11:28:36 +01:00
|
|
|
|
vector<BinaryOpNode *> equations;
|
2014-01-27 16:41:43 +01:00
|
|
|
|
//! Stores line numbers of declared equations; -1 means undefined
|
|
|
|
|
vector<int> equations_lineno;
|
2019-10-29 12:56:53 +01:00
|
|
|
|
//! Stores equation tags
|
2020-02-20 15:29:10 +01:00
|
|
|
|
EquationTags equation_tags;
|
2019-10-29 12:56:53 +01:00
|
|
|
|
/*
|
|
|
|
|
* ************** END **************
|
|
|
|
|
*/
|
|
|
|
|
|
2009-09-30 17:10:31 +02:00
|
|
|
|
//! Only stores generated auxiliary equations, in an order meaningful for evaluation
|
2018-07-27 14:19:59 +02:00
|
|
|
|
/*! 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 */
|
2019-12-03 14:19:32 +01:00
|
|
|
|
vector<BinaryOpNode *> aux_equations;
|
2020-01-20 17:22:32 +01:00
|
|
|
|
|
|
|
|
|
//! Maximum order at which (endogenous) derivatives have been computed
|
|
|
|
|
int computed_derivs_order{0};
|
2009-09-30 17:10:31 +02:00
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
//! Stores derivatives
|
|
|
|
|
/*! Index 0 is not used, index 1 contains first derivatives, ...
|
|
|
|
|
For each derivation order, stores a map whose key is a vector of integer: the
|
|
|
|
|
first integer is the equation index, the remaining ones are the derivation
|
2018-11-22 14:32:40 +01:00
|
|
|
|
IDs of variables (in non-decreasing order, to avoid storing symmetric
|
|
|
|
|
elements several times) */
|
2018-11-15 16:39:53 +01:00
|
|
|
|
vector<map<vector<int>, expr_t>> derivatives;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
//! Number of non-zero derivatives
|
|
|
|
|
/*! Index 0 is not used, index 1 contains number of non-zero first
|
|
|
|
|
derivatives, ... */
|
|
|
|
|
vector<int> NNZDerivatives;
|
|
|
|
|
|
|
|
|
|
//! Derivatives with respect to parameters
|
|
|
|
|
/*! The key of the outer map is a pair (derivation order w.r.t. endogenous,
|
|
|
|
|
derivation order w.r.t. parameters). For e.g., { 1, 2 } corresponds to the jacobian
|
|
|
|
|
differentiated twice w.r.t. to parameters.
|
|
|
|
|
In inner maps, the vector of integers consists of: the equation index, then
|
2018-11-22 15:41:11 +01:00
|
|
|
|
the derivation IDs of endogenous (in non-decreasing order),
|
|
|
|
|
then the IDs of parameters (in non-decreasing order)*/
|
2018-11-15 16:39:53 +01:00
|
|
|
|
map<pair<int,int>, map<vector<int>, expr_t>> params_derivatives;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-16 16:53:07 +01:00
|
|
|
|
//! Used model local variables, that will be treated as temporary terms
|
|
|
|
|
/*! See the comments in ModelTree::computeTemporaryTerms() */
|
2020-06-05 17:11:29 +02:00
|
|
|
|
map<VariableNode *, expr_t, ExprNodeLess> temporary_terms_mlv;
|
2018-11-15 16:39:53 +01:00
|
|
|
|
|
|
|
|
|
//! Temporary terms for residuals and derivatives
|
|
|
|
|
/*! Index 0 is temp. terms of residuals, index 1 for first derivatives, ... */
|
|
|
|
|
vector<temporary_terms_t> temporary_terms_derivatives;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-30 12:22:13 +01:00
|
|
|
|
//! Stores, for each temporary term, its index in the MATLAB/Julia vector
|
2018-03-27 17:14:30 +02:00
|
|
|
|
temporary_terms_idxs_t temporary_terms_idxs;
|
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
//! Temporary terms for parameter derivatives, under a disaggregated form
|
|
|
|
|
/*! The pair of integers is to be interpreted as in param_derivatives */
|
2019-12-20 16:59:30 +01:00
|
|
|
|
map<pair<int, int>, temporary_terms_t> params_derivs_temporary_terms;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-30 12:22:13 +01:00
|
|
|
|
//! Stores, for each temporary term in param. derivs, its index in the MATLAB/Julia vector
|
2018-05-28 15:23:15 +02:00
|
|
|
|
temporary_terms_idxs_t params_derivs_temporary_terms_idxs;
|
|
|
|
|
|
2010-10-15 19:05:16 +02:00
|
|
|
|
//! Trend variables and their growth factors
|
2013-03-26 16:46:18 +01:00
|
|
|
|
map<int, expr_t> trend_symbols_map;
|
|
|
|
|
|
|
|
|
|
//! for all trends; the boolean is true if this is a log-trend, false otherwise
|
2018-06-04 14:31:26 +02:00
|
|
|
|
using nonstationary_symbols_map_t = map<int, pair<bool, expr_t>>;
|
2013-03-26 16:46:18 +01:00
|
|
|
|
|
2010-10-15 19:05:16 +02:00
|
|
|
|
//! Nonstationary variables and their deflators
|
2013-03-26 16:46:18 +01:00
|
|
|
|
nonstationary_symbols_map_t nonstationary_symbols_map;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
|
2020-04-17 14:55:55 +02:00
|
|
|
|
/* Maps indices of equations in the block-decomposition order into original
|
|
|
|
|
equation IDs */
|
|
|
|
|
vector<int> eq_idx_block2orig;
|
|
|
|
|
/* Maps indices of (endogenous) variables in the block-decomposition order into original
|
|
|
|
|
type-specific endogenous IDs */
|
|
|
|
|
vector<int> endo_idx_block2orig;
|
|
|
|
|
/* Maps original variable and equation indices into the block-decomposition order.
|
|
|
|
|
Set by updateReverseVariableEquationOrderings() */
|
|
|
|
|
vector<int> eq_idx_orig2block, endo_idx_orig2block;
|
2011-06-22 11:56:07 +02:00
|
|
|
|
|
2020-03-17 18:58:34 +01:00
|
|
|
|
//! 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;
|
|
|
|
|
|
2020-04-30 16:00:16 +02:00
|
|
|
|
/* Stores derivatives of each block w.r.t. endogenous that belong to it.
|
2020-04-24 12:29:02 +02:00
|
|
|
|
The tuple is: equation number (inside the block), variable number (inside
|
|
|
|
|
the block), lead/lag */
|
|
|
|
|
vector<map<tuple<int, int, int>, expr_t>> blocks_derivatives;
|
2020-03-17 18:58:34 +01:00
|
|
|
|
|
2020-04-21 18:10:46 +02:00
|
|
|
|
class BlockInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
BlockSimulationType simulation_type;
|
|
|
|
|
int first_equation; // Stores a block-ordered equation ID
|
|
|
|
|
int size{0};
|
|
|
|
|
int mfs_size{0}; // Size of the minimal feedback set
|
|
|
|
|
bool linear{true}; // Whether the block is linear in endogenous variable
|
|
|
|
|
int n_static{0}, n_forward{0}, n_backward{0}, n_mixed{0};
|
2020-04-30 11:15:55 +02:00
|
|
|
|
int max_endo_lag{0}, max_endo_lead{0}; // Maximum lag/lead on endos that appear in and *that belong to* the block
|
|
|
|
|
int max_other_endo_lag{0}, max_other_endo_lead{0}; // Maximum lag/lead on endos that appear in but do not belong to the block
|
|
|
|
|
int max_exo_lag{0}, max_exo_lead{0};
|
|
|
|
|
int max_exo_det_lag{0}, max_exo_det_lead{0};
|
|
|
|
|
int max_lag{0}, max_lead{0}; // The max over all endo/exo variables
|
2020-04-23 16:04:02 +02:00
|
|
|
|
|
|
|
|
|
inline int getRecursiveSize() const { return size - mfs_size; };
|
2020-04-21 18:10:46 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Stores various informations on the blocks
|
|
|
|
|
vector<BlockInfo> blocks;
|
|
|
|
|
|
2020-04-29 16:41:33 +02:00
|
|
|
|
// Maps endogenous type-specific IDs to the block number to which it belongs
|
|
|
|
|
vector<int> endo2block;
|
|
|
|
|
/* Maps (original) equation number to the block number to which it belongs.
|
|
|
|
|
It verifies: ∀i, eq2block[endo2eq[i]] = endo2block[i] */
|
|
|
|
|
vector<int> eq2block;
|
|
|
|
|
|
2020-05-13 16:58:19 +02:00
|
|
|
|
/* Temporary terms for block decomposed models.
|
|
|
|
|
- the outer vector has as many elements as there are blocks in the model
|
|
|
|
|
- the inner vector has as many elements as there are equations in the
|
|
|
|
|
block, plus a last one which contains the temporary terms for
|
|
|
|
|
derivatives
|
|
|
|
|
|
|
|
|
|
It’s necessary to track temporary terms per equation, because some
|
|
|
|
|
equations are evaluated instead of solved, and an equation E1 may depend
|
|
|
|
|
on the value of an endogenous Y computed by a previously evaluated equation
|
|
|
|
|
E2; in this case, if some temporary term TT of equation E2 contains Y,
|
|
|
|
|
then TT needs to be computed after E1, but before E2. */
|
|
|
|
|
vector<vector<temporary_terms_t>> blocks_temporary_terms;
|
2020-05-06 17:13:47 +02:00
|
|
|
|
|
|
|
|
|
/* Stores, for each temporary term in block decomposed models, its index in
|
|
|
|
|
the vector of all temporary terms */
|
|
|
|
|
temporary_terms_idxs_t blocks_temporary_terms_idxs;
|
|
|
|
|
|
2018-11-22 14:32:40 +01:00
|
|
|
|
//! Computes derivatives
|
|
|
|
|
/*! \param order the derivation order
|
|
|
|
|
\param vars the derivation IDs w.r.t. which compute the derivatives */
|
|
|
|
|
void computeDerivatives(int order, const set<int> &vars);
|
2012-11-29 18:07:48 +01:00
|
|
|
|
//! Computes derivatives of the Jacobian and Hessian w.r. to parameters
|
2016-05-18 12:26:19 +02:00
|
|
|
|
void computeParamsDerivatives(int paramsDerivsOrder);
|
2008-02-03 11:28:36 +01:00
|
|
|
|
//! Write derivative of an equation w.r. to a variable
|
2010-09-16 19:00:48 +02:00
|
|
|
|
void writeDerivative(ostream &output, int eq, int symb_id, int lag, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
|
2009-04-20 12:48:54 +02:00
|
|
|
|
//! Computes temporary terms (for all equations and derivatives)
|
2018-09-25 15:56:52 +02:00
|
|
|
|
void computeTemporaryTerms(bool is_matlab, bool no_tmp_terms);
|
2020-05-06 17:13:47 +02:00
|
|
|
|
//! Computes temporary terms per block
|
|
|
|
|
void computeBlockTemporaryTerms();
|
|
|
|
|
/* Add additional temporary terms for a given block. This method is called by
|
|
|
|
|
computeBlockTemporaryTerms(). It does nothing by default, but is meant to
|
|
|
|
|
be overriden by subclasses (actually by DynamicModel, who needs extra
|
|
|
|
|
temporary terms for derivatives w.r.t. exogenous and other endogenous) */
|
|
|
|
|
virtual void additionalBlockTemporaryTerms(int blk,
|
2020-05-13 16:58:19 +02:00
|
|
|
|
vector<vector<temporary_terms_t>> &blocks_temporary_terms,
|
|
|
|
|
map<expr_t, tuple<int, int, int>> &reference_count) const;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
//! Computes temporary terms for the file containing parameters derivatives
|
|
|
|
|
void computeParamsDerivativesTemporaryTerms();
|
2017-06-14 07:01:31 +02:00
|
|
|
|
//! Writes temporary terms
|
2018-11-16 16:53:07 +01:00
|
|
|
|
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;
|
2019-04-18 14:34:48 +02:00
|
|
|
|
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;
|
2010-01-22 11:03:29 +01:00
|
|
|
|
//! Compiles temporary terms
|
2020-05-13 12:53:47 +02:00
|
|
|
|
void compileTemporaryTerms(ostream &code_file, unsigned int &instruction_number, bool dynamic, bool steady_dynamic, temporary_terms_t &temporary_terms_union, const temporary_terms_idxs_t &temporary_terms_idxs) const;
|
2020-05-19 17:43:35 +02:00
|
|
|
|
//! Adds information for (non-block) bytecode simulation in a separate .bin file
|
|
|
|
|
void writeBytecodeBinFile(const string &filename, int &u_count_int, bool &file_open, bool is_two_boundaries) const;
|
2016-12-30 11:26:56 +01:00
|
|
|
|
//! Fixes output when there are more than 32 nested parens, Issue #1201
|
2017-01-05 15:19:13 +01:00
|
|
|
|
void fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const;
|
2016-12-30 11:26:56 +01:00
|
|
|
|
//! Tests if string contains more than 32 nested parens, Issue #1201
|
|
|
|
|
bool testNestedParenthesis(const string &str) const;
|
2018-11-16 16:53:07 +01:00
|
|
|
|
void writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union,
|
2018-11-16 18:13:34 +01:00
|
|
|
|
const temporary_terms_idxs_t &tt_idxs,
|
2018-03-27 17:14:30 +02:00
|
|
|
|
ostream &output, ExprNodeOutputType output_type,
|
|
|
|
|
deriv_node_temp_terms_t &tef_terms) const;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
//! Writes model equations
|
|
|
|
|
void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
|
2018-03-27 17:14:30 +02:00
|
|
|
|
void writeModelEquations(ostream &output, ExprNodeOutputType output_type,
|
2018-05-24 19:29:53 +02:00
|
|
|
|
const temporary_terms_t &temporary_terms) const;
|
2017-02-02 15:09:43 +01:00
|
|
|
|
//! Writes JSON model equations
|
2017-02-20 12:18:11 +01:00
|
|
|
|
//! 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;
|
2020-06-05 16:07:52 +02:00
|
|
|
|
/* Writes JSON model local variables.
|
|
|
|
|
Optionally put the external function variable calls into TEF terms */
|
|
|
|
|
void writeJsonModelLocalVariables(ostream &output, bool write_tef_terms, deriv_node_temp_terms_t &tef_terms) const;
|
2010-01-22 11:03:29 +01:00
|
|
|
|
//! Compiles model equations
|
2020-05-13 12:53:47 +02:00
|
|
|
|
void compileModelEquations(ostream &code_file, unsigned int &instruction_number, bool dynamic, bool steady_dynamic, const temporary_terms_t &temporary_terms_union, const temporary_terms_idxs_t &temporary_terms_idxs) const;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
|
2009-04-30 15:14:33 +02:00
|
|
|
|
//! Writes LaTeX model file
|
2019-12-16 19:42:59 +01:00
|
|
|
|
void writeLatexModelFile(const string &mod_basename, const string &latex_basename, ExprNodeOutputType output_type, bool write_equation_tags) const;
|
2009-04-30 15:14:33 +02:00
|
|
|
|
|
2020-04-28 18:00:26 +02:00
|
|
|
|
//! Sparse matrix of double to store the values of the static Jacobian
|
2009-12-16 14:21:31 +01:00
|
|
|
|
/*! First index is equation number, second index is endogenous type specific ID */
|
2018-06-04 14:31:26 +02:00
|
|
|
|
using jacob_map_t = map<pair<int, int>, double>;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
2020-03-24 16:57:45 +01:00
|
|
|
|
//! Normalization of equations, as computed by computeNonSingularNormalization()
|
2009-12-16 14:21:31 +01:00
|
|
|
|
/*! Maps endogenous type specific IDs to equation numbers */
|
|
|
|
|
vector<int> endo2eq;
|
|
|
|
|
|
2020-04-15 17:56:28 +02:00
|
|
|
|
/* Compute a pseudo-Jacobian whose all elements are either zero or one,
|
|
|
|
|
depending on whether the variable symbolically appears in the equation */
|
|
|
|
|
jacob_map_t computeSymbolicJacobian() const;
|
|
|
|
|
|
2020-04-17 14:55:55 +02:00
|
|
|
|
// Compute {var,eq}_idx_orig2block from {var,eq}_idx_block2orig
|
2020-04-15 17:56:28 +02:00
|
|
|
|
void updateReverseVariableEquationOrderings();
|
|
|
|
|
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Compute the matching between endogenous and variable using the jacobian contemporaneous_jacobian
|
2009-12-21 11:29:21 +01:00
|
|
|
|
/*!
|
|
|
|
|
\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
|
|
|
|
|
*/
|
2010-09-16 19:00:48 +02:00
|
|
|
|
bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose);
|
2009-12-21 11:29:21 +01:00
|
|
|
|
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Try to compute the matching between endogenous and variable using a decreasing cutoff
|
2009-12-21 11:29:21 +01:00
|
|
|
|
/*!
|
|
|
|
|
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.
|
2020-03-24 16:57:45 +01:00
|
|
|
|
If no matching is found with a zero cutoff, an error message is printed.
|
|
|
|
|
The resulting normalization is stored in endo2eq.
|
2009-12-21 11:29:21 +01:00
|
|
|
|
*/
|
2020-05-06 18:09:44 +02:00
|
|
|
|
void computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian);
|
2020-03-20 18:42:59 +01:00
|
|
|
|
//! Evaluate the jacobian (w.r.t. endogenous) and suppress all the elements below the cutoff
|
2020-05-06 18:09:44 +02:00
|
|
|
|
/*! Returns the contemporaneous_jacobian.
|
2020-04-28 18:00:26 +02:00
|
|
|
|
Elements below the cutoff are discarded. External functions are evaluated to 1. */
|
2020-05-06 18:09:44 +02:00
|
|
|
|
jacob_map_t evaluateAndReduceJacobian(const eval_context_t &eval_context) const;
|
2020-04-30 12:48:16 +02:00
|
|
|
|
/* Search the equations and variables belonging to the prologue and the
|
|
|
|
|
epilogue of the model.
|
|
|
|
|
Initializes “eq_idx_block2orig” and “endo_idx_block2orig”.
|
|
|
|
|
Returns the sizes of the prologue and epilogue. */
|
|
|
|
|
pair<int, int> computePrologueAndEpilogue();
|
2020-03-20 18:47:29 +01:00
|
|
|
|
//! Determine the type of each equation of model and try to normalize the unnormalized equation
|
2020-03-20 15:23:23 +01:00
|
|
|
|
void equationTypeDetermination(const map<tuple<int, int, int>, expr_t> &first_order_endo_derivatives, int mfs);
|
2020-04-30 11:15:55 +02:00
|
|
|
|
/* Fills the max lags/leads and n_{static,mixed,forward,backward} fields of a
|
|
|
|
|
given block.
|
|
|
|
|
Needs the fields size and first_equation. */
|
|
|
|
|
void computeDynamicStructureOfBlock(int blk);
|
2020-04-30 12:48:16 +02:00
|
|
|
|
/* Fills the simulation_type field of a given block.
|
|
|
|
|
Needs the fields size, max_endo_lag and max_endo_lead. */
|
|
|
|
|
void computeSimulationTypeOfBlock(int blk);
|
2020-04-21 18:10:46 +02:00
|
|
|
|
/* Compute the block decomposition and for a non-recusive block find the minimum feedback set
|
|
|
|
|
|
2020-04-30 12:48:16 +02:00
|
|
|
|
Initializes the “blocks”, “endo2block” and “eq2block” structures. */
|
|
|
|
|
void computeBlockDecomposition(int prologue, int epilogue);
|
2020-04-21 18:10:46 +02:00
|
|
|
|
/* Reduce the number of block by merging the same type of equations in the
|
2020-04-30 12:48:16 +02:00
|
|
|
|
prologue and the epilogue */
|
|
|
|
|
void reduceBlockDecomposition();
|
2020-04-17 19:21:37 +02:00
|
|
|
|
/* The 1st output gives, for each equation (in original order) the (max_lag,
|
|
|
|
|
max_lead) across all endogenous that appear in the equation and that
|
|
|
|
|
belong to the same block (i.e. those endogenous are solved in the same
|
|
|
|
|
block).
|
|
|
|
|
|
|
|
|
|
The 2nd output gives, for each type-specific endo IDs, its (max_lag,
|
|
|
|
|
max_lead) across all its occurences inside the equations of the block to
|
|
|
|
|
which it belongs. */
|
2020-04-29 16:41:33 +02:00
|
|
|
|
pair<lag_lead_vector_t, lag_lead_vector_t> getVariableLeadLagByBlock() const;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Print an abstract of the block structure of the model
|
2020-04-15 17:56:28 +02:00
|
|
|
|
void printBlockDecomposition() const;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Determine for each block if it is linear or not
|
2020-03-20 15:23:23 +01:00
|
|
|
|
void determineLinearBlocks();
|
2019-11-18 17:13:49 +01:00
|
|
|
|
//! Remove equations specified by exclude_eqs
|
|
|
|
|
vector<int> includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
|
|
|
|
|
vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
|
2020-02-20 15:29:10 +01:00
|
|
|
|
EquationTags &equation_tags, bool static_equations) const;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the type of equation belonging to the block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
EquationType
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationType(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation+eq]].first;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Return true if the equation has been normalized
|
2020-04-17 16:04:19 +02:00
|
|
|
|
bool
|
2020-04-23 16:04:02 +02:00
|
|
|
|
isBlockEquationRenormalized(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-05-20 11:49:32 +02:00
|
|
|
|
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]].first == EquationType::evaluateRenormalized;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the expr_t of equation belonging to the block
|
2020-05-07 15:20:11 +02:00
|
|
|
|
BinaryOpNode *
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationExpr(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return equations[eq_idx_block2orig[blocks[blk].first_equation + eq]];
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the expr_t of renormalized equation belonging to the block
|
2020-05-07 15:20:11 +02:00
|
|
|
|
BinaryOpNode *
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationRenormalizedExpr(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]].second;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the original number of equation belonging to the block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationID(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return eq_idx_block2orig[blocks[blk].first_equation + eq];
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the original number of variable belonging to the block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockVariableID(int blk, int var) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return endo_idx_block2orig[blocks[blk].first_equation + var];
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the position of an equation (given by its original index) inside its block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockInitialEquationID(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return eq_idx_orig2block[eq] - blocks[blk].first_equation;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the position of a variable (given by its original index) inside its block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockInitialVariableID(int blk, int var) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return endo_idx_orig2block[var] - blocks[blk].first_equation;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2011-06-22 11:56:07 +02:00
|
|
|
|
//! Initialize equation_reordered & variable_reordered
|
|
|
|
|
void initializeVariablesAndEquations();
|
2020-03-30 14:51:53 +02:00
|
|
|
|
//! Returns the 1st derivatives w.r.t. endogenous in a different format
|
|
|
|
|
/*! Returns a map (equation, type-specific ID, lag) → derivative.
|
|
|
|
|
Assumes that derivatives have already been computed. */
|
|
|
|
|
map<tuple<int, int, int>, expr_t> collectFirstOrderDerivativesEndogenous();
|
2018-10-09 18:27:19 +02:00
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
//! 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 ModelTree &m);
|
2018-10-26 11:44:26 +02:00
|
|
|
|
//! Returns the name of the MATLAB architecture given the extension used for MEX files
|
|
|
|
|
static string matlab_arch(const string &mexext);
|
2020-05-29 16:12:01 +02:00
|
|
|
|
//! Compiles a MEX file
|
2020-06-23 15:13:04 +02:00
|
|
|
|
void compileMEX(const string &basename, const string &funcname, const string &mexext, const vector<filesystem::path> &src_files, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const;
|
2018-10-09 18:27:19 +02:00
|
|
|
|
|
2008-02-03 11:28:36 +01:00
|
|
|
|
public:
|
2018-08-14 14:23:21 +02:00
|
|
|
|
ModelTree(SymbolTable &symbol_table_arg,
|
|
|
|
|
NumericalConstants &num_constants_arg,
|
2018-10-09 18:27:19 +02:00
|
|
|
|
ExternalFunctionsTable &external_functions_table_arg,
|
|
|
|
|
bool is_dynamic_arg = false);
|
|
|
|
|
|
|
|
|
|
ModelTree(const ModelTree &m);
|
|
|
|
|
ModelTree(ModelTree &&) = delete;
|
2019-12-20 16:59:30 +01:00
|
|
|
|
ModelTree &operator=(const ModelTree &m);
|
|
|
|
|
ModelTree &operator=(ModelTree &&) = delete;
|
2018-10-09 18:27:19 +02:00
|
|
|
|
|
2011-06-22 11:56:07 +02:00
|
|
|
|
//! Absolute value under which a number is considered to be zero
|
2018-10-04 17:18:27 +02:00
|
|
|
|
double cutoff{1e-15};
|
2011-06-22 11:56:07 +02:00
|
|
|
|
//! 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 */
|
2018-10-04 17:18:27 +02:00
|
|
|
|
int mfs{0};
|
2014-01-27 16:41:43 +01:00
|
|
|
|
//! Declare a node as an equation of the model; also give its line number
|
|
|
|
|
void addEquation(expr_t eq, int lineno);
|
2013-04-11 17:07:39 +02:00
|
|
|
|
//! Declare a node as an equation of the model, also giving its tags
|
2020-02-20 15:29:10 +01:00
|
|
|
|
void addEquation(expr_t eq, int lineno, const map<string, string> &eq_tags);
|
2009-09-30 17:10:31 +02:00
|
|
|
|
//! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations
|
2010-09-16 19:18:45 +02:00
|
|
|
|
void addAuxEquation(expr_t eq);
|
2008-10-17 19:21:22 +02:00
|
|
|
|
//! Returns the number of equations in the model
|
2008-02-03 11:28:36 +01:00
|
|
|
|
int equation_number() const;
|
2010-10-15 19:05:16 +02:00
|
|
|
|
//! Adds a trend variable with its growth factor
|
2019-07-05 18:36:10 +02:00
|
|
|
|
void addTrendVariables(const vector<int> &trend_vars, expr_t growth_factor) noexcept(false);
|
2013-03-26 16:46:18 +01:00
|
|
|
|
//! Adds a nonstationary variables with their (common) deflator
|
2019-07-05 18:36:10 +02:00
|
|
|
|
void addNonstationaryVariables(const vector<int> &nonstationary_vars, bool log_deflator, expr_t deflator) noexcept(false);
|
2013-10-29 11:47:59 +01:00
|
|
|
|
//! Is a given variable non-stationary?
|
|
|
|
|
bool isNonstationary(int symb_id) const;
|
2011-06-22 11:56:07 +02:00
|
|
|
|
void set_cutoff_to_zero();
|
2019-01-28 14:57:30 +01:00
|
|
|
|
//! Simplify model equations: if a variable is equal to a constant, replace that variable elsewhere in the model
|
2020-03-27 18:14:17 +01:00
|
|
|
|
/*! Equations with MCP tags are excluded, see dynare#1697 */
|
2019-01-28 14:57:30 +01:00
|
|
|
|
void simplifyEquations();
|
2019-12-03 14:19:32 +01:00
|
|
|
|
/*! Reorder auxiliary variables so that they appear in recursive order in
|
|
|
|
|
set_auxiliary_variables.m and dynamic_set_auxiliary_series.m */
|
|
|
|
|
void reorderAuxiliaryEquations();
|
2020-03-27 18:14:17 +01:00
|
|
|
|
//! Find equations of the form “variable=constant”, excluding equations with “mcp” tag (see dynare#1697)
|
|
|
|
|
void findConstantEquationsWithoutMcpTag(map<VariableNode *, NumConstNode *> &subst_table) const;
|
2019-10-10 15:31:03 +02:00
|
|
|
|
//! Helper for writing the Jacobian elements in MATLAB and C
|
|
|
|
|
/*! Writes either (i+1,j+1) or [i+j*no_eq] */
|
2011-08-19 15:05:57 +02:00
|
|
|
|
void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
|
2019-12-13 17:15:03 +01:00
|
|
|
|
|
|
|
|
|
//! Returns all the equation tags associated to an equation
|
2019-12-20 16:59:30 +01:00
|
|
|
|
inline map<string, string>
|
|
|
|
|
getEquationTags(int eq) const
|
2019-12-13 17:15:03 +01:00
|
|
|
|
{
|
2020-02-20 15:29:10 +01:00
|
|
|
|
return equation_tags.getTagsByEqn(eq);
|
2019-12-13 17:15:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 14:52:29 +02:00
|
|
|
|
//! Returns the vector of non-zero derivative counts
|
|
|
|
|
inline const vector<int> &
|
|
|
|
|
getNNZDerivatives() const
|
|
|
|
|
{
|
|
|
|
|
return NNZDerivatives;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//!Returns the maximum order of computed derivatives
|
|
|
|
|
inline int
|
|
|
|
|
getComputedDerivsOrder() const
|
|
|
|
|
{
|
|
|
|
|
return computed_derivs_order;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-16 19:42:59 +01:00
|
|
|
|
inline static string
|
2020-03-20 17:31:14 +01:00
|
|
|
|
BlockSim(BlockSimulationType type)
|
2009-12-16 18:13:23 +01:00
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::evaluateForward:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "EVALUATE FORWARD ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::evaluateBackward:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "EVALUATE BACKWARD ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveForwardSimple:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE FORWARD SIMPLE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveBackwardSimple:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE BACKWARD SIMPLE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveTwoBoundariesSimple:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE TWO BOUNDARIES SIMPLE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveForwardComplete:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE FORWARD COMPLETE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveBackwardComplete:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE BACKWARD COMPLETE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveTwoBoundariesComplete:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE TWO BOUNDARIES COMPLETE";
|
2009-12-16 18:13:23 +01:00
|
|
|
|
default:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "UNKNOWN ";
|
2009-12-16 18:13:23 +01:00
|
|
|
|
}
|
2020-03-20 18:00:56 +01:00
|
|
|
|
}
|
2021-02-22 18:26:21 +01:00
|
|
|
|
|
|
|
|
|
/* Returns true if at least one equation has a tag associated to occbin
|
|
|
|
|
(bind/relax/pswitch/pcrit) */
|
|
|
|
|
bool hasOccbinTags() const;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|