2008-02-03 11:28:36 +01:00
/*
2021-01-12 17:33:53 +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
*/
# include "ModelTree.hh"
2020-04-09 17:44:17 +02:00
# include "VariableDependencyGraph.hh"
2019-04-23 14:51:14 +02:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast"
2019-09-11 16:24:09 +02:00
# pragma GCC diagnostic ignored "-Wsign-compare"
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
2009-12-16 14:21:31 +01:00
# include <boost/graph/adjacency_list.hpp>
# include <boost/graph/max_cardinality_matching.hpp>
# include <boost/graph/topological_sort.hpp>
2019-04-23 14:51:14 +02:00
# pragma GCC diagnostic pop
2009-12-16 14:21:31 +01:00
2019-11-04 15:50:26 +01:00
# ifdef __APPLE__
2019-12-20 16:59:30 +01:00
# include <mach-o / dyld.h>
2019-11-04 15:50:26 +01:00
# endif
2020-01-07 12:41:27 +01:00
# include <regex>
2020-03-24 16:57:45 +01:00
# include <utility>
2020-01-07 12:41:27 +01:00
2018-10-09 18:27:19 +02:00
void
ModelTree : : copyHelper ( const ModelTree & m )
{
2018-10-10 13:07:25 +02:00
auto f = [ this ] ( expr_t e ) { return e - > clone ( * this ) ; } ;
2018-10-09 18:27:19 +02:00
// Equations
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . equations )
2018-10-09 18:27:19 +02:00
equations . push_back ( dynamic_cast < BinaryOpNode * > ( f ( it ) ) ) ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . aux_equations )
2018-10-09 18:27:19 +02:00
aux_equations . push_back ( dynamic_cast < BinaryOpNode * > ( f ( it ) ) ) ;
2018-11-15 16:39:53 +01:00
auto convert_deriv_map = [ f ] ( map < vector < int > , expr_t > dm )
2019-12-20 16:59:30 +01:00
{
map < vector < int > , expr_t > dm2 ;
for ( const auto & it : dm )
dm2 . emplace ( it . first , f ( it . second ) ) ;
return dm2 ;
} ;
2018-11-15 16:39:53 +01:00
2018-10-09 18:27:19 +02:00
// Derivatives
2018-11-15 16:39:53 +01:00
for ( const auto & it : m . derivatives )
derivatives . push_back ( convert_deriv_map ( it ) ) ;
for ( const auto & it : m . params_derivatives )
params_derivatives [ it . first ] = convert_deriv_map ( it . second ) ;
auto convert_temporary_terms_t = [ f ] ( temporary_terms_t tt )
2019-12-20 16:59:30 +01:00
{
temporary_terms_t tt2 ;
for ( const auto & it : tt )
tt2 . insert ( f ( it ) ) ;
return tt2 ;
} ;
2018-10-09 18:27:19 +02:00
// Temporary terms
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . temporary_terms_mlv )
2020-06-05 17:11:29 +02:00
temporary_terms_mlv [ dynamic_cast < VariableNode * > ( f ( it . first ) ) ] = f ( it . second ) ;
2018-11-15 16:39:53 +01:00
for ( const auto & it : m . temporary_terms_derivatives )
temporary_terms_derivatives . push_back ( convert_temporary_terms_t ( it ) ) ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . temporary_terms_idxs )
2018-10-09 18:27:19 +02:00
temporary_terms_idxs [ f ( it . first ) ] = it . second ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . params_derivs_temporary_terms )
2018-11-16 18:24:06 +01:00
params_derivs_temporary_terms [ it . first ] = convert_temporary_terms_t ( it . second ) ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . params_derivs_temporary_terms_idxs )
2018-10-09 18:27:19 +02:00
params_derivs_temporary_terms_idxs [ f ( it . first ) ] = it . second ;
// Other stuff
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . trend_symbols_map )
2018-10-09 18:27:19 +02:00
trend_symbols_map [ it . first ] = f ( it . second ) ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : m . nonstationary_symbols_map )
2019-02-21 10:30:25 +01:00
nonstationary_symbols_map [ it . first ] = { it . second . first , f ( it . second . second ) } ;
2020-03-17 18:58:34 +01:00
for ( const auto & it : m . equation_type_and_normalized_equation )
2020-05-07 15:20:11 +02:00
equation_type_and_normalized_equation . emplace_back ( it . first , dynamic_cast < BinaryOpNode * > ( f ( it . second ) ) ) ;
2020-03-17 18:58:34 +01:00
for ( const auto & it : m . blocks_derivatives )
{
2020-04-24 12:29:02 +02:00
map < tuple < int , int , int > , expr_t > v ;
2020-03-17 18:58:34 +01:00
for ( const auto & it2 : it )
2020-04-24 12:29:02 +02:00
v [ it2 . first ] = f ( it2 . second ) ;
2020-03-17 18:58:34 +01:00
blocks_derivatives . push_back ( v ) ;
}
2020-05-06 17:13:47 +02:00
2020-05-13 16:58:19 +02:00
auto convert_vector_tt = [ f ] ( vector < temporary_terms_t > vtt )
{
vector < temporary_terms_t > vtt2 ;
for ( const auto & tt : vtt )
{
temporary_terms_t tt2 ;
for ( const auto & it : tt )
tt2 . insert ( f ( it ) ) ;
vtt2 . push_back ( tt2 ) ;
}
return vtt2 ;
} ;
2020-05-06 17:13:47 +02:00
for ( const auto & it : m . blocks_temporary_terms )
2020-05-13 16:58:19 +02:00
blocks_temporary_terms . push_back ( convert_vector_tt ( it ) ) ;
2020-05-06 17:13:47 +02:00
for ( const auto & it : m . blocks_temporary_terms_idxs )
blocks_temporary_terms_idxs [ f ( it . first ) ] = it . second ;
2018-10-09 18:27:19 +02:00
}
2018-11-22 14:36:03 +01:00
ModelTree : : ModelTree ( SymbolTable & symbol_table_arg ,
NumericalConstants & num_constants_arg ,
ExternalFunctionsTable & external_functions_table_arg ,
bool is_dynamic_arg ) :
2019-12-20 16:59:30 +01:00
DataTree { symbol_table_arg , num_constants_arg , external_functions_table_arg , is_dynamic_arg } ,
2018-11-22 14:36:03 +01:00
derivatives ( 4 ) ,
NNZDerivatives ( 4 , 0 ) ,
temporary_terms_derivatives ( 4 )
{
}
2018-10-09 18:27:19 +02:00
ModelTree : : ModelTree ( const ModelTree & m ) :
2019-12-20 16:59:30 +01:00
DataTree { m } ,
user_set_add_flags { m . user_set_add_flags } ,
user_set_subst_flags { m . user_set_subst_flags } ,
user_set_add_libs { m . user_set_add_libs } ,
user_set_subst_libs { m . user_set_subst_libs } ,
user_set_compiler { m . user_set_compiler } ,
equations_lineno { m . equations_lineno } ,
equation_tags { m . equation_tags } ,
2020-01-20 17:22:32 +01:00
computed_derivs_order { m . computed_derivs_order } ,
2019-12-20 16:59:30 +01:00
NNZDerivatives { m . NNZDerivatives } ,
2020-04-17 14:55:55 +02:00
eq_idx_block2orig { m . eq_idx_block2orig } ,
endo_idx_block2orig { m . endo_idx_block2orig } ,
eq_idx_orig2block { m . eq_idx_orig2block } ,
endo_idx_orig2block { m . endo_idx_orig2block } ,
2020-04-21 18:10:46 +02:00
blocks { m . blocks } ,
2020-04-29 16:41:33 +02:00
endo2block { m . endo2block } ,
eq2block { m . eq2block } ,
2019-12-20 16:59:30 +01:00
endo2eq { m . endo2eq } ,
cutoff { m . cutoff } ,
mfs { m . mfs }
2018-10-09 18:27:19 +02:00
{
copyHelper ( m ) ;
}
ModelTree &
ModelTree : : operator = ( const ModelTree & m )
{
DataTree : : operator = ( m ) ;
equations . clear ( ) ;
equations_lineno = m . equations_lineno ;
aux_equations . clear ( ) ;
equation_tags = m . equation_tags ;
2020-01-20 17:22:32 +01:00
computed_derivs_order = m . computed_derivs_order ;
2018-10-09 18:27:19 +02:00
NNZDerivatives = m . NNZDerivatives ;
2018-11-15 16:39:53 +01:00
derivatives . clear ( ) ;
params_derivatives . clear ( ) ;
2018-10-09 18:27:19 +02:00
temporary_terms_mlv . clear ( ) ;
2018-11-15 16:39:53 +01:00
temporary_terms_derivatives . clear ( ) ;
2018-10-09 18:27:19 +02:00
params_derivs_temporary_terms . clear ( ) ;
params_derivs_temporary_terms_idxs . clear ( ) ;
trend_symbols_map . clear ( ) ;
nonstationary_symbols_map . clear ( ) ;
2020-04-17 14:55:55 +02:00
eq_idx_block2orig = m . eq_idx_block2orig ;
endo_idx_block2orig = m . endo_idx_block2orig ;
eq_idx_orig2block = m . eq_idx_orig2block ;
endo_idx_orig2block = m . endo_idx_orig2block ;
2020-03-17 18:58:34 +01:00
equation_type_and_normalized_equation . clear ( ) ;
blocks_derivatives . clear ( ) ;
2020-04-21 18:10:46 +02:00
blocks = m . blocks ;
2020-04-29 16:41:33 +02:00
endo2block = m . endo2block ;
eq2block = m . eq2block ;
2020-05-06 17:13:47 +02:00
blocks_temporary_terms . clear ( ) ;
blocks_temporary_terms_idxs . clear ( ) ;
2018-10-09 18:27:19 +02:00
endo2eq = m . endo2eq ;
cutoff = m . cutoff ;
mfs = m . mfs ;
2019-12-02 19:21:14 +01:00
user_set_add_flags = m . user_set_add_flags ;
user_set_subst_flags = m . user_set_subst_flags ;
user_set_add_libs = m . user_set_add_libs ;
user_set_subst_libs = m . user_set_subst_libs ;
user_set_compiler = m . user_set_compiler ;
2018-10-09 18:27:19 +02:00
copyHelper ( m ) ;
return * this ;
}
2009-12-21 11:29:21 +01:00
bool
2010-09-16 19:00:48 +02:00
ModelTree : : computeNormalization ( const jacob_map_t & contemporaneous_jacobian , bool verbose )
2009-12-16 14:21:31 +01:00
{
2017-02-24 11:20:54 +01:00
const int n = equations . size ( ) ;
2009-12-16 14:21:31 +01:00
assert ( n = = symbol_table . endo_nbr ( ) ) ;
2018-06-05 14:56:34 +02:00
using BipartiteGraph = boost : : adjacency_list < boost : : vecS , boost : : vecS , boost : : undirectedS > ;
2009-12-16 14:21:31 +01:00
/*
Vertices 0 to n - 1 are for endogenous ( using type specific ID )
Vertices n to 2 * n - 1 are for equations ( using equation no . )
*/
BipartiteGraph g ( 2 * n ) ;
// Fill in the graph
2020-03-20 18:42:59 +01:00
for ( const auto & [ eq_and_endo , val ] : contemporaneous_jacobian )
add_edge ( eq_and_endo . first + n , eq_and_endo . second , g ) ;
2009-12-16 14:21:31 +01:00
// Compute maximum cardinality matching
vector < int > mate_map ( 2 * n ) ;
bool check = checked_edmonds_maximum_cardinality_matching ( g , & mate_map [ 0 ] ) ;
assert ( check ) ;
# ifdef DEBUG
2009-12-16 18:13:23 +01:00
for ( int i = 0 ; i < n ; i + + )
2009-12-16 14:21:31 +01:00
cout < < " Endogenous " < < symbol_table . getName ( symbol_table . getID ( eEndogenous , i ) )
< < " matched with equation " < < ( mate_map [ i ] - n + 1 ) < < endl ;
# endif
// Create the resulting map, by copying the n first elements of mate_map, and substracting n to them
2017-02-24 11:20:54 +01:00
endo2eq . resize ( equations . size ( ) ) ;
2018-11-23 17:19:59 +01:00
transform ( mate_map . begin ( ) , mate_map . begin ( ) + n , endo2eq . begin ( ) , [ = ] ( int i ) { return i - n ; } ) ;
2009-12-16 14:21:31 +01:00
// Check if all variables are normalized
2019-12-16 19:42:59 +01:00
if ( auto it = find ( mate_map . begin ( ) , mate_map . begin ( ) + n , boost : : graph_traits < BipartiteGraph > : : null_vertex ( ) ) ;
it ! = mate_map . begin ( ) + n )
2009-12-21 11:29:21 +01:00
{
if ( verbose )
cerr < < " ERROR: Could not normalize the model. Variable "
2018-07-17 18:34:07 +02:00
< < symbol_table . getName ( symbol_table . getID ( SymbolType : : endogenous , it - mate_map . begin ( ) ) )
2009-12-21 11:29:21 +01:00
< < " is not in the maximum cardinality matching. " < < endl ;
check = false ;
}
return check ;
2009-12-16 14:21:31 +01:00
}
void
2020-05-06 18:09:44 +02:00
ModelTree : : computeNonSingularNormalization ( const jacob_map_t & contemporaneous_jacobian )
2009-12-16 14:21:31 +01:00
{
cout < < " Normalizing the model... " < < endl ;
2017-02-24 11:20:54 +01:00
int n = equations . size ( ) ;
2009-12-16 14:21:31 +01:00
2020-03-20 18:42:59 +01:00
// Compute the maximum value of each row of the contemporaneous Jacobian matrix
2009-12-21 11:29:21 +01:00
vector < double > max_val ( n , 0.0 ) ;
2020-03-20 18:42:59 +01:00
for ( const auto & [ eq_and_endo , val ] : contemporaneous_jacobian )
max_val [ eq_and_endo . first ] = max ( max_val [ eq_and_endo . first ] , fabs ( val ) ) ;
2009-12-16 14:21:31 +01:00
2020-03-24 16:57:45 +01:00
// Compute normalized contemporaneous Jacobian
jacob_map_t normalized_contemporaneous_jacobian ( contemporaneous_jacobian ) ;
2020-03-20 18:42:59 +01:00
for ( auto & [ eq_and_endo , val ] : normalized_contemporaneous_jacobian )
val / = max_val [ eq_and_endo . first ] ;
2009-12-21 11:29:21 +01:00
2020-03-20 18:42:59 +01:00
// We start with the highest value of the cutoff and try to normalize the model
2009-12-21 11:29:21 +01:00
double current_cutoff = 0.99999999 ;
2020-03-20 18:42:59 +01:00
const double cutoff_lower_limit = 1e-19 ;
2009-12-21 11:29:21 +01:00
2020-03-24 16:57:45 +01:00
bool found_normalization = false ;
int last_suppressed = 0 ;
while ( ! found_normalization & & current_cutoff > cutoff_lower_limit )
2009-12-16 14:21:31 +01:00
{
2020-03-24 16:57:45 +01:00
// Drop elements below cutoff from normalized contemporaneous Jacobian
jacob_map_t normalized_contemporaneous_jacobian_above_cutoff ;
int suppressed = 0 ;
for ( const auto & [ eq_and_endo , val ] : normalized_contemporaneous_jacobian )
2020-03-20 18:42:59 +01:00
if ( fabs ( val ) > max ( current_cutoff , cutoff ) )
2020-03-24 16:57:45 +01:00
normalized_contemporaneous_jacobian_above_cutoff [ eq_and_endo ] = val ;
2009-12-21 11:29:21 +01:00
else
2020-03-24 16:57:45 +01:00
suppressed + + ;
2009-12-21 11:29:21 +01:00
2020-03-24 16:57:45 +01:00
if ( suppressed ! = last_suppressed )
found_normalization = computeNormalization ( normalized_contemporaneous_jacobian_above_cutoff , false ) ;
last_suppressed = suppressed ;
if ( ! found_normalization )
2009-12-16 14:21:31 +01:00
{
2009-12-21 11:29:21 +01:00
current_cutoff / = 2 ;
// In this last case try to normalize with the complete jacobian
2020-03-20 18:42:59 +01:00
if ( current_cutoff < = cutoff_lower_limit )
2020-03-24 16:57:45 +01:00
found_normalization = computeNormalization ( normalized_contemporaneous_jacobian , false ) ;
2009-12-16 14:21:31 +01:00
}
}
2020-03-24 16:57:45 +01:00
if ( ! found_normalization )
2009-12-16 14:21:31 +01:00
{
2009-12-21 11:29:21 +01:00
cout < < " Normalization failed with cutoff, trying symbolic normalization... " < < endl ;
2020-03-24 16:57:45 +01:00
/* If no non-singular normalization can be found, try to find a
normalization even with a potential singularity .
TODO : Explain why symbolic_jacobian is not contemporaneous . */
2020-04-15 17:56:28 +02:00
auto symbolic_jacobian = computeSymbolicJacobian ( ) ;
2020-03-24 16:57:45 +01:00
found_normalization = computeNormalization ( symbolic_jacobian , true ) ;
2009-12-16 14:21:31 +01:00
}
2009-12-21 11:29:21 +01:00
2020-03-24 16:57:45 +01:00
if ( ! found_normalization )
2009-12-21 11:29:21 +01:00
{
cerr < < " No normalization could be computed. Aborting. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2009-12-16 14:21:31 +01:00
}
2020-05-06 18:09:44 +02:00
ModelTree : : jacob_map_t
ModelTree : : evaluateAndReduceJacobian ( const eval_context_t & eval_context ) const
2009-12-16 14:21:31 +01:00
{
2020-05-06 18:09:44 +02:00
jacob_map_t contemporaneous_jacobian ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d1 ] : derivatives [ 1 ] )
2009-12-16 14:21:31 +01:00
{
2019-12-16 19:42:59 +01:00
int deriv_id = indices [ 1 ] ;
2018-07-17 18:34:07 +02:00
if ( getTypeByDerivID ( deriv_id ) = = SymbolType : : endogenous )
2009-12-16 14:21:31 +01:00
{
2019-12-16 19:42:59 +01:00
int eq = indices [ 0 ] ;
2009-12-16 14:21:31 +01:00
int symb = getSymbIDByDerivID ( deriv_id ) ;
int var = symbol_table . getTypeSpecificID ( symb ) ;
int lag = getLagByDerivID ( deriv_id ) ;
double val = 0 ;
try
{
2019-12-16 19:42:59 +01:00
val = d1 - > eval ( eval_context ) ;
2009-12-16 14:21:31 +01:00
}
2010-12-10 11:50:27 +01:00
catch ( ExprNode : : EvalExternalFunctionException & e )
{
val = 1 ;
}
2009-12-16 14:21:31 +01:00
catch ( ExprNode : : EvalException & e )
{
2014-01-27 16:41:43 +01:00
cerr < < " ERROR: evaluation of Jacobian failed for equation " < < eq + 1 < < " (line " < < equations_lineno [ eq ] < < " ) and variable " < < symbol_table . getName ( symb ) < < " ( " < < lag < < " ) [ " < < symb < < " ] ! " < < endl ;
2020-06-17 16:49:12 +02:00
d1 - > writeOutput ( cerr , ExprNodeOutputType : : matlabDynamicModel , { } , { } ) ;
2009-12-16 14:21:31 +01:00
cerr < < endl ;
exit ( EXIT_FAILURE ) ;
}
2020-05-07 16:51:49 +02:00
if ( ( isnan ( val ) | | fabs ( val ) > = cutoff ) & & lag = = 0 )
2020-05-06 18:09:44 +02:00
contemporaneous_jacobian [ { eq , var } ] = val ;
2009-12-16 14:21:31 +01:00
}
}
2020-05-06 18:09:44 +02:00
return contemporaneous_jacobian ;
2009-12-16 14:21:31 +01:00
}
2020-04-30 12:48:16 +02:00
pair < int , int >
2020-04-28 18:00:26 +02:00
ModelTree : : computePrologueAndEpilogue ( )
2009-12-16 14:21:31 +01:00
{
2020-03-24 16:57:45 +01:00
const int n = equations . size ( ) ;
2020-04-17 19:21:37 +02:00
/* Initialize “eq_idx_block2orig” and “endo_idx_block2orig” to the identity
2020-03-24 16:57:45 +01:00
permutation . */
2020-04-17 14:55:55 +02:00
eq_idx_block2orig . resize ( n ) ;
endo_idx_block2orig . resize ( n ) ;
2020-03-24 16:57:45 +01:00
for ( int i = 0 ; i < n ; i + + )
2009-12-16 14:21:31 +01:00
{
2020-04-17 14:55:55 +02:00
eq_idx_block2orig [ i ] = i ;
2020-04-17 19:21:37 +02:00
endo_idx_block2orig [ endo2eq [ i ] ] = i ;
2017-06-14 07:01:31 +02:00
}
2020-03-24 16:57:45 +01:00
/* Compute incidence matrix, equations in rows, variables in columns. Row
( resp . column ) indices are to be interpreted according to
2020-04-17 14:55:55 +02:00
“ eq_idx_block2orig ” ( resp . “ endo_idx_block2orig ” ) . Stored in row - major
2020-03-24 16:57:45 +01:00
order . */
vector < bool > IM ( n * n , false ) ;
2020-04-28 18:00:26 +02:00
for ( int i = 0 ; i < n ; i + + )
{
set < pair < int , int > > endos_and_lags ;
equations [ i ] - > collectEndogenous ( endos_and_lags ) ;
for ( auto [ endo , lag ] : endos_and_lags )
IM [ i * n + endo2eq [ endo ] ] = true ;
}
2020-03-24 16:57:45 +01:00
bool something_has_been_done ;
2009-12-16 14:21:31 +01:00
// Find the prologue equations and place first the AR(1) shock equations first
2020-04-30 12:48:16 +02:00
int prologue = 0 ;
2020-03-24 16:57:45 +01:00
do
2009-12-16 14:21:31 +01:00
{
something_has_been_done = false ;
2020-03-24 16:57:45 +01:00
int new_prologue = prologue ;
2009-12-16 18:13:23 +01:00
for ( int i = prologue ; i < n ; i + + )
2009-12-16 14:21:31 +01:00
{
int nze = 0 ;
2020-03-24 16:57:45 +01:00
int k = 0 ;
for ( int j = new_prologue ; j < n ; j + + )
2009-12-16 18:13:23 +01:00
if ( IM [ i * n + j ] )
2009-12-16 14:21:31 +01:00
{
2009-12-16 18:13:23 +01:00
nze + + ;
2009-12-16 14:21:31 +01:00
k = j ;
}
2009-12-16 18:13:23 +01:00
if ( nze = = 1 )
2009-12-16 14:21:31 +01:00
{
2020-03-24 16:57:45 +01:00
// Swap equations indexed by “new_prologue” and i
2009-12-16 18:13:23 +01:00
for ( int j = 0 ; j < n ; j + + )
2020-03-24 16:57:45 +01:00
swap ( IM [ new_prologue * n + j ] , IM [ i * n + j ] ) ;
2020-04-17 14:55:55 +02:00
swap ( eq_idx_block2orig [ new_prologue ] , eq_idx_block2orig [ i ] ) ;
2020-03-24 16:57:45 +01:00
// Swap variables indexed by “new_prologue” and k (in the matching)
2009-12-16 18:13:23 +01:00
for ( int j = 0 ; j < n ; j + + )
2020-03-24 16:57:45 +01:00
swap ( IM [ j * n + new_prologue ] , IM [ j * n + k ] ) ;
2020-04-17 14:55:55 +02:00
swap ( endo_idx_block2orig [ new_prologue ] , endo_idx_block2orig [ k ] ) ;
2020-03-24 16:57:45 +01:00
new_prologue + + ;
2009-12-16 14:21:31 +01:00
something_has_been_done = true ;
}
}
2020-03-24 16:57:45 +01:00
prologue = new_prologue ;
2009-12-16 14:21:31 +01:00
}
2020-03-24 16:57:45 +01:00
while ( something_has_been_done ) ;
2009-12-16 14:21:31 +01:00
// Find the epilogue equations
2020-04-30 12:48:16 +02:00
int epilogue = 0 ;
2020-03-24 16:57:45 +01:00
do
2009-12-16 14:21:31 +01:00
{
something_has_been_done = false ;
2020-03-24 16:57:45 +01:00
int new_epilogue = epilogue ;
2020-03-24 18:26:06 +01:00
for ( int i = prologue ; i < n - epilogue ; i + + )
2009-12-16 14:21:31 +01:00
{
int nze = 0 ;
2020-03-24 16:57:45 +01:00
int k = 0 ;
for ( int j = prologue ; j < n - new_epilogue ; j + + )
2009-12-16 18:13:23 +01:00
if ( IM [ j * n + i ] )
2009-12-16 14:21:31 +01:00
{
2009-12-16 18:13:23 +01:00
nze + + ;
2009-12-16 14:21:31 +01:00
k = j ;
}
2009-12-16 18:13:23 +01:00
if ( nze = = 1 )
2009-12-16 14:21:31 +01:00
{
2009-12-16 18:13:23 +01:00
for ( int j = 0 ; j < n ; j + + )
2020-03-24 16:57:45 +01:00
swap ( IM [ ( n - 1 - new_epilogue ) * n + j ] , IM [ k * n + j ] ) ;
2020-04-17 14:55:55 +02:00
swap ( eq_idx_block2orig [ n - 1 - new_epilogue ] , eq_idx_block2orig [ k ] ) ;
2020-03-24 16:57:45 +01:00
2009-12-16 18:13:23 +01:00
for ( int j = 0 ; j < n ; j + + )
2020-03-24 16:57:45 +01:00
swap ( IM [ j * n + n - 1 - new_epilogue ] , IM [ j * n + i ] ) ;
2020-04-17 14:55:55 +02:00
swap ( endo_idx_block2orig [ n - 1 - new_epilogue ] , endo_idx_block2orig [ i ] ) ;
2020-03-24 16:57:45 +01:00
new_epilogue + + ;
2009-12-16 14:21:31 +01:00
something_has_been_done = true ;
}
}
2020-03-24 16:57:45 +01:00
epilogue = new_epilogue ;
2009-12-16 14:21:31 +01:00
}
2020-03-24 16:57:45 +01:00
while ( something_has_been_done ) ;
2020-04-15 17:56:28 +02:00
updateReverseVariableEquationOrderings ( ) ;
2020-04-30 12:48:16 +02:00
return { prologue , epilogue } ;
2009-12-16 14:21:31 +01:00
}
2020-03-20 15:23:23 +01:00
void
ModelTree : : equationTypeDetermination ( const map < tuple < int , int , int > , expr_t > & first_order_endo_derivatives , int mfs )
2009-12-16 14:21:31 +01:00
{
2020-03-20 15:23:23 +01:00
equation_type_and_normalized_equation . clear ( ) ;
equation_type_and_normalized_equation . resize ( equations . size ( ) ) ;
2020-03-24 18:26:06 +01:00
for ( int i = 0 ; i < static_cast < int > ( equations . size ( ) ) ; i + + )
2009-12-16 14:21:31 +01:00
{
2020-04-17 14:55:55 +02:00
int eq = eq_idx_block2orig [ i ] ;
int var = endo_idx_block2orig [ i ] ;
2020-03-30 17:06:48 +02:00
expr_t lhs = equations [ eq ] - > arg1 ;
EquationType Equation_Simulation_Type = EquationType : : solve ;
2020-04-02 14:36:26 +02:00
BinaryOpNode * normalized_eq = nullptr ;
2020-03-30 17:06:48 +02:00
if ( auto it = first_order_endo_derivatives . find ( { eq , var , 0 } ) ;
it ! = first_order_endo_derivatives . end ( ) )
2009-12-16 14:21:31 +01:00
{
2020-03-30 17:06:48 +02:00
expr_t derivative = it - > second ;
// Determine whether the equation can be evaluated rather than solved
2020-04-17 14:55:55 +02:00
if ( lhs - > isVariableNodeEqualTo ( SymbolType : : endogenous , endo_idx_block2orig [ i ] , 0 )
2020-03-30 17:06:48 +02:00
& & derivative - > isNumConstNodeEqualTo ( 1 ) )
2020-03-20 18:00:56 +01:00
Equation_Simulation_Type = EquationType : : evaluate ;
2009-12-16 14:21:31 +01:00
else
{
2020-03-30 17:06:48 +02:00
set < pair < int , int > > result ;
derivative - > collectEndogenous ( result ) ;
bool variable_not_in_derivative = result . find ( { var , 0 } ) = = result . end ( ) ;
2020-04-02 14:36:26 +02:00
try
{
normalized_eq = equations [ eq ] - > normalizeEquation ( symbol_table . getID ( SymbolType : : endogenous , var ) , 0 ) ;
if ( ( mfs = = 2 & & variable_not_in_derivative ) | | mfs = = 3 )
2020-05-20 11:49:32 +02:00
Equation_Simulation_Type = EquationType : : evaluateRenormalized ;
2020-04-02 14:36:26 +02:00
}
catch ( ExprNode : : NormalizationFailed & e )
{
}
2009-12-16 14:21:31 +01:00
}
}
2020-04-02 14:36:26 +02:00
equation_type_and_normalized_equation [ eq ] = { Equation_Simulation_Type , normalized_eq } ;
2009-12-16 14:21:31 +01:00
}
}
2020-04-30 11:15:55 +02:00
void
ModelTree : : computeDynamicStructureOfBlock ( int blk )
{
vector < pair < int , int > > max_endo_lag_lead ( blocks [ blk ] . size , { 0 , 0 } ) ;
blocks [ blk ] . max_endo_lag = blocks [ blk ] . max_endo_lead = 0 ;
blocks [ blk ] . max_other_endo_lag = blocks [ blk ] . max_other_endo_lead = 0 ;
blocks [ blk ] . max_exo_lag = blocks [ blk ] . max_exo_lead = 0 ;
blocks [ blk ] . max_exo_det_lag = blocks [ blk ] . max_exo_det_lead = 0 ;
for ( int eq = 0 ; eq < blocks [ blk ] . size ; eq + + )
{
set < pair < int , int > > endos_and_lags ;
expr_t e = getBlockEquationExpr ( blk , eq ) ;
/* Compute max lags/leads for endogenous. Also fill per-variable structure
for endos belonging to this block */
e - > collectEndogenous ( endos_and_lags ) ;
for ( auto [ endo , lag ] : endos_and_lags )
if ( endo2block [ endo ] = = blk )
{
blocks [ blk ] . max_endo_lag = max ( blocks [ blk ] . max_endo_lag , - lag ) ;
blocks [ blk ] . max_endo_lead = max ( blocks [ blk ] . max_endo_lead , lag ) ;
auto & [ max_endo_lag , max_endo_lead ] = max_endo_lag_lead [ getBlockInitialVariableID ( blk , endo ) ] ;
max_endo_lag = max ( max_endo_lag , - lag ) ;
max_endo_lead = max ( max_endo_lead , lag ) ;
}
else
{
blocks [ blk ] . max_other_endo_lag = max ( blocks [ blk ] . max_other_endo_lag , - lag ) ;
blocks [ blk ] . max_other_endo_lead = max ( blocks [ blk ] . max_other_endo_lead , lag ) ;
}
// Compute max lags/leads for exogenous
blocks [ blk ] . max_exo_lag = max ( e - > maxExoLag ( ) , blocks [ blk ] . max_exo_lag ) ;
blocks [ blk ] . max_exo_lead = max ( e - > maxExoLead ( ) , blocks [ blk ] . max_exo_lead ) ;
// Compute max lags/leads for deterministic exogenous
set < pair < int , int > > dynvars ;
e - > collectDynamicVariables ( SymbolType : : exogenousDet , dynvars ) ;
for ( auto [ symb_id , lag ] : dynvars )
{
blocks [ blk ] . max_exo_det_lag = max ( - lag , blocks [ blk ] . max_exo_det_lag ) ;
blocks [ blk ] . max_exo_det_lead = max ( lag , blocks [ blk ] . max_exo_det_lead ) ;
}
}
// Compute max lags/leads over all variables
blocks [ blk ] . max_lag = max ( blocks [ blk ] . max_endo_lag , max ( blocks [ blk ] . max_other_endo_lag ,
max ( blocks [ blk ] . max_exo_lag ,
blocks [ blk ] . max_exo_det_lag ) ) ) ;
blocks [ blk ] . max_lead = max ( blocks [ blk ] . max_endo_lead , max ( blocks [ blk ] . max_other_endo_lead ,
max ( blocks [ blk ] . max_exo_lead ,
blocks [ blk ] . max_exo_det_lead ) ) ) ;
// Categorize endos that belong to the block
blocks [ blk ] . n_mixed = blocks [ blk ] . n_forward = blocks [ blk ] . n_backward = blocks [ blk ] . n_static = 0 ;
for ( int var = 0 ; var < blocks [ blk ] . size ; var + + )
{
auto [ max_lag , max_lead ] = max_endo_lag_lead [ var ] ;
if ( max_lag ! = 0 & & max_lead ! = 0 )
blocks [ blk ] . n_mixed + + ;
else if ( max_lag = = 0 & & max_lead ! = 0 )
blocks [ blk ] . n_forward + + ;
else if ( max_lag ! = 0 & & max_lead = = 0 )
blocks [ blk ] . n_backward + + ;
else
blocks [ blk ] . n_static + + ;
}
}
2020-04-30 12:48:16 +02:00
void
ModelTree : : computeSimulationTypeOfBlock ( int blk )
{
auto & type = blocks [ blk ] . simulation_type ;
if ( blocks [ blk ] . max_endo_lag > 0 & & blocks [ blk ] . max_endo_lead > 0 )
{
if ( blocks [ blk ] . size = = 1 )
type = BlockSimulationType : : solveTwoBoundariesSimple ;
else
type = BlockSimulationType : : solveTwoBoundariesComplete ;
}
else if ( blocks [ blk ] . size > 1 )
{
if ( blocks [ blk ] . max_endo_lead > 0 )
type = BlockSimulationType : : solveBackwardComplete ;
else
type = BlockSimulationType : : solveForwardComplete ;
}
else
{
bool can_eval = ( getBlockEquationType ( blk , 0 ) = = EquationType : : evaluate
2020-05-20 11:49:32 +02:00
| | getBlockEquationType ( blk , 0 ) = = EquationType : : evaluateRenormalized ) ;
2020-04-30 12:48:16 +02:00
if ( blocks [ blk ] . max_endo_lead > 0 )
type = can_eval ? BlockSimulationType : : evaluateBackward :
BlockSimulationType : : solveBackwardSimple ;
else
type = can_eval ? BlockSimulationType : : evaluateForward :
BlockSimulationType : : solveForwardSimple ;
}
}
2020-03-19 17:46:10 +01:00
pair < lag_lead_vector_t , lag_lead_vector_t >
2020-04-29 16:41:33 +02:00
ModelTree : : getVariableLeadLagByBlock ( ) const
2009-12-16 14:21:31 +01:00
{
int nb_endo = symbol_table . endo_nbr ( ) ;
2020-04-17 19:21:37 +02:00
lag_lead_vector_t variable_lag_lead ( nb_endo , { 0 , 0 } ) , equation_lag_lead ( nb_endo , { 0 , 0 } ) ;
2020-04-28 18:00:26 +02:00
for ( int eq = 0 ; eq < nb_endo ; eq + + )
2009-12-16 14:21:31 +01:00
{
2020-04-28 18:00:26 +02:00
set < pair < int , int > > endos_and_lags ;
equations [ eq ] - > collectEndogenous ( endos_and_lags ) ;
for ( auto [ endo , lag ] : endos_and_lags )
2020-04-29 16:41:33 +02:00
if ( endo2block [ endo ] = = eq2block [ eq ] )
2020-04-28 18:00:26 +02:00
{
variable_lag_lead [ endo ] . first = max ( variable_lag_lead [ endo ] . first , - lag ) ;
variable_lag_lead [ endo ] . second = max ( variable_lag_lead [ endo ] . second , lag ) ;
equation_lag_lead [ eq ] . first = max ( equation_lag_lead [ eq ] . first , - lag ) ;
equation_lag_lead [ eq ] . second = max ( equation_lag_lead [ eq ] . second , lag ) ;
}
2009-12-16 14:21:31 +01:00
}
2020-04-17 19:21:37 +02:00
return { equation_lag_lead , variable_lag_lead } ;
2009-12-16 14:21:31 +01:00
}
2020-04-29 17:44:57 +02:00
void
2020-04-30 12:48:16 +02:00
ModelTree : : computeBlockDecomposition ( int prologue , int epilogue )
2009-12-16 14:21:31 +01:00
{
2020-04-17 19:21:37 +02:00
int nb_var = symbol_table . endo_nbr ( ) ;
int nb_simvars = nb_var - prologue - epilogue ;
2009-12-16 14:21:31 +01:00
2020-04-09 17:44:17 +02:00
/* Construct the graph representing the dependencies between all
2020-04-15 17:56:28 +02:00
variables that do not belong to the prologue or the epilogue .
2009-12-16 14:21:31 +01:00
2020-04-28 18:00:26 +02:00
For detecting dependencies between variables , use the symbolic adjacency
2020-04-15 17:56:28 +02:00
matrix */
2020-04-17 19:21:37 +02:00
VariableDependencyGraph G ( nb_simvars ) ;
2020-04-28 18:00:26 +02:00
for ( const auto & [ key , value ] : computeSymbolicJacobian ( ) )
2009-12-16 14:21:31 +01:00
{
2020-04-15 17:56:28 +02:00
auto [ eq , endo ] = key ;
2020-04-17 14:55:55 +02:00
if ( eq_idx_orig2block [ eq ] > = prologue
& & eq_idx_orig2block [ eq ] < nb_var - epilogue
& & endo_idx_orig2block [ endo ] > = prologue
& & endo_idx_orig2block [ endo ] < nb_var - epilogue
2020-04-15 17:56:28 +02:00
& & eq ! = endo2eq [ endo ] )
2020-04-17 14:55:55 +02:00
add_edge ( vertex ( eq_idx_orig2block [ endo2eq [ endo ] ] - prologue , G ) ,
vertex ( eq_idx_orig2block [ eq ] - prologue , G ) , G ) ;
2017-06-14 07:01:31 +02:00
}
2020-04-09 17:44:17 +02:00
2020-04-15 17:56:28 +02:00
/* Identify the simultaneous blocks. Each simultaneous block is given an
index , starting from 0 , in recursive order */
2020-04-29 18:48:42 +02:00
auto [ num_simblocks , simvar2simblock ] = G . sortedStronglyConnectedComponents ( ) ;
2020-04-15 17:56:28 +02:00
2020-04-21 18:10:46 +02:00
int num_blocks = prologue + num_simblocks + epilogue ;
blocks . clear ( ) ;
blocks . resize ( num_blocks ) ;
2020-04-29 16:41:33 +02:00
endo2block . resize ( nb_var ) ;
eq2block . resize ( nb_var ) ;
2020-04-21 18:10:46 +02:00
2020-04-29 16:41:33 +02:00
// Initialize size and mfs_size for prologue and epilogue, plus eq/endo→block mappings
2020-04-29 18:48:42 +02:00
for ( int blk = 0 ; blk < num_blocks ; blk + + )
if ( blk < prologue | | blk > = num_blocks - epilogue )
{
int var_eq = ( blk < prologue ? blk : blk - num_simblocks + nb_simvars ) ;
blocks [ blk ] . size = 1 ;
blocks [ blk ] . mfs_size = 1 ;
blocks [ blk ] . first_equation = var_eq ;
endo2block [ endo_idx_block2orig [ var_eq ] ] = blk ;
eq2block [ eq_idx_block2orig [ var_eq ] ] = blk ;
}
2020-04-15 17:56:28 +02:00
2020-04-29 18:48:42 +02:00
// Initialize size for simultaneous blocks, plus eq/endo→block mappings
vector < vector < int > > simblock2simvars ( num_simblocks ) ;
for ( int i = 0 ; i < static_cast < int > ( simvar2simblock . size ( ) ) ; i + + )
2009-12-16 14:21:31 +01:00
{
2020-04-29 18:48:42 +02:00
simblock2simvars [ simvar2simblock [ i ] ] . push_back ( i ) ;
int blk = prologue + simvar2simblock [ i ] ;
2020-04-29 16:41:33 +02:00
blocks [ blk ] . size + + ;
endo2block [ endo_idx_block2orig [ prologue + i ] ] = blk ;
eq2block [ eq_idx_block2orig [ prologue + i ] ] = blk ;
2009-12-16 14:21:31 +01:00
}
2020-04-24 11:36:05 +02:00
// Determine the dynamic structure of each block
2020-04-29 16:41:33 +02:00
auto [ equation_lag_lead , variable_lag_lead ] = getVariableLeadLagByBlock ( ) ;
2009-12-16 14:21:31 +01:00
2020-04-24 11:36:05 +02:00
/* For each simultaneous block, the minimum set of feedback variable is computed.
Then , the variables within the blocks are reordered so that recursive
( non - feedback ) appear first , to get a sub - recursive block without feedback variables .
Within each of the two sub - blocks , variables are reordered depending
on their dynamic status : static first , then backward , mixed and forward . */
/* First, add a loop on vertices which could not be normalized or vertices
related to lead / lag variables . This forces those vertices to belong to the
feedback set */
2020-04-17 19:21:37 +02:00
for ( int i = 0 ; i < nb_simvars ; i + + )
2020-04-21 18:10:46 +02:00
if ( equation_type_and_normalized_equation [ eq_idx_block2orig [ i + prologue ] ] . first = = EquationType : : solve
2020-04-17 19:21:37 +02:00
| | variable_lag_lead [ endo_idx_block2orig [ i + prologue ] ] . first > 0
| | variable_lag_lead [ endo_idx_block2orig [ i + prologue ] ] . second > 0
| | equation_lag_lead [ eq_idx_block2orig [ i + prologue ] ] . first > 0
| | equation_lag_lead [ eq_idx_block2orig [ i + prologue ] ] . second > 0
| | mfs = = 0 )
add_edge ( vertex ( i , G ) , vertex ( i , G ) , G ) ;
2019-12-16 19:42:59 +01:00
2020-04-17 14:55:55 +02:00
const vector < int > old_eq_idx_block2orig ( eq_idx_block2orig ) , old_endo_idx_block2orig ( endo_idx_block2orig ) ;
2020-04-15 17:56:28 +02:00
int ordidx = prologue ;
2020-04-29 18:48:42 +02:00
for ( int blk = prologue ; blk < prologue + num_simblocks ; blk + + )
2009-12-16 14:21:31 +01:00
{
2020-04-29 18:48:42 +02:00
blocks [ blk ] . first_equation = ( blk = = 0 ? 0 : blocks [ blk - 1 ] . first_equation + blocks [ blk - 1 ] . size ) ;
auto subG = G . extractSubgraph ( simblock2simvars [ blk - prologue ] ) ;
2020-04-17 19:21:37 +02:00
auto feed_back_vertices = subG . minimalSetOfFeedbackVertices ( ) ;
2020-04-29 18:48:42 +02:00
blocks [ blk ] . mfs_size = feed_back_vertices . size ( ) ;
2020-04-29 18:46:15 +02:00
auto recursive_vertices = subG . reorderRecursiveVariables ( feed_back_vertices ) ;
auto v_index1 = get ( boost : : vertex_index1 , subG ) ;
2009-12-16 14:21:31 +01:00
2020-04-24 11:36:05 +02:00
const vector < pair < int , int > > dynamic_order { make_pair ( 0 , 0 ) , make_pair ( 1 , 0 ) ,
make_pair ( 1 , 1 ) , make_pair ( 0 , 1 ) } ;
// First the recursive equations conditional on feedback variables
for ( auto max_lag_lead : dynamic_order )
2020-04-29 18:46:15 +02:00
for ( int vtx : recursive_vertices )
if ( int simvar = v_index1 [ vertex ( vtx , subG ) ] ;
variable_lag_lead [ old_endo_idx_block2orig [ simvar + prologue ] ] = = max_lag_lead )
{
eq_idx_block2orig [ ordidx ] = old_eq_idx_block2orig [ simvar + prologue ] ;
endo_idx_block2orig [ ordidx ] = old_endo_idx_block2orig [ simvar + prologue ] ;
ordidx + + ;
}
2019-12-16 19:42:59 +01:00
2020-04-24 11:36:05 +02:00
// Then the equations related to the feedback variables
for ( auto max_lag_lead : dynamic_order )
2020-04-29 18:46:15 +02:00
for ( int vtx : feed_back_vertices )
if ( int simvar = v_index1 [ vertex ( vtx , subG ) ] ;
variable_lag_lead [ old_endo_idx_block2orig [ simvar + prologue ] ] = = max_lag_lead )
2020-04-24 11:36:05 +02:00
{
2020-04-29 18:46:15 +02:00
eq_idx_block2orig [ ordidx ] = old_eq_idx_block2orig [ simvar + prologue ] ;
endo_idx_block2orig [ ordidx ] = old_endo_idx_block2orig [ simvar + prologue ] ;
2020-04-24 11:36:05 +02:00
ordidx + + ;
}
2009-12-16 14:21:31 +01:00
}
2020-03-19 17:46:10 +01:00
2020-04-15 17:56:28 +02:00
updateReverseVariableEquationOrderings ( ) ;
2020-04-30 11:15:55 +02:00
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
2020-04-30 12:48:16 +02:00
{
computeDynamicStructureOfBlock ( blk ) ;
computeSimulationTypeOfBlock ( blk ) ;
}
2009-12-16 14:21:31 +01:00
}
2009-12-16 18:13:23 +01:00
void
2020-04-15 17:56:28 +02:00
ModelTree : : printBlockDecomposition ( ) const
2009-12-16 14:21:31 +01:00
{
2020-04-21 23:06:51 +02:00
int largest_block = 0 , Nb_SimulBlocks = 0 , Nb_feedback_variable = 0 ;
2020-04-23 16:04:02 +02:00
int Nb_TotalBlocks = blocks . size ( ) ;
2020-03-24 18:26:06 +01:00
for ( int block = 0 ; block < Nb_TotalBlocks ; block + + )
2020-04-23 16:04:02 +02:00
if ( BlockSimulationType simulation_type = blocks [ block ] . simulation_type ;
2020-04-21 23:06:51 +02:00
simulation_type = = BlockSimulationType : : solveForwardComplete
| | simulation_type = = BlockSimulationType : : solveBackwardComplete
| | simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete )
{
Nb_SimulBlocks + + ;
2020-04-23 16:04:02 +02:00
if ( int size = blocks [ block ] . size ;
2020-04-21 23:06:51 +02:00
size > largest_block )
{
largest_block = size ;
2020-04-23 16:04:02 +02:00
Nb_feedback_variable = blocks [ block ] . mfs_size ;
2020-04-21 23:06:51 +02:00
}
}
2009-12-16 14:21:31 +01:00
int Nb_RecursBlocks = Nb_TotalBlocks - Nb_SimulBlocks ;
cout < < Nb_TotalBlocks < < " block(s) found: " < < endl
< < " " < < Nb_RecursBlocks < < " recursive block(s) and " < < Nb_SimulBlocks < < " simultaneous block(s). " < < endl
< < " the largest simultaneous block has " < < largest_block < < " equation(s) " < < endl
< < " and " < < Nb_feedback_variable < < " feedback variable(s). " < < endl ;
}
2020-03-20 15:23:23 +01:00
void
2020-04-30 12:48:16 +02:00
ModelTree : : reduceBlockDecomposition ( )
2009-12-16 14:21:31 +01:00
{
2020-04-30 12:48:16 +02:00
for ( int blk = 1 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
if ( blocks [ blk ] . size = = 1 )
{
/* Try to merge this block with the previous one.
This is only possible if the two blocks can simply be evaluated
( in the same direction ) , and if the merge does not break the
restrictions on leads / lags . */
set < pair < int , int > > endos_and_lags ;
getBlockEquationExpr ( blk , 0 ) - > collectEndogenous ( endos_and_lags ) ;
bool is_lead = false , is_lag = false ;
for ( int var = 0 ; var < blocks [ blk - 1 ] . size ; var + + )
{
2020-06-17 19:42:13 +02:00
is_lag = is_lag | | endos_and_lags . find ( { getBlockVariableID ( blk - 1 , var ) , - 1 } ) ! = endos_and_lags . end ( ) ;
is_lead = is_lead | | endos_and_lags . find ( { getBlockVariableID ( blk - 1 , var ) , 1 } ) ! = endos_and_lags . end ( ) ;
2020-04-30 12:48:16 +02:00
}
2020-04-21 18:10:46 +02:00
2020-04-30 12:48:16 +02:00
if ( ( blocks [ blk - 1 ] . simulation_type = = BlockSimulationType : : evaluateForward
& & blocks [ blk ] . simulation_type = = BlockSimulationType : : evaluateForward
& & ! is_lead )
| | ( blocks [ blk - 1 ] . simulation_type = = BlockSimulationType : : evaluateBackward
& & blocks [ blk ] . simulation_type = = BlockSimulationType : : evaluateBackward
& & ! is_lag ) )
{
// Merge the current block into the previous one
blocks [ blk - 1 ] . size + + ;
blocks [ blk - 1 ] . mfs_size = blocks [ blk - 1 ] . size ;
computeDynamicStructureOfBlock ( blk - 1 ) ;
blocks . erase ( blocks . begin ( ) + blk ) ;
for ( auto & b : endo2block )
if ( b > = blk )
b - - ;
for ( auto & b : eq2block )
if ( b > = blk )
b - - ;
blk - - ;
continue ;
}
}
2009-12-16 14:21:31 +01:00
}
2020-03-20 15:23:23 +01:00
void
ModelTree : : determineLinearBlocks ( )
2009-12-16 14:21:31 +01:00
{
2020-04-21 18:10:46 +02:00
// Note that field “linear” in class BlockInfo defaults to true
2020-04-28 12:35:18 +02:00
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
switch ( blocks [ blk ] . simulation_type )
{
case BlockSimulationType : : solveBackwardComplete :
case BlockSimulationType : : solveForwardComplete :
for ( const auto & [ indices , d1 ] : blocks_derivatives [ blk ] )
2019-12-16 19:42:59 +01:00
{
2020-04-24 12:29:02 +02:00
int lag = get < 2 > ( indices ) ;
2019-12-16 19:42:59 +01:00
if ( lag = = 0 )
{
set < pair < int , int > > endogenous ;
d1 - > collectEndogenous ( endogenous ) ;
2020-04-28 12:35:18 +02:00
for ( int l = 0 ; l < blocks [ blk ] . size ; l + + )
if ( endogenous . find ( { endo_idx_block2orig [ blocks [ blk ] . first_equation + l ] , 0 } )
! = endogenous . end ( ) )
{
blocks [ blk ] . linear = false ;
goto the_end ;
}
2019-12-16 19:42:59 +01:00
}
}
2020-04-28 12:35:18 +02:00
the_end :
break ;
case BlockSimulationType : : solveTwoBoundariesComplete :
case BlockSimulationType : : solveTwoBoundariesSimple :
for ( const auto & [ indices , d1 ] : blocks_derivatives [ blk ] )
2019-12-16 19:42:59 +01:00
{
2020-04-24 12:29:02 +02:00
int lag = get < 2 > ( indices ) ;
2019-12-16 19:42:59 +01:00
set < pair < int , int > > endogenous ;
d1 - > collectEndogenous ( endogenous ) ;
2020-04-28 12:35:18 +02:00
for ( int l = 0 ; l < blocks [ blk ] . size ; l + + )
if ( endogenous . find ( { endo_idx_block2orig [ blocks [ blk ] . first_equation + l ] , lag } )
! = endogenous . end ( ) )
{
blocks [ blk ] . linear = false ;
goto the_end2 ;
}
2019-12-16 19:42:59 +01:00
}
2020-04-28 12:35:18 +02:00
the_end2 :
break ;
default :
break ;
}
2009-12-16 14:21:31 +01:00
}
2008-02-03 11:28:36 +01:00
int
ModelTree : : equation_number ( ) const
2009-01-23 11:59:37 +01:00
{
2009-12-16 18:13:23 +01:00
return ( equations . size ( ) ) ;
2009-01-23 11:59:37 +01:00
}
2008-02-03 11:28:36 +01:00
void
ModelTree : : writeDerivative ( ostream & output , int eq , int symb_id , int lag ,
ExprNodeOutputType output_type ,
2010-09-16 19:00:48 +02:00
const temporary_terms_t & temporary_terms ) const
2009-01-23 11:59:37 +01:00
{
2019-12-16 19:42:59 +01:00
if ( auto it = derivatives [ 1 ] . find ( { eq , getDerivID ( symb_id , lag ) } ) ;
it ! = derivatives [ 1 ] . end ( ) )
it - > second - > writeOutput ( output , output_type , temporary_terms , { } ) ;
2009-01-23 11:59:37 +01:00
else
output < < 0 ;
}
2008-02-03 11:28:36 +01:00
void
2018-11-22 14:32:40 +01:00
ModelTree : : computeDerivatives ( int order , const set < int > & vars )
2008-02-03 11:28:36 +01:00
{
2019-12-20 16:59:30 +01:00
assert ( order > = 1 ) ;
2008-02-03 11:28:36 +01:00
2020-01-20 17:22:32 +01:00
computed_derivs_order = order ;
2018-11-22 14:32:40 +01:00
// Do not shrink the vectors, since they have a minimal size of 4 (see constructor)
2019-04-12 15:41:52 +02:00
derivatives . resize ( max ( static_cast < size_t > ( order + 1 ) , derivatives . size ( ) ) ) ;
NNZDerivatives . resize ( max ( static_cast < size_t > ( order + 1 ) , NNZDerivatives . size ( ) ) , 0 ) ;
2009-04-20 12:48:54 +02:00
2018-11-22 14:32:40 +01:00
// First-order derivatives
for ( int var : vars )
2019-04-12 15:41:52 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2018-11-22 14:32:40 +01:00
{
expr_t d1 = equations [ eq ] - > getDerivative ( var ) ;
if ( d1 = = Zero )
continue ;
derivatives [ 1 ] [ { eq , var } ] = d1 ;
+ + NNZDerivatives [ 1 ] ;
}
2009-04-20 12:48:54 +02:00
2018-11-22 14:32:40 +01:00
// Higher-order derivatives
for ( int o = 2 ; o < = order ; o + + )
for ( const auto & it : derivatives [ o - 1 ] )
for ( int var : vars )
2008-02-03 11:28:36 +01:00
{
2018-11-22 14:32:40 +01:00
if ( it . first . back ( ) > var )
2009-04-20 12:48:54 +02:00
continue ;
2018-11-22 14:32:40 +01:00
expr_t d = it . second - > getDerivative ( var ) ;
if ( d = = Zero )
2009-04-20 12:48:54 +02:00
continue ;
2018-11-22 14:32:40 +01:00
vector < int > indices { it . first } ;
indices . push_back ( var ) ;
// At this point, indices of endogenous variables are sorted in non-decreasing order
derivatives [ o ] [ indices ] = d ;
2019-06-17 15:28:33 +02:00
// We output symmetric elements at order = 2
if ( o = = 2 & & indices [ 1 ] ! = indices [ 2 ] )
NNZDerivatives [ o ] + = 2 ;
2019-04-12 15:41:52 +02:00
else
2018-11-22 14:32:40 +01:00
NNZDerivatives [ o ] + + ;
2008-02-03 11:28:36 +01:00
}
}
void
2018-09-25 15:56:52 +02:00
ModelTree : : computeTemporaryTerms ( bool is_matlab , bool no_tmp_terms )
2008-02-03 11:28:36 +01:00
{
2018-11-16 16:53:07 +01:00
/* Collect all model local variables appearing in equations (and only those,
because printing unused model local variables can lead to a crash ,
see Dynare / dynare # 101 ) .
Then store them in a dedicated structure ( temporary_terms_mlv ) , that will
be treated as the rest of temporary terms . */
2018-11-30 12:22:13 +01:00
temporary_terms_mlv . clear ( ) ;
2018-05-23 19:19:11 +02:00
set < int > used_local_vars ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-07-17 18:34:07 +02:00
equation - > collectVariables ( SymbolType : : modelLocalVariable , used_local_vars ) ;
2018-06-04 12:26:16 +02:00
for ( int used_local_var : used_local_vars )
2018-03-27 17:14:30 +02:00
{
2018-06-04 12:26:16 +02:00
VariableNode * v = AddVariable ( used_local_var ) ;
temporary_terms_mlv [ v ] = local_variables_table . find ( used_local_var ) - > second ;
2018-03-27 17:14:30 +02:00
}
2018-11-30 12:22:13 +01:00
// Compute the temporary terms in equations and derivatives
map < pair < int , int > , temporary_terms_t > temp_terms_map ;
2019-08-14 15:28:41 +02:00
map < expr_t , pair < int , pair < int , int > > > reference_count ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2019-08-14 15:28:41 +02:00
equation - > computeTemporaryTerms ( { 0 , 0 } ,
temp_terms_map ,
reference_count ,
is_matlab ) ;
for ( int order = 1 ; order < static_cast < int > ( derivatives . size ( ) ) ; order + + )
for ( const auto & it : derivatives [ order ] )
it . second - > computeTemporaryTerms ( { 0 , order } ,
temp_terms_map ,
reference_count ,
is_matlab ) ;
/* If the user has specified the notmpterms option, clear all temporary
terms , except those that correspond to external functions ( since they are
not optional ) */
if ( no_tmp_terms )
for ( auto & it : temp_terms_map )
// The following loop can be simplified with std::erase_if() in C++20
2019-12-20 16:59:30 +01:00
for ( auto it2 = it . second . begin ( ) ; it2 ! = it . second . end ( ) ; )
2019-08-14 15:28:41 +02:00
if ( ! dynamic_cast < AbstractExternalFunctionNode * > ( * it2 ) )
it2 = it . second . erase ( it2 ) ;
else
+ + it2 ;
2015-09-03 13:50:02 +02:00
2020-05-06 17:13:47 +02:00
// Fill the structures
2018-11-30 12:22:13 +01:00
temporary_terms_derivatives . clear ( ) ;
temporary_terms_derivatives . resize ( derivatives . size ( ) ) ;
2019-04-23 11:07:32 +02:00
for ( int order = 0 ; order < static_cast < int > ( derivatives . size ( ) ) ; order + + )
2018-11-30 12:22:13 +01:00
temporary_terms_derivatives [ order ] = move ( temp_terms_map [ { 0 , order } ] ) ;
2018-03-27 17:14:30 +02:00
2018-11-30 12:22:13 +01:00
// Compute indices in MATLAB/Julia vector
2018-05-25 15:19:33 +02:00
int idx = 0 ;
2020-06-05 14:52:22 +02:00
for ( auto [ mlv , value ] : temporary_terms_mlv )
temporary_terms_idxs [ mlv ] = idx + + ;
2019-04-23 11:07:32 +02:00
for ( int order = 0 ; order < static_cast < int > ( derivatives . size ( ) ) ; order + + )
2020-06-05 14:52:22 +02:00
for ( auto it : temporary_terms_derivatives [ order ] )
2018-11-30 12:22:13 +01:00
temporary_terms_idxs [ it ] = idx + + ;
2018-03-27 17:14:30 +02:00
}
2020-05-06 17:13:47 +02:00
void
ModelTree : : computeBlockTemporaryTerms ( )
{
int nb_blocks = blocks . size ( ) ;
blocks_temporary_terms . resize ( nb_blocks ) ;
2020-05-13 16:58:19 +02:00
map < expr_t , tuple < int , int , int > > reference_count ;
2020-05-06 17:13:47 +02:00
for ( int blk = 0 ; blk < nb_blocks ; blk + + )
{
2020-05-13 16:58:19 +02:00
blocks_temporary_terms [ blk ] . resize ( blocks [ blk ] . size + 1 ) ;
2020-05-06 17:13:47 +02:00
for ( int eq = 0 ; eq < blocks [ blk ] . size ; eq + + )
{
if ( eq < blocks [ blk ] . getRecursiveSize ( ) & & isBlockEquationRenormalized ( blk , eq ) )
2020-05-13 16:58:19 +02:00
getBlockEquationRenormalizedExpr ( blk , eq ) - > computeBlockTemporaryTerms ( blk , eq , blocks_temporary_terms , reference_count ) ;
2020-05-06 17:13:47 +02:00
else
2020-05-13 16:58:19 +02:00
getBlockEquationExpr ( blk , eq ) - > computeBlockTemporaryTerms ( blk , eq , blocks_temporary_terms , reference_count ) ;
2020-05-06 17:13:47 +02:00
}
for ( const auto & [ ignore , d ] : blocks_derivatives [ blk ] )
2020-05-13 16:58:19 +02:00
d - > computeBlockTemporaryTerms ( blk , blocks [ blk ] . size , blocks_temporary_terms , reference_count ) ;
2020-05-06 17:13:47 +02:00
additionalBlockTemporaryTerms ( blk , blocks_temporary_terms , reference_count ) ;
}
// Compute indices in the temporary terms vector
int idx = 0 ;
blocks_temporary_terms_idxs . clear ( ) ;
2020-05-13 16:58:19 +02:00
for ( auto & blk_tt : blocks_temporary_terms )
for ( auto & eq_tt : blk_tt )
for ( auto tt : eq_tt )
blocks_temporary_terms_idxs [ tt ] = idx + + ;
2020-05-06 17:13:47 +02:00
}
void
ModelTree : : 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
2020-05-06 17:13:47 +02:00
{
}
2018-03-27 17:14:30 +02:00
void
2018-11-16 16:53:07 +01:00
ModelTree : : 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
{
2018-11-16 16:53:07 +01:00
temporary_terms_t tto ;
2020-06-05 14:52:22 +02:00
for ( auto [ mlv , value ] : temporary_terms_mlv )
tto . insert ( mlv ) ;
2018-11-16 16:53:07 +01:00
2020-06-05 14:52:22 +02:00
for ( auto [ mlv , value ] : temporary_terms_mlv )
2018-03-27 17:14:30 +02:00
{
2020-06-05 14:52:22 +02:00
value - > writeExternalFunctionOutput ( output , output_type , temp_term_union , tt_idxs , tef_terms ) ;
2020-06-05 14:50:06 +02:00
2018-09-25 19:15:22 +02:00
if ( isJuliaOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
output < < " @inbounds const " ;
2020-06-05 14:52:22 +02:00
mlv - > writeOutput ( output , output_type , tto , tt_idxs , tef_terms ) ;
2018-03-27 17:14:30 +02:00
output < < " = " ;
2020-06-05 14:52:22 +02:00
value - > writeOutput ( output , output_type , temp_term_union , tt_idxs , tef_terms ) ;
2018-03-27 17:14:30 +02:00
2018-09-05 18:27:13 +02:00
if ( isCOutput ( output_type ) | | isMatlabOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
output < < " ; " ;
output < < endl ;
2018-11-16 16:53:07 +01:00
/* We put in temp_term_union the VariableNode corresponding to the MLV,
not its definition , so that when equations use the MLV ,
T ( XXX ) is printed instead of the MLV name */
2020-06-05 14:52:22 +02:00
temp_term_union . insert ( mlv ) ;
2018-03-27 17:14:30 +02:00
}
}
void
2018-05-24 19:29:53 +02:00
ModelTree : : writeTemporaryTerms ( const temporary_terms_t & tt ,
2018-11-16 16:53:07 +01:00
temporary_terms_t & temp_term_union ,
2018-05-28 15:23:15 +02: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
{
2018-11-16 16:53:07 +01:00
for ( auto it : tt )
2018-03-27 17:14:30 +02:00
{
2019-12-16 19:42:59 +01:00
if ( dynamic_cast < AbstractExternalFunctionNode * > ( it ) )
2018-11-16 16:53:07 +01:00
it - > writeExternalFunctionOutput ( output , output_type , temp_term_union , tt_idxs , tef_terms ) ;
2018-03-27 17:14:30 +02:00
2018-09-25 19:15:22 +02:00
if ( isJuliaOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
output < < " @inbounds " ;
2018-11-16 16:53:07 +01:00
it - > writeOutput ( output , output_type , tt , tt_idxs , tef_terms ) ;
2018-03-27 17:14:30 +02:00
output < < " = " ;
2018-11-16 16:53:07 +01:00
it - > writeOutput ( output , output_type , temp_term_union , tt_idxs , tef_terms ) ;
2018-03-27 17:14:30 +02:00
2018-09-05 18:27:13 +02:00
if ( isCOutput ( output_type ) | | isMatlabOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
output < < " ; " ;
output < < endl ;
2018-11-16 16:53:07 +01:00
temp_term_union . insert ( it ) ;
2018-03-27 17:14:30 +02:00
}
2009-01-23 11:59:37 +01:00
}
2008-02-03 11:28:36 +01:00
2017-02-20 12:18:11 +01:00
void
2019-04-18 14:34:48 +02:00
ModelTree : : 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
2017-02-20 12:18:11 +01:00
{
// Local var used to keep track of temp nodes already written
bool wrote_term = false ;
2019-04-18 14:34:48 +02:00
temporary_terms_t tt2 = temp_term_union ;
2017-02-20 12:18:11 +01:00
2019-04-03 16:32:52 +02:00
output < < R " ( " external_functions_temporary_terms_ ) " << concat << R " ( " : [) " ;
2018-06-04 12:26:16 +02:00
for ( auto it : tt )
2019-04-18 14:34:48 +02:00
{
2019-12-16 19:42:59 +01:00
if ( dynamic_cast < AbstractExternalFunctionNode * > ( it ) )
2019-04-18 14:34:48 +02:00
{
if ( wrote_term )
output < < " , " ;
vector < string > efout ;
it - > writeJsonExternalFunctionOutput ( efout , tt2 , tef_terms ) ;
for ( auto it1 = efout . begin ( ) ; it1 ! = efout . end ( ) ; + + it1 )
{
if ( it1 ! = efout . begin ( ) )
output < < " , " ;
output < < * it1 ;
}
wrote_term = true ;
}
tt2 . insert ( it ) ;
}
2017-02-20 12:18:11 +01:00
wrote_term = false ;
output < < " ] "
2019-04-03 16:32:52 +02:00
< < R " (, " temporary_terms_ ) " << concat << R " ( " : [) " ;
2019-04-18 14:34:48 +02:00
for ( const auto & it : tt )
{
if ( wrote_term )
output < < " , " ;
output < < R " ({ " temporary_term " : " ) " ;
it - > writeJsonOutput ( output , tt , tef_terms ) ;
output < < R " ( " ) "
< < R " (, " value " : " ) " ;
it - > writeJsonOutput ( output , temp_term_union , tef_terms ) ;
output < < R " ( " } ) " << endl;
wrote_term = true ;
temp_term_union . insert ( it ) ;
}
2017-02-20 12:18:11 +01:00
output < < " ] " ;
}
2016-12-28 14:02:50 +01:00
void
2017-01-05 15:19:13 +01:00
ModelTree : : fixNestedParenthesis ( ostringstream & output , map < string , string > & tmp_paren_vars , bool & message_printed ) const
2016-12-28 14:02:50 +01:00
{
string str = output . str ( ) ;
2016-12-30 18:32:20 +01:00
if ( ! testNestedParenthesis ( str ) )
return ;
2016-12-28 14:02:50 +01:00
int open = 0 ;
2016-12-30 11:26:56 +01:00
int first_open_paren = 0 ;
int matching_paren = 0 ;
bool hit_limit = false ;
int i1 = 0 ;
2017-01-02 11:37:15 +01:00
for ( size_t i = 0 ; i < str . length ( ) ; i + + )
2016-12-28 14:02:50 +01:00
{
2016-12-30 11:26:56 +01:00
if ( str . at ( i ) = = ' ( ' )
{
if ( open = = 0 )
first_open_paren = i ;
open + + ;
}
else if ( str . at ( i ) = = ' ) ' )
{
open - - ;
if ( open = = 0 )
matching_paren = i ;
}
2016-12-28 14:02:50 +01:00
if ( open > 32 )
2016-12-30 11:26:56 +01:00
hit_limit = true ;
if ( hit_limit & & open = = 0 )
2016-12-28 14:02:50 +01:00
{
2017-01-05 15:19:13 +01:00
if ( ! message_printed )
{
2019-10-02 11:24:37 +02:00
cerr < < " Warning: A .m file created by Dynare will have more than 32 nested parenthesis. MATLAB cannot support this. " < < endl
2017-01-05 15:19:13 +01:00
< < " We are going to modify, albeit inefficiently, this output to have fewer than 32 nested parenthesis. " < < endl
< < " It would hence behoove you to use the use_dll option of the model block to circumnavigate this problem. " < < endl
2019-10-02 11:24:37 +02:00
< < " If you have not yet set up a compiler on your system, see the MATLAB documentation for doing so. " < < endl
2017-01-05 15:19:13 +01:00
< < " For Windows, see: https://www.mathworks.com/help/matlab/matlab_external/install-mingw-support-package.html " < < endl < < endl ;
message_printed = true ;
}
2016-12-30 11:26:56 +01:00
string str1 = str . substr ( first_open_paren , matching_paren - first_open_paren + 1 ) ;
2019-12-16 19:42:59 +01:00
string repstr , varname ;
2016-12-30 11:26:56 +01:00
while ( testNestedParenthesis ( str1 ) )
{
2019-12-20 16:59:30 +01:00
size_t open_paren_idx = string : : npos ;
2017-01-02 11:37:15 +01:00
size_t match_paren_idx = string : : npos ;
size_t last_open_paren = string : : npos ;
for ( size_t j = 0 ; j < str1 . length ( ) ; j + + )
2016-12-30 11:26:56 +01:00
{
if ( str1 . at ( j ) = = ' ( ' )
{
// don't match, e.g. y(1)
2019-12-16 19:42:59 +01:00
if ( size_t idx = str1 . find_last_of ( " */-+ " , j - 1 ) ;
j = = 0 | | ( idx ! = string : : npos & & idx = = j - 1 ) )
2016-12-30 11:26:56 +01:00
open_paren_idx = j ;
last_open_paren = j ;
}
else if ( str1 . at ( j ) = = ' ) ' )
{
// don't match, e.g. y(1)
2019-12-16 19:42:59 +01:00
if ( size_t idx = str1 . find_last_not_of ( " 0123456789 " , j - 1 ) ;
idx ! = string : : npos & & idx ! = last_open_paren )
2016-12-30 11:26:56 +01:00
match_paren_idx = j ;
}
2017-01-02 11:37:15 +01:00
if ( open_paren_idx ! = string : : npos & & match_paren_idx ! = string : : npos )
2016-12-30 11:26:56 +01:00
{
string val = str1 . substr ( open_paren_idx , match_paren_idx - open_paren_idx + 1 ) ;
2019-12-16 19:42:59 +01:00
if ( auto it = tmp_paren_vars . find ( val ) ;
it = = tmp_paren_vars . end ( ) )
2016-12-30 11:26:56 +01:00
{
2017-01-02 11:21:28 +01:00
ostringstream ptvstr ;
ptvstr < < i1 + + ;
varname = " paren32_tmp_var_ " + ptvstr . str ( ) ;
2016-12-30 11:26:56 +01:00
repstr = repstr + varname + " = " + val + " ; \n " ;
tmp_paren_vars [ val ] = varname ;
}
else
varname = it - > second ;
str1 . replace ( open_paren_idx , match_paren_idx - open_paren_idx + 1 , varname ) ;
break ;
}
}
}
2019-12-16 19:42:59 +01:00
if ( auto it = tmp_paren_vars . find ( str1 ) ;
it = = tmp_paren_vars . end ( ) )
2016-12-30 11:26:56 +01:00
{
2017-01-02 11:21:28 +01:00
ostringstream ptvstr ;
ptvstr < < i1 + + ;
varname = " paren32_tmp_var_ " + ptvstr . str ( ) ;
2016-12-30 11:26:56 +01:00
repstr = repstr + varname + " = " + str1 + " ; \n " ;
}
else
varname = it - > second ;
str . replace ( first_open_paren , matching_paren - first_open_paren + 1 , varname ) ;
size_t insertLoc = str . find_last_of ( " \n " , first_open_paren ) ;
str . insert ( insertLoc + 1 , repstr ) ;
hit_limit = false ;
i = - 1 ;
first_open_paren = matching_paren = open = 0 ;
2016-12-28 14:02:50 +01:00
}
}
2016-12-30 11:26:56 +01:00
output . str ( str ) ;
}
bool
ModelTree : : testNestedParenthesis ( const string & str ) const
{
int open = 0 ;
2018-06-04 12:26:16 +02:00
for ( char i : str )
2016-12-30 11:26:56 +01:00
{
2018-06-04 12:26:16 +02:00
if ( i = = ' ( ' )
2016-12-30 11:26:56 +01:00
open + + ;
2018-06-04 12:26:16 +02:00
else if ( i = = ' ) ' )
2016-12-30 11:26:56 +01:00
open - - ;
if ( open > 32 )
return true ;
}
return false ;
2016-12-28 14:02:50 +01:00
}
2010-01-22 11:03:29 +01:00
void
2020-05-13 12:53:47 +02:00
ModelTree : : 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
2010-01-22 11:03:29 +01:00
{
2010-12-10 11:50:27 +01:00
// To store the functions that have already been written in the form TEF* = ext_fun();
deriv_node_temp_terms_t tef_terms ;
2020-05-06 17:13:47 +02:00
for ( auto [ tt , idx ] : temporary_terms_idxs )
2010-01-22 11:03:29 +01:00
{
2020-05-06 17:13:47 +02:00
if ( dynamic_cast < AbstractExternalFunctionNode * > ( tt ) )
2020-05-13 12:53:47 +02:00
tt - > compileExternalFunctionOutput ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , dynamic , steady_dynamic , tef_terms ) ;
2010-12-10 11:50:27 +01:00
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : TemporaryTerm , idx ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2020-05-13 12:53:47 +02:00
tt - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , dynamic , steady_dynamic , tef_terms ) ;
2010-01-22 11:03:29 +01:00
if ( dynamic )
{
2020-05-06 17:13:47 +02:00
FSTPT_ fstpt ( idx ) ;
2010-07-23 11:20:24 +02:00
fstpt . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
}
else
{
2020-05-06 17:13:47 +02:00
FSTPST_ fstpst ( idx ) ;
2010-07-23 11:20:24 +02:00
fstpst . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
}
}
}
2017-02-20 12:18:11 +01:00
void
2020-06-05 16:07:52 +02:00
ModelTree : : writeJsonModelLocalVariables ( ostream & output , bool write_tef_terms , deriv_node_temp_terms_t & tef_terms ) const
2017-02-20 12:18:11 +01:00
{
/* Collect all model local variables appearing in equations, and print only
them . Printing unused model local variables can lead to a crash ( see
ticket # 101 ) . */
set < int > used_local_vars ;
2018-06-04 12:26:16 +02:00
for ( auto equation : equations )
2018-07-17 18:34:07 +02:00
equation - > collectVariables ( SymbolType : : modelLocalVariable , used_local_vars ) ;
2017-02-20 12:18:11 +01:00
2019-04-03 16:32:52 +02:00
output < < R " ( " model_local_variables " : [) " ;
2017-08-28 15:14:11 +02:00
bool printed = false ;
2020-06-05 14:52:22 +02:00
for ( int id : local_variables_vector )
if ( used_local_vars . find ( id ) ! = used_local_vars . end ( ) )
2017-08-28 15:14:11 +02:00
{
if ( printed )
output < < " , " ;
else
printed = true ;
2017-11-06 15:21:11 +01:00
expr_t value = local_variables_table . find ( id ) - > second ;
2020-06-05 16:07:52 +02:00
if ( write_tef_terms )
2017-11-06 15:21:11 +01:00
{
2020-06-05 16:07:52 +02:00
vector < string > efout ;
2020-06-05 14:52:22 +02:00
value - > writeJsonExternalFunctionOutput ( efout , { } , tef_terms ) ;
2020-06-05 16:07:52 +02:00
for ( auto it1 = efout . begin ( ) ; it1 ! = efout . end ( ) ; + + it1 )
{
if ( it1 ! = efout . begin ( ) )
output < < " , " ;
output < < * it1 ;
}
if ( ! efout . empty ( ) )
2017-11-06 15:21:11 +01:00
output < < " , " ;
}
2020-06-05 15:00:39 +02:00
output < < R " ({ " variable " : " ) " << symbol_table.getName(id)
< < R " ( " , " value " : " ) " ;
2020-06-05 14:52:22 +02:00
value - > writeJsonOutput ( output , { } , tef_terms ) ;
2019-04-03 16:32:52 +02:00
output < < R " ( " } ) " << endl;
2017-08-28 15:14:11 +02:00
}
2017-02-20 12:18:11 +01:00
output < < " ] " ;
}
2008-02-03 11:28:36 +01:00
void
ModelTree : : writeModelEquations ( ostream & output , ExprNodeOutputType output_type ) const
2009-01-23 11:59:37 +01:00
{
2018-03-27 17:14:30 +02:00
temporary_terms_t tt ;
temporary_terms_idxs_t ttidxs ;
2018-05-24 19:29:53 +02:00
writeModelEquations ( output , output_type , tt ) ;
2018-03-27 17:14:30 +02:00
}
2015-09-01 17:39:49 +02:00
2018-03-27 17:14:30 +02:00
void
ModelTree : : writeModelEquations ( ostream & output , ExprNodeOutputType output_type ,
2018-05-24 19:29:53 +02:00
const temporary_terms_t & temporary_terms ) const
2018-03-27 17:14:30 +02:00
{
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2009-01-23 11:59:37 +01:00
{
BinaryOpNode * eq_node = equations [ eq ] ;
2018-11-28 14:32:26 +01:00
expr_t lhs = eq_node - > arg1 ;
expr_t rhs = eq_node - > arg2 ;
2008-02-03 11:28:36 +01:00
2009-10-29 18:16:10 +01:00
// Test if the right hand side of the equation is empty.
double vrhs = 1.0 ;
try
{
2010-09-16 19:00:48 +02:00
vrhs = rhs - > eval ( eval_context_t ( ) ) ;
2009-10-29 18:16:10 +01:00
}
2009-12-16 18:13:23 +01:00
catch ( ExprNode : : EvalException & e )
2009-10-29 18:16:10 +01:00
{
}
2009-12-16 18:13:23 +01:00
if ( vrhs ! = 0 ) // The right hand side of the equation is not empty ==> residual=lhs-rhs;
2018-09-05 18:27:13 +02:00
if ( isJuliaOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
{
output < < " @inbounds residual " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < eq + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = ( " ;
lhs - > writeOutput ( output , output_type , temporary_terms , temporary_terms_idxs ) ;
output < < " ) - ( " ;
rhs - > writeOutput ( output , output_type , temporary_terms , temporary_terms_idxs ) ;
output < < " ) " < < endl ;
}
else
{
output < < " lhs = " ;
lhs - > writeOutput ( output , output_type , temporary_terms , temporary_terms_idxs ) ;
output < < " ; " < < endl
< < " rhs = " ;
rhs - > writeOutput ( output , output_type , temporary_terms , temporary_terms_idxs ) ;
output < < " ; " < < endl
< < " residual " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < eq + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = lhs - rhs; " < < endl ;
}
2009-12-16 18:13:23 +01:00
else // The right hand side of the equation is empty ==> residual=lhs;
2009-10-29 18:16:10 +01:00
{
2018-09-05 18:27:13 +02:00
if ( isJuliaOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
output < < " @inbounds " ;
2009-12-16 18:13:23 +01:00
output < < " residual " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < eq + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = " ;
2018-03-27 17:14:30 +02:00
lhs - > writeOutput ( output , output_type , temporary_terms , temporary_terms_idxs ) ;
2009-12-16 18:13:23 +01:00
output < < " ; " < < endl ;
2009-10-29 18:16:10 +01:00
}
2009-01-23 11:59:37 +01:00
}
}
2008-02-03 11:28:36 +01:00
2010-01-22 11:03:29 +01:00
void
2020-05-13 12:53:47 +02:00
ModelTree : : 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
2010-01-22 11:03:29 +01:00
{
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2010-01-22 11:03:29 +01:00
{
BinaryOpNode * eq_node = equations [ eq ] ;
2018-11-28 14:32:26 +01:00
expr_t lhs = eq_node - > arg1 ;
expr_t rhs = eq_node - > arg2 ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : ModelEquation , eq ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
// Test if the right hand side of the equation is empty.
double vrhs = 1.0 ;
try
{
2010-09-16 19:00:48 +02:00
vrhs = rhs - > eval ( eval_context_t ( ) ) ;
2010-01-22 11:03:29 +01:00
}
catch ( ExprNode : : EvalException & e )
{
}
if ( vrhs ! = 0 ) // The right hand side of the equation is not empty ==> residual=lhs-rhs;
{
2020-05-13 12:53:47 +02:00
lhs - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , dynamic , steady_dynamic ) ;
rhs - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , dynamic , steady_dynamic ) ;
2010-01-22 11:03:29 +01:00
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : minus ) } ;
2010-07-23 11:20:24 +02:00
fbinary . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
FSTPR_ fstpr ( eq ) ;
2010-07-23 11:20:24 +02:00
fstpr . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
}
else // The right hand side of the equation is empty ==> residual=lhs;
{
2020-05-13 12:53:47 +02:00
lhs - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , dynamic , steady_dynamic ) ;
2010-01-22 11:03:29 +01:00
FSTPR_ fstpr ( eq ) ;
2010-07-23 11:20:24 +02:00
fstpr . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
}
}
}
void
2020-05-19 17:43:35 +02:00
ModelTree : : writeBytecodeBinFile ( const string & filename , int & u_count_int , bool & file_open ,
bool is_two_boundaries ) const
2010-01-22 11:03:29 +01:00
{
int j ;
std : : ofstream SaveCode ;
if ( file_open )
2018-06-27 15:01:31 +02:00
SaveCode . open ( filename , ios : : out | ios : : in | ios : : binary | ios : : ate ) ;
2010-01-22 11:03:29 +01:00
else
2018-06-27 15:01:31 +02:00
SaveCode . open ( filename , ios : : out | ios : : binary ) ;
2010-01-22 11:03:29 +01:00
if ( ! SaveCode . is_open ( ) )
{
2019-04-03 16:32:52 +02:00
cerr < < R " (Error : Can't open file " ) " << filename << R " ( " for writing) " < < endl ;
2010-01-22 11:03:29 +01:00
exit ( EXIT_FAILURE ) ;
}
u_count_int = 0 ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d1 ] : derivatives [ 1 ] )
2010-01-22 11:03:29 +01:00
{
2019-12-16 19:42:59 +01:00
int deriv_id = indices [ 1 ] ;
2018-07-17 18:34:07 +02:00
if ( getTypeByDerivID ( deriv_id ) = = SymbolType : : endogenous )
2010-01-22 11:03:29 +01:00
{
2019-12-16 19:42:59 +01:00
int eq = indices [ 0 ] ;
2010-01-22 11:03:29 +01:00
int symb = getSymbIDByDerivID ( deriv_id ) ;
int var = symbol_table . getTypeSpecificID ( symb ) ;
int lag = getLagByDerivID ( deriv_id ) ;
SaveCode . write ( reinterpret_cast < char * > ( & eq ) , sizeof ( eq ) ) ;
2020-05-19 17:43:35 +02:00
int varr = var + lag * symbol_table . endo_nbr ( ) ;
2010-01-22 11:03:29 +01:00
SaveCode . write ( reinterpret_cast < char * > ( & varr ) , sizeof ( varr ) ) ;
SaveCode . write ( reinterpret_cast < char * > ( & lag ) , sizeof ( lag ) ) ;
2020-05-19 17:43:35 +02:00
int u = u_count_int + symbol_table . endo_nbr ( ) ;
2010-01-22 11:03:29 +01:00
SaveCode . write ( reinterpret_cast < char * > ( & u ) , sizeof ( u ) ) ;
u_count_int + + ;
}
}
if ( is_two_boundaries )
2019-12-20 16:59:30 +01:00
u_count_int + = symbol_table . endo_nbr ( ) ;
2020-03-24 18:26:06 +01:00
for ( j = 0 ; j < symbol_table . endo_nbr ( ) ; j + + )
2010-01-22 11:03:29 +01:00
SaveCode . write ( reinterpret_cast < char * > ( & j ) , sizeof ( j ) ) ;
2020-03-24 18:26:06 +01:00
for ( j = 0 ; j < symbol_table . endo_nbr ( ) ; j + + )
2010-01-22 11:03:29 +01:00
SaveCode . write ( reinterpret_cast < char * > ( & j ) , sizeof ( j ) ) ;
SaveCode . close ( ) ;
}
2009-04-30 15:14:33 +02:00
void
2019-12-16 19:42:59 +01:00
ModelTree : : 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
{
2019-04-04 17:01:37 +02:00
filesystem : : create_directories ( mod_basename + " /latex " ) ;
2019-07-11 17:33:53 +02:00
2015-07-15 08:58:15 +02:00
ofstream output , content_output ;
2019-07-11 17:33:53 +02:00
string filename = mod_basename + " /latex/ " + latex_basename + " .tex " ;
string content_filename = mod_basename + " /latex/ " + latex_basename + " _content " + " .tex " ;
2018-06-27 15:12:12 +02:00
output . open ( filename , ios : : out | ios : : binary ) ;
2009-04-30 15:14:33 +02:00
if ( ! output . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-06-27 15:12:12 +02:00
content_output . open ( content_filename , ios : : out | ios : : binary ) ;
2015-07-15 08:58:15 +02:00
if ( ! content_output . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < content_filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2019-04-03 16:32:52 +02:00
output < < R " ( \ documentclass[10pt,a4paper]{article}) " < < endl
< < R " ( \ usepackage[landscape]{geometry}) " < < endl
< < R " ( \ usepackage{fullpage}) " < < endl
< < R " ( \ usepackage{amsfonts}) " < < endl
< < R " ( \ usepackage{breqn}) " < < endl
< < R " ( \b egin{document}) " < < endl
< < R " ( \f ootnotesize) " < < endl ;
2009-04-30 15:14:33 +02:00
// Write model local variables
2018-06-04 12:26:16 +02:00
for ( int id : local_variables_vector )
2009-04-30 15:14:33 +02:00
{
2017-08-28 15:14:11 +02:00
expr_t value = local_variables_table . find ( id ) - > second ;
2009-04-30 15:14:33 +02:00
2019-04-03 16:32:52 +02:00
content_output < < R " ( \b egin{dmath*}) " < < endl
2015-09-16 12:20:20 +02:00
< < symbol_table . getTeXName ( id ) < < " = " ;
2009-04-30 15:14:33 +02:00
// Use an empty set for the temporary terms
2015-07-15 08:58:15 +02:00
value - > writeOutput ( content_output , output_type ) ;
2019-04-03 16:32:52 +02:00
content_output < < endl < < R " ( \ end{dmath*}) " < < endl ;
2009-04-30 15:14:33 +02:00
}
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2009-04-30 15:14:33 +02:00
{
2017-04-05 10:28:37 +02:00
content_output < < " % Equation " < < eq + 1 < < endl ;
2017-04-04 15:28:27 +02:00
if ( write_equation_tags )
2020-02-20 15:29:10 +01:00
equation_tags . writeLatexOutput ( content_output , eq ) ;
2017-04-04 15:28:27 +02:00
2019-04-03 16:32:52 +02:00
content_output < < R " ( \b egin{dmath}) " < < endl ;
2010-03-09 12:16:32 +01:00
// Here it is necessary to cast to superclass ExprNode, otherwise the overloaded writeOutput() method is not found
2015-07-15 08:58:15 +02:00
dynamic_cast < ExprNode * > ( equations [ eq ] ) - > writeOutput ( content_output , output_type ) ;
2019-04-03 16:32:52 +02:00
content_output < < endl < < R " ( \ end{dmath}) " < < endl ;
2009-04-30 15:14:33 +02:00
}
2019-07-11 17:33:53 +02:00
output < < R " ( \ include{) " < < latex_basename + " _content " < < " } " < < endl
2019-04-03 16:32:52 +02:00
< < R " ( \ end{document}) " < < endl ;
2009-04-30 15:14:33 +02:00
output . close ( ) ;
2015-07-15 08:58:15 +02:00
content_output . close ( ) ;
2009-04-30 15:14:33 +02:00
}
2008-02-03 11:28:36 +01:00
void
2014-01-27 16:41:43 +01:00
ModelTree : : addEquation ( expr_t eq , int lineno )
2009-01-23 11:59:37 +01:00
{
2019-12-16 19:42:59 +01:00
auto beq = dynamic_cast < BinaryOpNode * > ( eq ) ;
assert ( beq & & beq - > op_code = = BinaryOpcode : : equal ) ;
2008-02-03 11:28:36 +01:00
equations . push_back ( beq ) ;
2014-01-27 16:41:43 +01:00
equations_lineno . push_back ( lineno ) ;
2008-02-03 11:28:36 +01:00
}
2009-09-02 16:37:59 +02:00
2019-11-18 17:13:49 +01:00
vector < int >
ModelTree : : 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
2019-11-18 17:13:49 +01:00
{
vector < int > excluded_vars ;
if ( equations . empty ( ) )
return excluded_vars ;
// Get equation numbers of tags
set < int > tag_eqns ;
2020-07-23 11:04:09 +02:00
for ( auto it = eqs . begin ( ) ; it ! = eqs . end ( ) ; )
if ( auto tmp = equation_tags . getEqnsByTag ( it - > first , it - > second ) ;
! tmp . empty ( ) )
2019-11-18 17:13:49 +01:00
{
2020-02-20 15:29:10 +01:00
tag_eqns . insert ( tmp . begin ( ) , tmp . end ( ) ) ;
2020-07-23 11:04:09 +02:00
it = eqs . erase ( it ) ;
2019-11-18 17:13:49 +01:00
}
2020-07-23 11:04:09 +02:00
else
+ + it ;
2020-02-20 15:29:10 +01:00
2019-11-18 17:13:49 +01:00
if ( tag_eqns . empty ( ) )
return excluded_vars ;
set < int > eqns ;
if ( exclude_eqs )
eqns = tag_eqns ;
else
for ( size_t i = 0 ; i < equations . size ( ) ; i + + )
if ( tag_eqns . find ( i ) = = tag_eqns . end ( ) )
eqns . insert ( i ) ;
2020-02-20 15:29:10 +01:00
// remove from equations, equations_lineno, equation_tags
2019-11-18 17:13:49 +01:00
vector < BinaryOpNode * > new_eqns ;
vector < int > new_equations_lineno ;
map < int , int > old_eqn_num_2_new ;
for ( size_t i = 0 ; i < equations . size ( ) ; i + + )
if ( eqns . find ( i ) ! = eqns . end ( ) )
{
2020-02-20 15:29:10 +01:00
if ( auto tmp = equation_tags . getTagValueByEqnAndKey ( i , " endogenous " ) ; ! tmp . empty ( ) )
2020-07-23 11:04:09 +02:00
excluded_vars . push_back ( symbol_table . getID ( tmp ) ) ;
else
2019-11-18 17:13:49 +01:00
{
set < pair < int , int > > result ;
equations [ i ] - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , result ) ;
if ( result . size ( ) = = 1 )
excluded_vars . push_back ( result . begin ( ) - > first ) ;
else
{
cerr < < " ERROR: Equation " < < i
< < " has been excluded but does not have a single variable on LHS or `endogenous` tag " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
}
else
{
new_eqns . emplace_back ( equations [ i ] ) ;
old_eqn_num_2_new [ i ] = new_eqns . size ( ) - 1 ;
new_equations_lineno . emplace_back ( equations_lineno [ i ] ) ;
}
int n_excl = equations . size ( ) - new_eqns . size ( ) ;
equations = new_eqns ;
equations_lineno = new_equations_lineno ;
2020-02-20 15:29:10 +01:00
equation_tags . erase ( eqns , old_eqn_num_2_new ) ;
2019-11-18 17:13:49 +01:00
if ( ! static_equations )
for ( size_t i = 0 ; i < excluded_vars . size ( ) ; i + + )
for ( size_t j = i + 1 ; j < excluded_vars . size ( ) ; j + + )
if ( excluded_vars [ i ] = = excluded_vars [ j ] )
{
cerr < < " Error: Variable " < < symbol_table . getName ( i ) < < " was excluded twice "
< < " via in/exclude_eqs option " < < endl ;
exit ( EXIT_FAILURE ) ;
}
cout < < " Excluded " < < n_excl < < ( static_equations ? " static " : " dynamic " )
2019-12-20 16:59:30 +01:00
< < " equation " < < ( n_excl > 1 ? " s " : " " ) < < " via in/exclude_eqs option " < < endl ;
2019-11-18 17:13:49 +01:00
return excluded_vars ;
}
2019-01-28 14:57:30 +01:00
void
ModelTree : : simplifyEquations ( )
{
size_t last_subst_table_size = 0 ;
2019-01-29 17:29:24 +01:00
map < VariableNode * , NumConstNode * > subst_table ;
2020-03-27 18:14:17 +01:00
// Equations with “mcp” tag are excluded, see dynare#1697
findConstantEquationsWithoutMcpTag ( subst_table ) ;
2019-01-28 14:57:30 +01:00
while ( subst_table . size ( ) ! = last_subst_table_size )
{
last_subst_table_size = subst_table . size ( ) ;
2021-02-19 20:11:33 +01:00
for ( auto & [ id , definition ] : local_variables_table )
definition = definition - > replaceVarsInEquation ( subst_table ) ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2019-01-28 14:57:30 +01:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > replaceVarsInEquation ( subst_table ) ) ;
subst_table . clear ( ) ;
2020-03-27 18:14:17 +01:00
findConstantEquationsWithoutMcpTag ( subst_table ) ;
2019-01-28 14:57:30 +01:00
}
}
void
2020-03-27 18:14:17 +01:00
ModelTree : : findConstantEquationsWithoutMcpTag ( map < VariableNode * , NumConstNode * > & subst_table ) const
2019-01-28 14:57:30 +01:00
{
2020-01-27 15:58:13 +01:00
for ( size_t i = 0 ; i < equations . size ( ) ; i + + )
2020-03-27 18:14:17 +01:00
if ( auto tags = getEquationTags ( i ) ;
tags . find ( " mcp " ) = = tags . end ( ) )
2020-01-27 15:58:13 +01:00
equations [ i ] - > findConstantEquations ( subst_table ) ;
2019-01-28 14:57:30 +01:00
}
2009-09-02 16:37:59 +02:00
void
2020-02-20 15:29:10 +01:00
ModelTree : : addEquation ( expr_t eq , int lineno , const map < string , string > & eq_tags )
2009-09-02 16:37:59 +02:00
{
2020-02-20 15:29:10 +01:00
equation_tags . add ( equations . size ( ) , eq_tags ) ;
2014-01-27 16:41:43 +01:00
addEquation ( eq , lineno ) ;
2009-09-02 16:37:59 +02:00
}
2009-09-30 17:10:31 +02:00
void
2010-09-16 19:18:45 +02:00
ModelTree : : addAuxEquation ( expr_t eq )
2009-09-30 17:10:31 +02:00
{
2019-12-16 19:42:59 +01:00
auto beq = dynamic_cast < BinaryOpNode * > ( eq ) ;
assert ( beq & & beq - > op_code = = BinaryOpcode : : equal ) ;
2009-09-30 17:10:31 +02:00
aux_equations . push_back ( beq ) ;
}
2010-10-15 19:05:16 +02:00
void
2019-07-05 18:36:10 +02:00
ModelTree : : addTrendVariables ( const vector < int > & trend_vars , expr_t growth_factor ) noexcept ( false )
2010-10-15 19:05:16 +02:00
{
2019-07-05 18:36:10 +02:00
for ( int id : trend_vars )
if ( trend_symbols_map . find ( id ) ! = trend_symbols_map . end ( ) )
throw TrendException ( symbol_table . getName ( id ) ) ;
2010-10-15 19:05:16 +02:00
else
2019-07-05 18:36:10 +02:00
trend_symbols_map [ id ] = growth_factor ;
2010-10-15 19:05:16 +02:00
}
void
2019-07-05 18:36:10 +02:00
ModelTree : : addNonstationaryVariables ( const vector < int > & nonstationary_vars , bool log_deflator , expr_t deflator ) noexcept ( false )
2010-10-15 19:05:16 +02:00
{
2019-07-05 18:36:10 +02:00
for ( int id : nonstationary_vars )
if ( nonstationary_symbols_map . find ( id ) ! = nonstationary_symbols_map . end ( ) )
throw TrendException ( symbol_table . getName ( id ) ) ;
2010-10-15 19:05:16 +02:00
else
2019-07-05 18:36:10 +02:00
nonstationary_symbols_map [ id ] = { log_deflator , deflator } ;
2010-10-15 19:05:16 +02:00
}
2011-06-22 11:56:07 +02:00
void
ModelTree : : initializeVariablesAndEquations ( )
{
2017-06-14 23:49:10 +02:00
for ( size_t j = 0 ; j < equations . size ( ) ; j + + )
2020-04-17 14:55:55 +02:00
eq_idx_block2orig . push_back ( j ) ;
2018-10-10 17:06:19 +02:00
for ( int j = 0 ; j < symbol_table . endo_nbr ( ) ; j + + )
2020-04-17 14:55:55 +02:00
endo_idx_block2orig . push_back ( j ) ;
2011-06-22 11:56:07 +02:00
}
void
ModelTree : : set_cutoff_to_zero ( )
{
cutoff = 0 ;
}
2011-08-19 15:05:57 +02:00
void
ModelTree : : jacobianHelper ( ostream & output , int eq_nb , int col_nb , ExprNodeOutputType output_type ) const
{
2018-09-05 18:27:13 +02:00
if ( isJuliaOutput ( output_type ) )
2018-03-27 17:14:30 +02:00
output < < " @inbounds " ;
2015-08-20 12:12:17 +02:00
output < < " g1 " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) ;
2018-09-05 18:27:13 +02:00
if ( isMatlabOutput ( output_type ) | | isJuliaOutput ( output_type ) )
2011-08-19 15:05:57 +02:00
output < < eq_nb + 1 < < " , " < < col_nb + 1 ;
else
output < < eq_nb + col_nb * equations . size ( ) ;
output < < RIGHT_ARRAY_SUBSCRIPT ( output_type ) ;
}
2012-11-29 18:07:48 +01:00
void
2016-05-18 12:26:19 +02:00
ModelTree : : computeParamsDerivatives ( int paramsDerivsOrder )
2012-11-29 18:07:48 +01:00
{
2018-11-22 15:41:11 +01:00
assert ( paramsDerivsOrder > = 1 ) ;
2012-11-29 18:07:48 +01:00
set < int > deriv_id_set ;
addAllParamDerivId ( deriv_id_set ) ;
2016-03-25 15:38:49 +01:00
2018-11-22 15:41:11 +01:00
// First-order derivatives w.r.t. params
2018-06-04 12:26:16 +02:00
for ( int param : deriv_id_set )
2012-11-29 18:07:48 +01:00
{
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2012-11-29 18:07:48 +01:00
{
2018-11-22 15:41:11 +01:00
expr_t d = equations [ eq ] - > getDerivative ( param ) ;
if ( d = = Zero )
2012-11-29 18:07:48 +01:00
continue ;
2018-11-22 15:41:11 +01:00
params_derivatives [ { 0 , 1 } ] [ { eq , param } ] = d ;
2012-11-29 18:07:48 +01:00
}
2019-04-23 11:07:32 +02:00
for ( int endoOrd = 1 ; endoOrd < static_cast < int > ( derivatives . size ( ) ) ; endoOrd + + )
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , dprev ] : derivatives [ endoOrd ] )
2016-05-12 12:02:34 +02:00
{
2019-12-16 19:42:59 +01:00
expr_t d = dprev - > getDerivative ( param ) ;
2018-11-22 15:41:11 +01:00
if ( d = = Zero )
2016-05-12 12:02:34 +02:00
continue ;
2019-12-16 19:42:59 +01:00
vector < int > new_indices = indices ;
new_indices . push_back ( param ) ;
params_derivatives [ { endoOrd , 1 } ] [ new_indices ] = d ;
2016-05-12 12:02:34 +02:00
}
2018-11-22 15:41:11 +01:00
}
2012-11-29 18:07:48 +01:00
2018-11-22 15:41:11 +01:00
// Higher-order derivatives w.r.t. parameters
2019-04-23 11:07:32 +02:00
for ( int endoOrd = 0 ; endoOrd < static_cast < int > ( derivatives . size ( ) ) ; endoOrd + + )
2018-11-22 15:41:11 +01:00
for ( int paramOrd = 2 ; paramOrd < = paramsDerivsOrder ; paramOrd + + )
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , dprev ] : params_derivatives [ { endoOrd , paramOrd - 1 } ] )
2018-11-22 15:41:11 +01:00
for ( int param : deriv_id_set )
{
2019-12-16 19:42:59 +01:00
if ( indices . back ( ) > param )
2018-11-22 15:41:11 +01:00
continue ;
2016-05-18 10:33:45 +02:00
2019-12-16 19:42:59 +01:00
expr_t d = dprev - > getDerivative ( param ) ;
2018-11-22 15:41:11 +01:00
if ( d = = Zero )
continue ;
2019-12-16 19:42:59 +01:00
vector < int > new_indices = indices ;
new_indices . push_back ( param ) ;
2018-11-22 15:41:11 +01:00
// At this point, indices of both endogenous and parameters are sorted in non-decreasing order
2019-12-16 19:42:59 +01:00
params_derivatives [ { endoOrd , paramOrd } ] [ new_indices ] = d ;
2018-11-22 15:41:11 +01:00
}
2012-11-29 18:07:48 +01:00
}
void
ModelTree : : computeParamsDerivativesTemporaryTerms ( )
{
2018-11-30 12:22:13 +01:00
map < expr_t , pair < int , pair < int , int > > > reference_count ;
2018-11-16 18:24:06 +01:00
/* The temp terms should be constructed in the same order as the for loops in
{ Static , Dynamic } Model : : write { Json , } ParamsDerivativesFile ( ) */
2018-11-30 12:22:13 +01:00
params_derivs_temporary_terms . clear ( ) ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ order , derivs ] : params_derivatives )
for ( const auto & [ indices , d ] : derivs )
d - > computeTemporaryTerms ( order , params_derivs_temporary_terms ,
reference_count , true ) ;
2018-05-28 15:23:15 +02:00
int idx = 0 ;
2019-12-16 19:42:59 +01:00
for ( auto & [ mlv , value ] : temporary_terms_mlv )
params_derivs_temporary_terms_idxs [ mlv ] = idx + + ;
for ( const auto & [ order , tts ] : params_derivs_temporary_terms )
for ( const auto & tt : tts )
2018-11-30 12:22:13 +01:00
params_derivs_temporary_terms_idxs [ tt ] = idx + + ;
2012-11-29 18:07:48 +01:00
}
2013-10-29 11:47:59 +01:00
2017-06-14 07:01:31 +02:00
bool
ModelTree : : isNonstationary ( int symb_id ) const
2013-10-29 11:47:59 +01:00
{
2019-12-16 19:42:59 +01:00
return nonstationary_symbols_map . find ( symb_id ) ! = nonstationary_symbols_map . end ( ) ;
2013-10-29 11:47:59 +01:00
}
2017-02-02 15:09:43 +01:00
void
2017-02-20 12:18:11 +01:00
ModelTree : : writeJsonModelEquations ( ostream & output , bool residuals ) const
2017-02-02 15:09:43 +01:00
{
2017-02-20 12:18:11 +01:00
if ( residuals )
2019-04-03 16:32:52 +02:00
output < < endl < < R " ( " residuals " :[) " < < endl ;
2017-02-20 12:18:11 +01:00
else
2019-04-03 16:32:52 +02:00
output < < endl < < R " ( " model " :[) " < < endl ;
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2017-02-02 15:09:43 +01:00
{
2017-02-20 12:18:11 +01:00
if ( eq > 0 )
output < < " , " ;
2017-03-15 12:52:55 +01:00
BinaryOpNode * eq_node = equations [ eq ] ;
2018-11-28 14:32:26 +01:00
expr_t lhs = eq_node - > arg1 ;
expr_t rhs = eq_node - > arg2 ;
2017-03-15 12:52:55 +01:00
2017-02-20 12:18:11 +01:00
if ( residuals )
2017-02-02 15:09:43 +01:00
{
2019-04-03 16:32:52 +02:00
output < < R " ({ " residual " : {) "
< < R " ( " lhs " : " ) " ;
2020-05-06 17:13:47 +02:00
lhs - > writeJsonOutput ( output , { } , { } ) ;
2019-04-03 16:32:52 +02:00
output < < R " ( " ) " ;
2017-02-20 12:18:11 +01:00
2019-04-03 16:32:52 +02:00
output < < R " (, " rhs " : " ) " ;
2020-05-06 17:13:47 +02:00
rhs - > writeJsonOutput ( output , { } , { } ) ;
2019-04-03 16:32:52 +02:00
output < < R " ( " ) " ;
2017-02-20 12:18:11 +01:00
try
{
// Test if the right hand side of the equation is empty.
2020-05-06 17:13:47 +02:00
if ( rhs - > eval ( { } ) ! = 0 )
2017-02-20 12:18:11 +01:00
{
2019-04-03 16:32:52 +02:00
output < < R " (, " rhs " : " ) " ;
2020-05-06 17:13:47 +02:00
rhs - > writeJsonOutput ( output , { } , { } ) ;
2019-04-03 16:32:52 +02:00
output < < R " ( " ) " ;
2017-02-20 12:18:11 +01:00
}
}
catch ( ExprNode : : EvalException & e )
2017-02-02 15:09:43 +01:00
{
}
output < < " } " ;
}
2017-02-20 12:18:11 +01:00
else
{
2019-04-03 16:32:52 +02:00
output < < R " ({ " lhs " : " ) " ;
2019-12-16 19:42:59 +01:00
lhs - > writeJsonOutput ( output , { } , { } ) ;
2019-04-03 16:32:52 +02:00
output < < R " ( " , " rhs " : " ) " ;
2019-12-16 19:42:59 +01:00
rhs - > writeJsonOutput ( output , { } , { } ) ;
2019-04-03 16:32:52 +02:00
output < < R " ( " ) "
< < R " (, " line " : ) " < < equations_lineno [ eq ] ;
2017-02-20 12:18:11 +01:00
2019-12-16 19:42:59 +01:00
if ( auto eqtags = getEquationTags ( eq ) ;
! eqtags . empty ( ) )
2017-02-20 12:18:11 +01:00
{
2019-04-03 16:32:52 +02:00
output < < R " (, " tags " : {) " ;
2017-02-20 12:18:11 +01:00
int i = 0 ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ name , value ] : eqtags )
2017-02-20 12:18:11 +01:00
{
if ( i ! = 0 )
output < < " , " ;
2019-12-16 19:42:59 +01:00
output < < R " ( " ) " << name << R " ( " : " ) " << value << R " ( " ) " ;
i + + ;
2017-02-20 12:18:11 +01:00
}
output < < " } " ;
eqtags . clear ( ) ;
}
}
output < < " } " < < endl ;
2017-02-02 15:09:43 +01:00
}
output < < endl < < " ] " < < endl ;
}
2018-10-26 11:44:26 +02:00
string
ModelTree : : matlab_arch ( const string & mexext )
{
if ( mexext = = " mexglx " )
return " glnx86 " ;
else if ( mexext = = " mexa64 " )
return " glnxa64 " ;
if ( mexext = = " mexw32 " )
return " win32 " ;
else if ( mexext = = " mexw64 " )
return " win64 " ;
else if ( mexext = = " mexmaci " )
2019-11-04 15:50:26 +01:00
{
cerr < < " 32-bit MATLAB not supported on macOS " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-10-26 11:44:26 +02:00
else if ( mexext = = " mexmaci64 " )
return " maci64 " ;
else
{
cerr < < " ERROR: 'mexext' option to preprocessor incorrectly set, needed with 'use_dll' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
void
2020-06-23 15:13:04 +02:00
ModelTree : : 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-26 11:44:26 +02:00
{
const string opt_flags = " -O3 -g0 --param ira-max-conflict-table-size=1 -fno-forward-propagate -fno-gcse -fno-dce -fno-dse -fno-tree-fre -fno-tree-pre -fno-tree-cselim -fno-tree-dse -fno-tree-dce -fno-tree-pta -fno-gcse-after-reload " ;
2019-04-04 17:01:37 +02:00
filesystem : : path compiler ;
2018-10-26 11:44:26 +02:00
ostringstream flags ;
string libs ;
2020-09-18 15:00:47 +02:00
if ( matlabroot . empty ( ) )
{
cerr < < " ERROR: 'matlabroot' option to preprocessor is not set, needed with 'use_dll' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-10-26 11:44:26 +02:00
if ( mexext = = " mex " )
{
// Octave
compiler = matlabroot / " bin " / " mkoctfile " ;
flags < < " --mex " ;
}
else
{
// MATLAB
compiler = " gcc " ;
string arch = matlab_arch ( mexext ) ;
auto include_dir = matlabroot / " extern " / " include " ;
flags < < " -I " < < include_dir ;
auto bin_dir = matlabroot / " bin " / arch ;
flags < < " -L " < < bin_dir ;
flags < < " -fexceptions -DNDEBUG " ;
2019-07-11 16:11:24 +02:00
libs = " -lmex -lmx " ;
2021-05-24 18:21:23 +02:00
if ( mexext = = " mexa64 " )
2018-10-26 11:44:26 +02:00
{
// GNU/Linux
flags < < " -D_GNU_SOURCE -fPIC -pthread "
< < " -shared -Wl,--no-undefined -Wl,-rpath-link, " < < bin_dir ;
2021-05-24 18:21:23 +02:00
libs + = " -lm " ;
2018-10-26 11:44:26 +02:00
}
2021-05-24 18:21:23 +02:00
else if ( mexext = = " mexw64 " )
2018-10-26 11:44:26 +02:00
{
// Windows
2021-05-24 18:21:23 +02:00
flags < < " -static-libgcc -shared " ;
2018-10-26 11:44:26 +02:00
// Put the MinGW environment shipped with Dynare in the path
2021-05-24 18:21:23 +02:00
auto mingwpath = dynareroot / " mingw64 " / " bin " ;
2018-10-26 11:44:26 +02:00
string newpath = " PATH= " + mingwpath . string ( ) + ' ; ' + string { getenv ( " PATH " ) } ;
if ( putenv ( const_cast < char * > ( newpath . c_str ( ) ) ) ! = 0 )
{
cerr < < " Can't set PATH " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2019-12-20 16:59:30 +01:00
}
2021-05-24 18:21:23 +02:00
# ifdef __APPLE__
else if ( mexext = = " mexmaci64 " )
2018-10-26 11:44:26 +02:00
{
// macOS
2019-11-04 15:50:26 +01:00
char dynare_m_path [ PATH_MAX ] ;
uint32_t size = PATH_MAX ;
2021-05-24 18:21:23 +02:00
string gcc_relative_path ;
2019-11-04 15:50:26 +01:00
if ( _NSGetExecutablePath ( dynare_m_path , & size ) = = 0 )
{
string str = dynare_m_path ;
2021-01-12 17:33:34 +01:00
gcc_relative_path = str . substr ( 0 , str . find_last_of ( " / " ) ) + " /../../.brew/bin/gcc-10 " ;
2019-11-04 15:50:26 +01:00
}
if ( filesystem : : exists ( gcc_relative_path ) )
compiler = gcc_relative_path ;
2021-01-12 17:33:34 +01:00
else if ( filesystem : : exists ( " /usr/local/bin/gcc-10 " ) )
compiler = " /usr/local/bin/gcc-10 " ;
2019-11-04 15:50:26 +01:00
else
{
2021-01-12 17:33:34 +01:00
cerr < < " ERROR: You must install gcc-10 on your system before using the `use_dll` option of Dynare. "
2019-11-04 15:50:26 +01:00
< < " You can do this via the Dynare installation package. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2021-01-12 17:34:44 +01:00
flags < < " -fno-common -Wl,-twolevel_namespace -undefined error -bundle " ;
2021-05-24 18:21:23 +02:00
libs + = " -lm " ;
}
# endif
else
{
cerr < < " ERROR: unsupported value ' " < < mexext < < " ' for 'mexext' option " < < endl ;
exit ( EXIT_FAILURE ) ;
2018-10-26 11:44:26 +02:00
}
}
2019-04-04 17:01:37 +02:00
filesystem : : path mex_dir { " + " + basename } ;
2020-05-29 16:12:01 +02:00
filesystem : : path binary { mex_dir / ( funcname + " . " + mexext ) } ;
2018-10-26 11:44:26 +02:00
ostringstream cmd ;
# ifdef _WIN32
/* On Windows, system() hands the command over to "cmd.exe /C". We need to
enclose the whole command line within double quotes if we want the inner
quotes to be correctly handled . See " cmd /? " for more details . */
cmd < < ' " ' ;
# endif
2019-12-02 19:21:14 +01:00
if ( user_set_compiler . empty ( ) )
cmd < < compiler < < " " ;
else
if ( ! filesystem : : exists ( user_set_compiler ) )
{
cerr < < " Error: The specified compiler ' " < < user_set_compiler < < " ' cannot be found on your system " < < endl ;
exit ( EXIT_FAILURE ) ;
}
else
cmd < < user_set_compiler < < " " ;
if ( user_set_subst_flags . empty ( ) )
cmd < < opt_flags < < " " < < flags . str ( ) < < " " ;
else
cmd < < user_set_subst_flags < < " " ;
if ( ! user_set_add_flags . empty ( ) )
cmd < < user_set_add_flags < < " " ;
2020-06-23 15:13:04 +02:00
for ( auto & src : src_files )
cmd < < src < < " " ;
cmd < < " -o " < < binary < < " " ;
2019-12-02 19:21:14 +01:00
if ( user_set_subst_libs . empty ( ) )
cmd < < libs ;
else
cmd < < user_set_subst_libs ;
if ( ! user_set_add_libs . empty ( ) )
cmd < < " " < < user_set_add_libs ;
2018-10-26 11:44:26 +02:00
# ifdef _WIN32
cmd < < ' " ' ;
# endif
2020-05-29 16:12:01 +02:00
cout < < " Compiling " < < funcname < < " MEX... " < < endl < < cmd . str ( ) < < endl ;
2018-10-26 11:44:26 +02:00
if ( system ( cmd . str ( ) . c_str ( ) ) )
{
cerr < < " Compilation failed " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2019-12-03 14:19:32 +01:00
void
ModelTree : : reorderAuxiliaryEquations ( )
{
using namespace boost ;
// Create the mapping between auxiliary variables and auxiliary equations
int n = static_cast < int > ( aux_equations . size ( ) ) ;
map < int , int > auxEndoToEq ;
for ( int i = 0 ; i < n ; i + + )
{
auto varexpr = dynamic_cast < VariableNode * > ( aux_equations [ i ] - > arg1 ) ;
assert ( varexpr & & symbol_table . getType ( varexpr - > symb_id ) = = SymbolType : : endogenous ) ;
auxEndoToEq [ varexpr - > symb_id ] = i ;
}
assert ( static_cast < int > ( auxEndoToEq . size ( ) ) = = n ) ;
/* Construct the directed acyclic graph where auxiliary equations are
vertices and edges represent dependency relationships . */
using Graph = adjacency_list < vecS , vecS , directedS > ;
Graph g ( n ) ;
for ( int i = 0 ; i < n ; i + + )
{
set < int > endos ;
aux_equations [ i ] - > collectVariables ( SymbolType : : endogenous , endos ) ;
for ( int endo : endos )
2019-12-16 19:42:59 +01:00
if ( auto it = auxEndoToEq . find ( endo ) ;
it ! = auxEndoToEq . end ( ) & & it - > second ! = i )
add_edge ( i , it - > second , g ) ;
2019-12-03 14:19:32 +01:00
}
// Topological sort of the graph
using Vertex = graph_traits < Graph > : : vertex_descriptor ;
vector < Vertex > ordered ;
topological_sort ( g , back_inserter ( ordered ) ) ;
// Reorder auxiliary equations accordingly
auto aux_equations_old = aux_equations ;
auto index = get ( vertex_index , g ) ; // Maps vertex descriptors to their index
for ( int i = 0 ; i < n ; i + + )
aux_equations [ i ] = aux_equations_old [ index [ ordered [ i ] ] ] ;
}
2020-03-30 14:51:53 +02:00
map < tuple < int , int , int > , expr_t >
ModelTree : : collectFirstOrderDerivativesEndogenous ( )
{
map < tuple < int , int , int > , expr_t > endo_derivatives ;
for ( auto & [ indices , d1 ] : derivatives [ 1 ] )
if ( getTypeByDerivID ( indices [ 1 ] ) = = SymbolType : : endogenous )
{
int eq = indices [ 0 ] ;
int var = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( indices [ 1 ] ) ) ;
int lag = getLagByDerivID ( indices [ 1 ] ) ;
endo_derivatives [ { eq , var , lag } ] = d1 ;
}
return endo_derivatives ;
}
2020-04-15 17:56:28 +02:00
ModelTree : : jacob_map_t
ModelTree : : computeSymbolicJacobian ( ) const
{
jacob_map_t symbolic_jacobian ;
for ( int i = 0 ; i < static_cast < int > ( equations . size ( ) ) ; i + + )
{
set < pair < int , int > > endos_and_lags ;
equations [ i ] - > collectEndogenous ( endos_and_lags ) ;
for ( const auto & [ endo , lag ] : endos_and_lags )
symbolic_jacobian [ { i , endo } ] = 1 ;
}
return symbolic_jacobian ;
}
void
ModelTree : : updateReverseVariableEquationOrderings ( )
{
int n = equations . size ( ) ;
2020-04-17 14:55:55 +02:00
eq_idx_orig2block . resize ( n ) ;
endo_idx_orig2block . resize ( n ) ;
2020-04-15 17:56:28 +02:00
for ( int i = 0 ; i < n ; i + + )
{
2020-04-17 14:55:55 +02:00
endo_idx_orig2block [ endo_idx_block2orig [ i ] ] = i ;
eq_idx_orig2block [ eq_idx_block2orig [ i ] ] = i ;
2020-04-15 17:56:28 +02:00
}
}
2021-02-22 18:26:21 +01:00
bool
ModelTree : : hasOccbinTags ( ) const
{
return equation_tags . hasOccbinTags ( ) ;
}