2009-04-14 16:39:53 +02:00
/*
2023-01-04 16:03:12 +01:00
* Copyright © 2003 - 2023 Dynare Team
2009-04-14 16:39:53 +02: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/>.
2009-04-14 16:39:53 +02:00
*/
2009-07-06 12:36:36 +02:00
# include <iostream>
2009-04-14 16:39:53 +02:00
# include <cmath>
2009-04-14 16:47:57 +02:00
# include <cstdlib>
2009-04-28 18:21:39 +02:00
# include <cassert>
2009-12-16 14:21:31 +01:00
# include <algorithm>
2018-06-07 12:53:00 +02:00
# include <numeric>
2019-11-18 17:13:49 +01:00
# include <regex>
2021-04-23 17:30:38 +02:00
# include <sstream>
2022-10-04 16:34:43 +02:00
# include <string_view>
2009-04-14 16:39:53 +02:00
2018-06-27 15:01:31 +02:00
# include "DynamicModel.hh"
2021-07-20 18:18:24 +02:00
# include "ParsingDriver.hh"
2009-04-14 16:39:53 +02:00
2018-10-09 18:27:19 +02:00
void
DynamicModel : : copyHelper ( const DynamicModel & m )
{
2018-10-10 13:07:25 +02:00
auto f = [ this ] ( const ExprNode * e ) { return e - > clone ( * this ) ; } ;
2018-10-09 18:27:19 +02:00
for ( const auto & it : m . static_only_equations )
static_only_equations . push_back ( dynamic_cast < BinaryOpNode * > ( f ( it ) ) ) ;
2020-04-30 16:00:16 +02:00
2022-01-06 14:46:38 +01:00
auto convert_block_derivative = [ f ] ( const map < tuple < int , int , int > , expr_t > & dt )
2020-04-30 16:00:16 +02:00
{
map < tuple < int , int , int > , expr_t > dt2 ;
for ( const auto & it : dt )
2022-09-21 15:13:41 +02:00
dt2 . emplace ( it . first , f ( it . second ) ) ;
2020-04-30 16:00:16 +02:00
return dt2 ;
} ;
for ( const auto & it : m . blocks_derivatives_other_endo )
blocks_derivatives_other_endo . emplace_back ( convert_block_derivative ( it ) ) ;
for ( const auto & it : m . blocks_derivatives_exo )
blocks_derivatives_exo . emplace_back ( convert_block_derivative ( it ) ) ;
for ( const auto & it : m . blocks_derivatives_exo_det )
blocks_derivatives_exo_det . emplace_back ( convert_block_derivative ( it ) ) ;
2018-10-09 18:27:19 +02:00
}
2009-04-14 16:39:53 +02:00
DynamicModel : : DynamicModel ( SymbolTable & symbol_table_arg ,
2010-02-22 17:33:38 +01:00
NumericalConstants & num_constants_arg ,
2018-08-14 14:23:21 +02:00
ExternalFunctionsTable & external_functions_table_arg ,
2018-08-21 11:46:59 +02:00
TrendComponentModelTable & trend_component_model_table_arg ,
VarModelTable & var_model_table_arg ) :
2019-12-20 16:59:30 +01:00
ModelTree { symbol_table_arg , num_constants_arg , external_functions_table_arg , true } ,
2018-10-04 17:18:27 +02:00
trend_component_model_table { trend_component_model_table_arg } ,
var_model_table { var_model_table_arg }
2009-04-14 16:39:53 +02:00
{
}
2018-10-09 18:27:19 +02:00
DynamicModel : : DynamicModel ( const DynamicModel & m ) :
2019-12-20 16:59:30 +01:00
ModelTree { m } ,
trend_component_model_table { m . trend_component_model_table } ,
var_model_table { m . var_model_table } ,
balanced_growth_test_tol { m . balanced_growth_test_tol } ,
static_only_equations_lineno { m . static_only_equations_lineno } ,
static_only_equations_equation_tags { m . static_only_equations_equation_tags } ,
deriv_id_table { m . deriv_id_table } ,
inv_deriv_id_table { m . inv_deriv_id_table } ,
dyn_jacobian_cols_table { m . dyn_jacobian_cols_table } ,
max_lag { m . max_lag } ,
max_lead { m . max_lead } ,
max_endo_lag { m . max_endo_lag } ,
max_endo_lead { m . max_endo_lead } ,
max_exo_lag { m . max_exo_lag } ,
max_exo_lead { m . max_exo_lead } ,
max_exo_det_lag { m . max_exo_det_lag } ,
max_exo_det_lead { m . max_exo_det_lead } ,
max_lag_orig { m . max_lag_orig } ,
max_lead_orig { m . max_lead_orig } ,
max_lag_with_diffs_expanded_orig { m . max_lag_with_diffs_expanded_orig } ,
max_endo_lag_orig { m . max_endo_lag_orig } ,
max_endo_lead_orig { m . max_endo_lead_orig } ,
max_exo_lag_orig { m . max_exo_lag_orig } ,
max_exo_lead_orig { m . max_exo_lead_orig } ,
max_exo_det_lag_orig { m . max_exo_det_lag_orig } ,
max_exo_det_lead_orig { m . max_exo_det_lead_orig } ,
xrefs { m . xrefs } ,
xref_param { m . xref_param } ,
xref_endo { m . xref_endo } ,
xref_exo { m . xref_exo } ,
xref_exo_det { m . xref_exo_det } ,
nonzero_hessian_eqs { m . nonzero_hessian_eqs } ,
2020-04-30 14:57:50 +02:00
variableMapping { m . variableMapping } ,
2020-05-06 14:02:58 +02:00
blocks_other_endo { m . blocks_other_endo } ,
blocks_exo { m . blocks_exo } ,
blocks_exo_det { m . blocks_exo_det } ,
blocks_jacob_cols_endo { m . blocks_jacob_cols_endo } ,
blocks_jacob_cols_other_endo { m . blocks_jacob_cols_other_endo } ,
blocks_jacob_cols_exo { m . blocks_jacob_cols_exo } ,
blocks_jacob_cols_exo_det { m . blocks_jacob_cols_exo_det } ,
2021-10-27 18:17:14 +02:00
var_expectation_functions_to_write { m . var_expectation_functions_to_write }
2009-04-16 12:33:30 +02:00
{
2018-10-09 18:27:19 +02:00
copyHelper ( m ) ;
}
DynamicModel &
DynamicModel : : operator = ( const DynamicModel & m )
{
ModelTree : : operator = ( m ) ;
assert ( & trend_component_model_table = = & m . trend_component_model_table ) ;
assert ( & var_model_table = = & m . var_model_table ) ;
2019-11-14 17:51:16 +01:00
balanced_growth_test_tol = m . balanced_growth_test_tol ;
2018-10-09 18:27:19 +02:00
static_only_equations_lineno = m . static_only_equations_lineno ;
static_only_equations_equation_tags = m . static_only_equations_equation_tags ;
deriv_id_table = m . deriv_id_table ;
inv_deriv_id_table = m . inv_deriv_id_table ;
dyn_jacobian_cols_table = m . dyn_jacobian_cols_table ;
max_lag = m . max_lag ;
max_lead = m . max_lead ;
max_endo_lag = m . max_endo_lag ;
max_endo_lead = m . max_endo_lead ;
max_exo_lag = m . max_exo_lag ;
max_exo_lead = m . max_exo_lead ;
max_exo_det_lag = m . max_exo_det_lag ;
max_exo_det_lead = m . max_exo_det_lead ;
max_lag_orig = m . max_lag_orig ;
max_lead_orig = m . max_lead_orig ;
2018-12-11 17:26:50 +01:00
max_lag_with_diffs_expanded_orig = m . max_lag_with_diffs_expanded_orig ;
2018-10-09 18:27:19 +02:00
max_endo_lag_orig = m . max_endo_lag_orig ;
max_endo_lead_orig = m . max_endo_lead_orig ;
max_exo_lag_orig = m . max_exo_lag_orig ;
max_exo_lead_orig = m . max_exo_lead_orig ;
max_exo_det_lag_orig = m . max_exo_det_lag_orig ;
max_exo_det_lead_orig = m . max_exo_det_lead_orig ;
xrefs = m . xrefs ;
2019-12-20 16:59:30 +01:00
xref_param = m . xref_param ;
2018-10-09 18:27:19 +02:00
xref_endo = m . xref_endo ;
xref_exo = m . xref_exo ;
xref_exo_det = m . xref_exo_det ;
nonzero_hessian_eqs = m . nonzero_hessian_eqs ;
2020-04-30 14:57:50 +02:00
variableMapping = m . variableMapping ;
2020-04-30 16:00:16 +02:00
blocks_derivatives_other_endo . clear ( ) ;
blocks_derivatives_exo . clear ( ) ;
blocks_derivatives_exo_det . clear ( ) ;
2020-05-06 14:02:58 +02:00
blocks_other_endo = m . blocks_other_endo ;
blocks_exo = m . blocks_exo ;
blocks_exo_det = m . blocks_exo_det ;
blocks_jacob_cols_endo = m . blocks_jacob_cols_endo ;
blocks_jacob_cols_other_endo = m . blocks_jacob_cols_other_endo ;
blocks_jacob_cols_exo = m . blocks_jacob_cols_exo ;
blocks_jacob_cols_exo_det = m . blocks_jacob_cols_exo_det ;
2018-10-09 18:27:19 +02:00
var_expectation_functions_to_write = m . var_expectation_functions_to_write ;
copyHelper ( m ) ;
return * this ;
2009-04-16 12:33:30 +02:00
}
2009-04-14 16:39:53 +02:00
void
2020-05-06 17:13:47 +02:00
DynamicModel : : 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
2009-04-14 16:39:53 +02:00
{
2020-05-06 17:13:47 +02:00
for ( const auto & [ ignore , d ] : blocks_derivatives_exo [ 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
for ( const auto & [ ignore , d ] : blocks_derivatives_exo_det [ 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
for ( const auto & [ ignore , d ] : blocks_derivatives_other_endo [ blk ] )
2020-05-13 16:58:19 +02:00
d - > computeBlockTemporaryTerms ( blk , blocks [ blk ] . size , blocks_temporary_terms , reference_count ) ;
2010-01-22 11:03:29 +01:00
}
2022-07-19 18:24:36 +02:00
void
DynamicModel : : writeBlockBytecodeAdditionalDerivatives ( BytecodeWriter & code_file , int block ,
const temporary_terms_t & temporary_terms_union ,
const deriv_node_temp_terms_t & tef_terms ) const
{
constexpr ExprNodeBytecodeOutputType output_type { ExprNodeBytecodeOutputType : : dynamicModel } ;
/* FIXME: there is an inconsistency between endos and the following 3 other
variable types . For the latter , the index of equation within the block is
taken from FNUMEXPR , while it is taken from FSTPG3 for the former . */
for ( const auto & [ indices , d ] : blocks_derivatives_exo [ block ] )
{
const auto & [ eq , var , lag ] { indices } ;
code_file < < FNUMEXPR_ { ExpressionType : : FirstExoDerivative , eq , 0 , lag } ;
d - > writeBytecodeOutput ( code_file , output_type , temporary_terms_union , blocks_temporary_terms_idxs , tef_terms ) ;
code_file < < FSTPG3_ { eq , var , lag , blocks_jacob_cols_exo [ block ] . at ( { var , lag } ) } ;
}
for ( const auto & [ indices , d ] : blocks_derivatives_exo_det [ block ] )
{
const auto & [ eq , var , lag ] { indices } ;
code_file < < FNUMEXPR_ { ExpressionType : : FirstExodetDerivative , eq , 0 , lag } ;
d - > writeBytecodeOutput ( code_file , output_type , temporary_terms_union , blocks_temporary_terms_idxs , tef_terms ) ;
code_file < < FSTPG3_ { eq , var , lag , blocks_jacob_cols_exo_det [ block ] . at ( { var , lag } ) } ;
}
for ( const auto & [ indices , d ] : blocks_derivatives_other_endo [ block ] )
{
const auto & [ eq , var , lag ] { indices } ;
code_file < < FNUMEXPR_ { ExpressionType : : FirstOtherEndoDerivative , eq , 0 , lag } ;
d - > writeBytecodeOutput ( code_file , output_type , temporary_terms_union , blocks_temporary_terms_idxs , tef_terms ) ;
code_file < < FSTPG3_ { eq , var , lag , blocks_jacob_cols_other_endo [ block ] . at ( { var , lag } ) } ;
}
}
2009-04-14 16:39:53 +02:00
void
2020-05-19 17:43:35 +02:00
DynamicModel : : writeDynamicBytecode ( const string & basename ) const
2010-01-22 11:03:29 +01:00
{
2022-07-13 13:04:10 +02:00
// Determine the type of model (used for typing the single block)
2010-01-22 11:03:29 +01:00
BlockSimulationType simulation_type ;
2022-07-13 13:04:10 +02:00
if ( max_endo_lag > 0 & & max_endo_lead > 0 )
2020-03-20 17:31:14 +01:00
simulation_type = BlockSimulationType : : solveTwoBoundariesComplete ;
2022-07-13 13:04:10 +02:00
else if ( max_endo_lag > = 0 & & max_endo_lead = = 0 )
2020-03-20 17:31:14 +01:00
simulation_type = BlockSimulationType : : solveForwardComplete ;
2010-01-22 11:03:29 +01:00
else
2020-03-20 17:31:14 +01:00
simulation_type = BlockSimulationType : : solveBackwardComplete ;
2010-01-22 11:03:29 +01:00
2022-07-13 13:04:10 +02:00
// First write the .bin file
int u_count_int { writeBytecodeBinFile ( basename + " /model/bytecode/dynamic.bin " ,
simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete ) } ;
2010-01-22 11:03:29 +01:00
2022-07-13 13:04:10 +02:00
BytecodeWriter code_file { basename + " /model/bytecode/dynamic.cod " } ;
2010-07-23 11:20:24 +02:00
2022-07-13 13:04:10 +02:00
// Declare temporary terms
code_file < < FDIMT_ { static_cast < int > ( temporary_terms_derivatives [ 0 ] . size ( )
+ temporary_terms_derivatives [ 1 ] . size ( ) ) } ;
2010-01-22 11:03:29 +01:00
2022-07-13 13:04:10 +02:00
// Declare the (single) block
vector < int > exo ( symbol_table . exo_nbr ( ) ) , exo_det ( symbol_table . exo_det_nbr ( ) ) ;
iota ( exo . begin ( ) , exo . end ( ) , 0 ) ;
iota ( exo_det . begin ( ) , exo_det . end ( ) , 0 ) ;
2010-10-27 15:34:48 +02:00
2022-07-13 13:04:10 +02:00
int jacobian_ncols_endo
{ static_cast < int > ( count_if ( dyn_jacobian_cols_table . begin ( ) , dyn_jacobian_cols_table . end ( ) ,
[ this ] ( const auto & v )
{ return getTypeByDerivID ( v . first ) = = SymbolType : : endogenous ; } ) )
} ;
int jacobian_ncols_exo { symbol_table . exo_nbr ( ) } ;
int jacobian_ncols_exo_det { symbol_table . exo_det_nbr ( ) } ;
2022-09-13 15:43:13 +02:00
vector < int > eq_idx ( equations . size ( ) ) ;
iota ( eq_idx . begin ( ) , eq_idx . end ( ) , 0 ) ;
vector < int > endo_idx ( symbol_table . endo_nbr ( ) ) ;
iota ( endo_idx . begin ( ) , endo_idx . end ( ) , 0 ) ;
2017-06-01 19:58:32 +02:00
2022-06-23 14:28:13 +02:00
code_file < < FBEGINBLOCK_ { symbol_table . endo_nbr ( ) ,
2022-07-13 13:04:10 +02:00
simulation_type ,
0 ,
symbol_table . endo_nbr ( ) ,
2022-09-13 15:43:13 +02:00
endo_idx ,
eq_idx ,
2022-07-13 13:04:10 +02:00
false ,
symbol_table . endo_nbr ( ) ,
max_endo_lag ,
max_endo_lead ,
u_count_int ,
jacobian_ncols_endo ,
symbol_table . exo_det_nbr ( ) ,
jacobian_ncols_exo_det ,
symbol_table . exo_nbr ( ) ,
jacobian_ncols_exo ,
0 ,
0 ,
exo_det ,
exo ,
{ } } ;
writeBytecodeHelper < true > ( code_file ) ;
2010-01-22 11:03:29 +01:00
}
void
2021-01-25 18:03:37 +01:00
DynamicModel : : writeDynamicBlockBytecode ( const string & basename ) const
2009-12-16 18:13:23 +01:00
{
2023-01-09 13:35:49 +01:00
BytecodeWriter code_file { basename + " /model/bytecode/block/dynamic.cod " } ;
2009-12-16 18:13:23 +01:00
2023-01-09 13:35:49 +01:00
const filesystem : : path bin_filename { basename + " /model/bytecode/block/dynamic.bin " } ;
2022-07-19 18:24:36 +02:00
ofstream bin_file { bin_filename , ios : : out | ios : : binary } ;
if ( ! bin_file . is_open ( ) )
2009-12-16 18:13:23 +01:00
{
2023-01-05 16:40:04 +01:00
cerr < < R " (Error : Can't open file " ) " << bin_filename.string() << R " ( " for writing) " < < endl ;
2022-07-19 18:24:36 +02:00
exit ( EXIT_FAILURE ) ;
}
2022-02-18 12:37:37 +01:00
2022-07-19 18:24:36 +02:00
// Temporary variables declaration
code_file < < FDIMT_ { static_cast < int > ( blocks_temporary_terms_idxs . size ( ) ) } ;
2010-07-23 11:20:24 +02:00
2022-07-19 18:24:36 +02:00
for ( int block { 0 } ; block < static_cast < int > ( blocks . size ( ) ) ; block + + )
{
const BlockSimulationType simulation_type { blocks [ block ] . simulation_type } ;
// Write section of .bin file except for evaluate blocks and solve simple blocks
const int u_count { simulation_type = = BlockSimulationType : : solveTwoBoundariesSimple
| | simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete
| | simulation_type = = BlockSimulationType : : solveBackwardComplete
| | simulation_type = = BlockSimulationType : : solveForwardComplete
? writeBlockBytecodeBinFile ( bin_file , block )
: 0 } ;
code_file < < FBEGINBLOCK_ { blocks [ block ] . mfs_size ,
simulation_type ,
blocks [ block ] . first_equation ,
blocks [ block ] . size ,
endo_idx_block2orig ,
eq_idx_block2orig ,
blocks [ block ] . linear ,
symbol_table . endo_nbr ( ) ,
blocks [ block ] . max_lag ,
blocks [ block ] . max_lead ,
u_count ,
static_cast < int > ( blocks_jacob_cols_endo [ block ] . size ( ) ) ,
static_cast < int > ( blocks_exo_det [ block ] . size ( ) ) ,
static_cast < int > ( blocks_jacob_cols_exo_det [ block ] . size ( ) ) ,
static_cast < int > ( blocks_exo [ block ] . size ( ) ) ,
static_cast < int > ( blocks_jacob_cols_exo [ block ] . size ( ) ) ,
static_cast < int > ( blocks_other_endo [ block ] . size ( ) ) ,
static_cast < int > ( blocks_jacob_cols_other_endo [ block ] . size ( ) ) ,
{ blocks_exo_det [ block ] . begin ( ) , blocks_exo_det [ block ] . end ( ) } ,
{ blocks_exo [ block ] . begin ( ) , blocks_exo [ block ] . end ( ) } ,
{ blocks_other_endo [ block ] . begin ( ) , blocks_other_endo [ block ] . end ( ) } } ;
writeBlockBytecodeHelper < true > ( code_file , block ) ;
2009-12-16 18:13:23 +01:00
}
2022-07-19 18:24:36 +02:00
code_file < < FEND_ { } ;
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
void
2018-06-27 15:01:31 +02:00
DynamicModel : : writeDynamicMFile ( const string & basename ) const
2009-12-16 18:13:23 +01:00
{
2022-07-11 17:33:09 +02:00
auto [ d_output , tt_output ] = writeModelFileHelper < ExprNodeOutputType : : matlabDynamicModel > ( ) ;
ostringstream init_output , end_output ;
init_output < < " residual = zeros( " < < equations . size ( ) < < " , 1); " ;
2022-07-12 17:04:41 +02:00
writeDynamicMFileHelper ( basename , " dynamic_resid " , " residual " , " dynamic_resid_tt " ,
2022-09-26 14:53:36 +02:00
temporary_terms_derivatives [ 0 ] . size ( ) ,
2022-07-12 17:04:41 +02:00
" " , init_output , end_output , d_output [ 0 ] , tt_output [ 0 ] ) ;
2022-07-11 17:33:09 +02:00
init_output . str ( " " ) ;
2022-09-14 17:07:08 +02:00
init_output < < " g1 = zeros( " < < equations . size ( ) < < " , " < < getJacobianColsNbr ( false ) < < " ); " ;
2022-07-12 17:04:41 +02:00
writeDynamicMFileHelper ( basename , " dynamic_g1 " , " g1 " , " dynamic_g1_tt " ,
2022-09-26 14:53:36 +02:00
temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) ,
2022-07-12 17:04:41 +02:00
" dynamic_resid_tt " , init_output , end_output , d_output [ 1 ] , tt_output [ 1 ] ) ;
writeDynamicMWrapperFunction ( basename , " g1 " ) ;
2022-07-11 17:33:09 +02:00
// For order ≥ 2
2022-09-14 17:07:08 +02:00
int ncols { getJacobianColsNbr ( false ) } ;
int ntt { static_cast < int > ( temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) ) } ;
2022-07-11 17:33:09 +02:00
for ( size_t i { 2 } ; i < derivatives . size ( ) ; i + + )
{
2022-09-14 17:07:08 +02:00
ncols * = getJacobianColsNbr ( false ) ;
2022-07-11 17:33:09 +02:00
ntt + = temporary_terms_derivatives [ i ] . size ( ) ;
string gname { " g " + to_string ( i ) } ;
string gprevname { " g " + to_string ( i - 1 ) } ;
init_output . str ( " " ) ;
end_output . str ( " " ) ;
if ( derivatives [ i ] . size ( ) )
{
init_output < < gname < < " _i = zeros( " < < NNZDerivatives [ i ] < < " ,1); " < < endl
< < gname < < " _j = zeros( " < < NNZDerivatives [ i ] < < " ,1); " < < endl
< < gname < < " _v = zeros( " < < NNZDerivatives [ i ] < < " ,1); " < < endl ;
end_output < < gname < < " = sparse( "
< < gname < < " _i, " < < gname < < " _j, " < < gname < < " _v, "
< < equations . size ( ) < < " , " < < ncols < < " ); " ;
}
else
init_output < < gname < < " = sparse([],[],[], " < < equations . size ( ) < < " , " < < ncols < < " ); " ;
2022-07-12 17:04:41 +02:00
writeDynamicMFileHelper ( basename , " dynamic_ " + gname , gname , " dynamic_ " + gname + " _tt " , ntt ,
" dynamic_ " + gprevname + " _tt " , init_output , end_output ,
2022-07-11 17:33:09 +02:00
d_output [ i ] , tt_output [ i ] ) ;
if ( i < = 3 )
2022-07-12 17:04:41 +02:00
writeDynamicMWrapperFunction ( basename , gname ) ;
2022-07-11 17:33:09 +02:00
}
2022-07-12 17:04:41 +02:00
writeDynamicMCompatFile ( basename ) ;
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
string
2019-12-16 19:42:59 +01:00
DynamicModel : : reform ( const string & name1 ) const
2009-12-16 18:13:23 +01:00
{
string name = name1 ;
2019-04-03 16:32:52 +02:00
int pos = name . find ( R " ( \ ) " , 0 ) ;
2009-12-16 18:13:23 +01:00
while ( pos > = 0 )
{
2019-04-03 16:32:52 +02:00
if ( name . substr ( pos + 1 , 1 ) ! = R " ( \ ) " )
2009-12-16 18:13:23 +01:00
{
2019-04-03 16:32:52 +02:00
name = name . insert ( pos , R " ( \ ) " ) ;
2009-12-16 18:13:23 +01:00
pos + + ;
}
pos + + ;
2019-04-03 16:32:52 +02:00
pos = name . find ( R " ( \ ) " , pos ) ;
2009-12-16 18:13:23 +01:00
}
2019-12-16 19:42:59 +01:00
return name ;
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
2016-07-27 21:01:54 +02:00
void
2018-01-11 12:55:36 +01:00
DynamicModel : : printNonZeroHessianEquations ( ostream & output ) const
{
2019-12-16 19:42:59 +01:00
if ( nonzero_hessian_eqs . size ( ) ! = 1 )
2018-01-11 12:55:36 +01:00
output < < " [ " ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
int it : nonzero_hessian_eqs )
2018-01-11 12:55:36 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2018-01-11 12:55:36 +01:00
output < < " " ;
2022-06-03 16:24:26 +02:00
output < < it + 1 ;
2018-01-11 12:55:36 +01:00
}
if ( nonzero_hessian_eqs . size ( ) ! = 1 )
output < < " ] " ;
}
2018-03-27 17:14:30 +02:00
void
2022-07-12 17:04:41 +02:00
DynamicModel : : writeDynamicMWrapperFunction ( const string & basename , const string & ending ) const
2018-03-27 17:14:30 +02:00
{
string name ;
if ( ending = = " g1 " )
2018-06-27 15:01:31 +02:00
name = " dynamic_resid_g1 " ;
2018-03-27 17:14:30 +02:00
else if ( ending = = " g2 " )
2019-12-20 16:59:30 +01:00
name = " dynamic_resid_g1_g2 " ;
2018-03-27 17:14:30 +02:00
else if ( ending = = " g3 " )
2018-06-27 15:01:31 +02:00
name = " dynamic_resid_g1_g2_g3 " ;
2018-03-27 17:14:30 +02:00
2022-10-11 15:59:56 +02:00
filesystem : : path filename { packageDir ( basename ) / ( name + " .m " ) } ;
2022-07-11 16:09:07 +02:00
ofstream output { filename , ios : : out | ios : : binary } ;
2018-03-27 17:14:30 +02:00
if ( ! output . is_open ( ) )
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2018-03-27 17:14:30 +02:00
exit ( EXIT_FAILURE ) ;
}
if ( ending = = " g1 " )
2018-05-23 17:32:50 +02:00
output < < " function [residual, g1] = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl
< < " % function [residual, g1] = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl ;
2018-03-27 17:14:30 +02:00
else if ( ending = = " g2 " )
2018-05-23 17:32:50 +02:00
output < < " function [residual, g1, g2] = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl
< < " % function [residual, g1, g2] = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl ;
2018-03-27 17:14:30 +02:00
else if ( ending = = " g3 " )
2018-05-23 17:32:50 +02:00
output < < " function [residual, g1, g2, g3] = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl
< < " % function [residual, g1, g2, g3] = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl ;
2018-03-27 17:14:30 +02:00
output < < " % " < < endl
< < " % Wrapper function automatically created by Dynare " < < endl
2018-05-23 17:32:50 +02:00
< < " % " < < endl
< < endl
< < " if T_flag " < < endl
2018-06-27 15:01:31 +02:00
< < " T = " < < basename < < " .dynamic_ " < < ending < < " _tt(T, y, x, params, steady_state, it_); " < < endl
2018-05-23 17:32:50 +02:00
< < " end " < < endl ;
2018-03-27 17:14:30 +02:00
if ( ending = = " g1 " )
2018-06-27 15:01:31 +02:00
output < < " residual = " < < basename < < " .dynamic_resid(T, y, x, params, steady_state, it_, false); " < < endl
< < " g1 = " < < basename < < " .dynamic_g1(T, y, x, params, steady_state, it_, false); " < < endl ;
2018-03-27 17:14:30 +02:00
else if ( ending = = " g2 " )
2018-06-27 15:01:31 +02:00
output < < " [residual, g1] = " < < basename < < " .dynamic_resid_g1(T, y, x, params, steady_state, it_, false); " < < endl
< < " g2 = " < < basename < < " .dynamic_g2(T, y, x, params, steady_state, it_, false); " < < endl ;
2018-03-27 17:14:30 +02:00
else if ( ending = = " g3 " )
2018-06-27 15:01:31 +02:00
output < < " [residual, g1, g2] = " < < basename < < " .dynamic_resid_g1_g2(T, y, x, params, steady_state, it_, false); " < < endl
< < " g3 = " < < basename < < " .dynamic_g3(T, y, x, params, steady_state, it_, false); " < < endl ;
2018-03-27 17:14:30 +02:00
output < < endl < < " end " < < endl ;
output . close ( ) ;
}
void
2022-07-12 17:04:41 +02:00
DynamicModel : : writeDynamicMFileHelper ( const string & basename ,
2018-06-27 15:01:31 +02:00
const string & name , const string & retvalname ,
2018-03-27 17:14:30 +02:00
const string & name_tt , size_t ttlen ,
const string & previous_tt_name ,
2022-07-12 17:04:41 +02:00
const ostringstream & init_s , const ostringstream & end_s ,
2018-03-27 17:14:30 +02:00
const ostringstream & s , const ostringstream & s_tt ) const
{
2022-10-11 15:59:56 +02:00
filesystem : : path filename { packageDir ( basename ) / ( name_tt + " .m " ) } ;
2022-07-11 16:09:07 +02:00
ofstream output { filename , ios : : out | ios : : binary } ;
2018-03-27 17:14:30 +02:00
if ( ! output . is_open ( ) )
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2018-03-27 17:14:30 +02:00
exit ( EXIT_FAILURE ) ;
}
output < < " function T = " < < name_tt < < " (T, y, x, params, steady_state, it_) " < < endl
< < " % function T = " < < name_tt < < " (T, y, x, params, steady_state, it_) " < < endl
< < " % " < < endl
< < " % File created by Dynare Preprocessor from .mod file " < < endl
< < " % " < < endl
< < " % Inputs: " < < endl
< < " % T [#temp variables by 1] double vector of temporary terms to be filled by function " < < endl
< < " % y [#dynamic variables by 1] double vector of endogenous variables in the order stored " < < endl
< < " % in M_.lead_lag_incidence; see the Manual " < < endl
< < " % x [nperiods by M_.exo_nbr] double matrix of exogenous variables (in declaration order) " < < endl
< < " % for all simulation periods " < < endl
< < " % steady_state [M_.endo_nbr by 1] double vector of steady state values " < < endl
< < " % params [M_.param_nbr by 1] double vector of parameter values in declaration order " < < endl
< < " % it_ scalar double time period for exogenous variables for which " < < endl
< < " % to evaluate the model " < < endl
< < " % " < < endl
< < " % Output: " < < endl
< < " % T [#temp variables by 1] double vector of temporary terms " < < endl
< < " % " < < endl < < endl
< < " assert(length(T) >= " < < ttlen < < " ); " < < endl
< < endl ;
if ( ! previous_tt_name . empty ( ) )
2018-06-27 15:01:31 +02:00
output < < " T = " < < basename < < " . " < < previous_tt_name < < " (T, y, x, params, steady_state, it_); " < < endl < < endl ;
2018-03-27 17:14:30 +02:00
output < < s_tt . str ( ) < < endl
< < " end " < < endl ;
output . close ( ) ;
2022-10-11 15:59:56 +02:00
filename = packageDir ( basename ) / ( name + " .m " ) ;
2018-06-27 15:12:12 +02:00
output . open ( filename , ios : : out | ios : : binary ) ;
2018-03-27 17:14:30 +02:00
if ( ! output . is_open ( ) )
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2018-03-27 17:14:30 +02:00
exit ( EXIT_FAILURE ) ;
}
output < < " function " < < retvalname < < " = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl
< < " % function " < < retvalname < < " = " < < name < < " (T, y, x, params, steady_state, it_, T_flag) " < < endl
< < " % " < < endl
< < " % File created by Dynare Preprocessor from .mod file " < < endl
< < " % " < < endl
< < " % Inputs: " < < endl
< < " % T [#temp variables by 1] double vector of temporary terms to be filled by function " < < endl
< < " % y [#dynamic variables by 1] double vector of endogenous variables in the order stored " < < endl
< < " % in M_.lead_lag_incidence; see the Manual " < < endl
< < " % x [nperiods by M_.exo_nbr] double matrix of exogenous variables (in declaration order) " < < endl
< < " % for all simulation periods " < < endl
< < " % steady_state [M_.endo_nbr by 1] double vector of steady state values " < < endl
< < " % params [M_.param_nbr by 1] double vector of parameter values in declaration order " < < endl
< < " % it_ scalar double time period for exogenous variables for which " < < endl
< < " % to evaluate the model " < < endl
< < " % T_flag boolean boolean flag saying whether or not to calculate temporary terms " < < endl
< < " % " < < endl
< < " % Output: " < < endl
< < " % " < < retvalname < < endl
< < " % " < < endl < < endl ;
if ( ! name_tt . empty ( ) )
output < < " if T_flag " < < endl
2018-06-27 15:01:31 +02:00
< < " T = " < < basename < < " . " < < name_tt < < " (T, y, x, params, steady_state, it_); " < < endl
2018-03-27 17:14:30 +02:00
< < " end " < < endl ;
output < < init_s . str ( ) < < endl
< < s . str ( )
< < end_s . str ( ) < < endl
< < " end " < < endl ;
output . close ( ) ;
}
2018-05-23 16:10:26 +02:00
void
2022-07-12 17:04:41 +02:00
DynamicModel : : writeDynamicMCompatFile ( const string & basename ) const
2018-05-23 16:10:26 +02:00
{
2022-10-11 15:59:56 +02:00
filesystem : : path filename { packageDir ( basename ) / " dynamic.m " } ;
2022-07-11 16:09:07 +02:00
ofstream output { filename , ios : : out | ios : : binary } ;
2018-05-23 16:10:26 +02:00
if ( ! output . is_open ( ) )
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2018-05-23 16:10:26 +02:00
exit ( EXIT_FAILURE ) ;
}
2022-09-26 14:53:36 +02:00
int ntt { static_cast < int > ( temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) + temporary_terms_derivatives [ 2 ] . size ( ) + temporary_terms_derivatives [ 3 ] . size ( ) ) } ;
2018-05-23 16:10:26 +02:00
2018-06-27 15:01:31 +02:00
output < < " function [residual, g1, g2, g3] = dynamic(y, x, params, steady_state, it_) " < < endl
2018-05-23 16:10:26 +02:00
< < " T = NaN( " < < ntt < < " , 1); " < < endl
< < " if nargout <= 1 " < < endl
2018-06-27 15:01:31 +02:00
< < " residual = " < < basename < < " .dynamic_resid(T, y, x, params, steady_state, it_, true); " < < endl
2018-05-23 16:10:26 +02:00
< < " elseif nargout == 2 " < < endl
2018-06-27 15:01:31 +02:00
< < " [residual, g1] = " < < basename < < " .dynamic_resid_g1(T, y, x, params, steady_state, it_, true); " < < endl
2018-05-23 16:10:26 +02:00
< < " elseif nargout == 3 " < < endl
2018-06-27 15:01:31 +02:00
< < " [residual, g1, g2] = " < < basename < < " .dynamic_resid_g1_g2(T, y, x, params, steady_state, it_, true); " < < endl
2018-05-23 16:10:26 +02:00
< < " else " < < endl
2018-06-27 15:01:31 +02:00
< < " [residual, g1, g2, g3] = " < < basename < < " .dynamic_resid_g1_g2_g3(T, y, x, params, steady_state, it_, true); " < < endl
2018-05-23 16:10:26 +02:00
< < " end " < < endl
< < " end " < < endl ;
output . close ( ) ;
}
2019-05-03 19:24:55 +02:00
void
2022-07-12 17:04:41 +02:00
DynamicModel : : writeDynamicJacobianNonZeroEltsFile ( const string & basename ) const
2019-05-03 19:24:55 +02:00
{
vector < pair < int , int > > nzij_pred , nzij_current , nzij_fwrd ; // pairs (tsid, equation)
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d1 ] : derivatives [ 1 ] )
2019-05-03 19:24:55 +02:00
{
2022-07-11 22:30:50 +02:00
if ( getTypeByDerivID ( indices [ 1 ] ) ! = SymbolType : : endogenous )
2019-05-03 19:24:55 +02:00
continue ;
2022-07-12 15:28:52 +02:00
int tsid { getTypeSpecificIDByDerivID ( indices [ 1 ] ) } ;
2019-12-16 19:42:59 +01:00
int lag = getLagByDerivID ( indices [ 1 ] ) ;
2019-05-03 19:24:55 +02:00
if ( lag = = - 1 )
2019-12-16 19:42:59 +01:00
nzij_pred . emplace_back ( tsid , indices [ 0 ] ) ;
2019-05-03 19:24:55 +02:00
else if ( lag = = 0 )
2019-12-16 19:42:59 +01:00
nzij_current . emplace_back ( tsid , indices [ 0 ] ) ;
2019-05-03 19:24:55 +02:00
else
2019-12-16 19:42:59 +01:00
nzij_fwrd . emplace_back ( tsid , indices [ 0 ] ) ;
2019-05-03 19:24:55 +02:00
}
sort ( nzij_pred . begin ( ) , nzij_pred . end ( ) ) ;
sort ( nzij_current . begin ( ) , nzij_current . end ( ) ) ;
sort ( nzij_fwrd . begin ( ) , nzij_fwrd . end ( ) ) ;
2023-01-05 16:40:04 +01:00
const filesystem : : path filename { packageDir ( basename ) / " dynamic_g1_nz.m " } ;
ofstream output { filename , ios : : out | ios : : binary } ;
2023-01-05 16:40:16 +01:00
if ( ! output . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2019-05-03 19:24:55 +02:00
output < < " function [nzij_pred, nzij_current, nzij_fwrd] = dynamic_g1_nz() " < < endl
< < " % Returns the coordinates of non-zero elements in the Jacobian, in column-major order, for each lead/lag (only for endogenous) " < < endl ;
2019-12-20 16:59:30 +01:00
auto print_nzij = [ & output ] ( const vector < pair < int , int > > & nzij , const string & name ) {
output < < " " < < name < < " = zeros( " < < nzij . size ( ) < < " , 2, 'int32'); " < < endl ;
2022-06-03 16:24:26 +02:00
for ( int idx { 1 } ;
const auto & it : nzij )
2019-12-20 16:59:30 +01:00
{
output < < " " < < name < < " ( " < < idx < < " ,1)= " < < it . second + 1 < < ' ; '
< < " " < < name < < " ( " < < idx < < " ,2)= " < < it . first + 1 < < ' ; ' < < endl ;
idx + + ;
}
} ;
2019-05-03 19:24:55 +02:00
print_nzij ( nzij_pred , " nzij_pred " ) ;
print_nzij ( nzij_current , " nzij_current " ) ;
print_nzij ( nzij_fwrd , " nzij_fwrd " ) ;
output < < " end " < < endl ;
output . close ( ) ;
}
2021-12-14 17:24:14 +01:00
vector < pair < string , string > >
DynamicModel : : parseIncludeExcludeEquations ( const string & inc_exc_option_value , bool exclude_eqs )
2019-11-18 17:13:49 +01:00
{
2021-12-14 17:24:14 +01:00
auto removeLeadingTrailingWhitespace = [ ] ( string & str )
{
str . erase ( 0 , str . find_first_not_of ( " \t \n \v \f \r " ) ) ;
str . erase ( str . find_last_not_of ( " \t \n \v \f \r " ) + 1 ) ;
} ;
2019-11-18 17:13:49 +01:00
string tags ;
2021-12-14 17:24:14 +01:00
if ( filesystem : : exists ( inc_exc_option_value ) )
2019-11-18 17:13:49 +01:00
{
ifstream exclude_file ;
2021-12-14 17:24:14 +01:00
exclude_file . open ( inc_exc_option_value , ifstream : : in ) ;
2019-11-18 17:13:49 +01:00
if ( ! exclude_file . is_open ( ) )
{
2021-12-14 17:24:14 +01:00
cerr < < " ERROR: Could not open " < < inc_exc_option_value < < endl ;
2019-11-18 17:13:49 +01:00
exit ( EXIT_FAILURE ) ;
}
string line ;
bool tagname_on_first_line = false ;
while ( getline ( exclude_file , line ) )
{
removeLeadingTrailingWhitespace ( line ) ;
if ( ! line . empty ( ) )
if ( tags . empty ( ) & & line . find ( " = " ) ! = string : : npos )
{
tagname_on_first_line = true ;
tags + = line + " ( " ;
}
else
if ( line . find ( " ' " ) ! = string : : npos )
tags + = line + " , " ;
else
tags + = " ' " + line + " ', " ;
}
if ( ! tags . empty ( ) )
{
tags = tags . substr ( 0 , tags . size ( ) - 1 ) ;
if ( tagname_on_first_line )
tags + = " ) " ;
}
}
else
2021-12-14 17:24:14 +01:00
tags = inc_exc_option_value ;
2019-11-18 17:13:49 +01:00
removeLeadingTrailingWhitespace ( tags ) ;
if ( tags . front ( ) = = ' [ ' & & tags . back ( ) ! = ' ] ' )
{
2021-12-14 17:24:14 +01:00
cerr < < " ERROR: " < < ( exclude_eqs ? " exclude_eqs " : " include_eqs " )
2019-11-18 17:13:49 +01:00
< < " : if the first character is '[' the last must be ']' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( tags . front ( ) = = ' [ ' & & tags . back ( ) = = ' ] ' )
tags = tags . substr ( 1 , tags . length ( ) - 2 ) ;
removeLeadingTrailingWhitespace ( tags ) ;
2019-12-20 16:59:30 +01:00
regex q ( R " (^ \ w+ \ s*=) " ) ;
2019-11-18 17:13:49 +01:00
smatch matches ;
string tagname = " name " ;
if ( regex_search ( tags , matches , q ) )
{
tagname = matches [ 0 ] . str ( ) ;
tags = tags . substr ( tagname . size ( ) , tags . length ( ) - tagname . size ( ) + 1 ) ;
removeLeadingTrailingWhitespace ( tags ) ;
if ( tags . front ( ) = = ' ( ' & & tags . back ( ) = = ' ) ' )
{
tags = tags . substr ( 1 , tags . length ( ) - 2 ) ;
removeLeadingTrailingWhitespace ( tags ) ;
}
tagname = tagname . substr ( 0 , tagname . size ( ) - 1 ) ;
removeLeadingTrailingWhitespace ( tagname ) ;
}
string quote_regex = " '[^']+' " ;
2019-12-16 19:42:59 +01:00
string non_quote_regex = R " ([^, \ s]+) " ;
2019-12-20 16:59:30 +01:00
regex r ( R " (( \ s*) " + quote_regex + " | " + non_quote_regex + R " ( \ s * ) ( , \ s * ( ) " + quote_regex + " | " + non_quote_regex + R " ( ) \ s * ) * ) " ) ;
if ( ! regex_match ( tags , r ) )
2019-11-18 17:13:49 +01:00
{
2021-12-14 17:24:14 +01:00
cerr < < " ERROR: " < < ( exclude_eqs ? " exclude_eqs " : " include_eqs " )
2019-11-18 17:13:49 +01:00
< < " : argument is of incorrect format. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2021-12-14 17:24:14 +01:00
vector < pair < string , string > > eq_tag_set ;
2019-12-20 16:59:30 +01:00
regex s ( quote_regex + " | " + non_quote_regex ) ;
2019-11-18 17:13:49 +01:00
for ( auto it = sregex_iterator ( tags . begin ( ) , tags . end ( ) , s ) ;
2019-12-20 16:59:30 +01:00
it ! = sregex_iterator ( ) ; + + it )
2019-11-18 17:13:49 +01:00
{
2022-10-04 16:34:43 +02:00
string_view str { it - > str ( ) } ;
if ( str . front ( ) = = ' \' ' & & str . back ( ) = = ' \' ' )
{
str . remove_prefix ( 1 ) ;
str . remove_suffix ( 1 ) ;
}
2021-12-14 17:24:14 +01:00
eq_tag_set . emplace_back ( tagname , str ) ;
2019-11-18 17:13:49 +01:00
}
2021-12-14 17:24:14 +01:00
return eq_tag_set ;
2019-11-18 17:13:49 +01:00
}
2021-12-14 17:24:14 +01:00
vector < int >
DynamicModel : : removeEquationsHelper ( set < pair < string , string > > & listed_eqs_by_tag , bool exclude_eqs ,
bool excluded_vars_change_type ,
vector < BinaryOpNode * > & all_equations ,
2022-05-05 18:39:27 +02:00
vector < optional < int > > & all_equations_lineno ,
2021-12-14 17:24:14 +01:00
EquationTags & all_equation_tags , bool static_equations ) const
2019-11-18 17:13:49 +01:00
{
2021-12-14 17:24:14 +01:00
if ( all_equations . empty ( ) )
return { } ;
/* Try to convert the list of equations by tags into a list of equation
numbers .
The tag pairs that match an equation are removed from the list , so that
the caller knows which tag pairs have not been handled . */
set < int > listed_eqs_by_number ;
for ( auto it = listed_eqs_by_tag . begin ( ) ; it ! = listed_eqs_by_tag . end ( ) ; )
if ( auto tmp = all_equation_tags . getEqnsByTag ( it - > first , it - > second ) ;
! tmp . empty ( ) )
{
listed_eqs_by_number . insert ( tmp . begin ( ) , tmp . end ( ) ) ;
it = listed_eqs_by_tag . erase ( it ) ;
}
else
+ + it ;
2019-11-18 17:13:49 +01:00
2021-12-14 17:24:14 +01:00
// Compute the indices of equations to be actually deleted
set < int > eqs_to_delete_by_number ;
if ( exclude_eqs )
eqs_to_delete_by_number = listed_eqs_by_number ;
else
for ( size_t i = 0 ; i < all_equations . size ( ) ; i + + )
2022-05-04 16:01:34 +02:00
if ( ! listed_eqs_by_number . contains ( i ) )
2021-12-14 17:24:14 +01:00
eqs_to_delete_by_number . insert ( i ) ;
// remove from equations, equations_lineno, equation_tags
vector < BinaryOpNode * > new_equations ;
2022-05-05 18:39:27 +02:00
vector < optional < int > > new_equations_lineno ;
2021-12-14 17:24:14 +01:00
map < int , int > old_eqn_num_2_new ;
vector < int > excluded_vars ;
for ( size_t i = 0 ; i < all_equations . size ( ) ; i + + )
2022-05-04 16:01:34 +02:00
if ( eqs_to_delete_by_number . contains ( i ) )
2021-12-14 17:24:14 +01:00
{
if ( excluded_vars_change_type )
2023-01-04 16:03:12 +01:00
if ( auto tmp = all_equation_tags . getTagValueByEqnAndKey ( i , " endogenous " ) ; tmp )
excluded_vars . push_back ( symbol_table . getID ( * tmp ) ) ;
2022-06-02 10:50:21 +02:00
else
{
set < int > result ;
all_equations [ i ] - > arg1 - > collectVariables ( SymbolType : : endogenous , result ) ;
if ( result . size ( ) = = 1 )
excluded_vars . push_back ( * result . begin ( ) ) ;
else
{
cerr < < " ERROR: Equation " < < i + 1
< < " has been excluded but it does not have a single variable on its left-hand side or an `endogenous` tag " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2021-12-14 17:24:14 +01:00
}
else
{
new_equations . emplace_back ( all_equations [ i ] ) ;
old_eqn_num_2_new [ i ] = new_equations . size ( ) - 1 ;
new_equations_lineno . emplace_back ( all_equations_lineno [ i ] ) ;
}
int n_excl = all_equations . size ( ) - new_equations . size ( ) ;
all_equations = new_equations ;
all_equations_lineno = new_equations_lineno ;
2019-11-18 17:13:49 +01:00
2021-12-14 17:24:14 +01:00
all_equation_tags . erase ( eqs_to_delete_by_number , old_eqn_num_2_new ) ;
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 a model_remove or model_replace statement, or via the include_eqs or exclude_eqs option " < < endl ;
exit ( EXIT_FAILURE ) ;
}
cout < < " Excluded " < < n_excl < < ( static_equations ? " static " : " dynamic " )
< < " equation " < < ( n_excl > 1 ? " s " : " " ) < < " via model_remove or model_replace statement, or via include_eqs or exclude_eqs option " < < endl ;
return excluded_vars ;
}
void
DynamicModel : : removeEquations ( const vector < pair < string , string > > & listed_eqs_by_tag , bool exclude_eqs ,
bool excluded_vars_change_type )
{
/* Convert the const vector to a (mutable) set */
2022-06-03 16:21:30 +02:00
set listed_eqs_by_tag2 ( listed_eqs_by_tag . begin ( ) , listed_eqs_by_tag . end ( ) ) ;
2021-12-14 17:24:14 +01:00
vector < int > excluded_vars = removeEquationsHelper ( listed_eqs_by_tag2 , exclude_eqs ,
excluded_vars_change_type ,
equations , equations_lineno ,
equation_tags , false ) ;
2019-11-18 17:13:49 +01:00
// Ignore output because variables are not excluded when equations marked 'static' are excluded
2021-12-14 17:24:14 +01:00
removeEquationsHelper ( listed_eqs_by_tag2 , exclude_eqs , excluded_vars_change_type ,
static_only_equations , static_only_equations_lineno ,
static_only_equations_equation_tags , true ) ;
2020-02-20 15:29:10 +01:00
2021-12-14 17:24:14 +01:00
if ( ! listed_eqs_by_tag2 . empty ( ) )
2019-11-18 17:13:49 +01:00
{
2021-12-14 17:24:14 +01:00
cerr < < " ERROR: model_remove/model_replace/exclude_eqs/include_eqs: The equations specified by " < < endl ;
for ( const auto & [ tagname , tagvalue ] : listed_eqs_by_tag )
cerr < < " " < < tagname < < " = " < < tagvalue < < endl ;
cerr < < " were not found. " < < endl ;
2019-11-18 17:13:49 +01:00
exit ( EXIT_FAILURE ) ;
}
2021-12-14 17:24:14 +01:00
if ( excluded_vars_change_type )
2019-11-18 17:13:49 +01:00
{
2021-12-14 17:24:14 +01:00
// Collect list of used variables in updated list of equations
set < int > eqn_vars ;
for ( auto eqn : equations )
eqn - > collectVariables ( SymbolType : : endogenous , eqn_vars ) ;
for ( auto eqn : static_only_equations )
eqn - > collectVariables ( SymbolType : : endogenous , eqn_vars ) ;
/* Change type of endogenous variables determined by excluded equations.
They become exogenous if they are still used somewhere , otherwise they are
completely excluded from the model . */
for ( auto ev : excluded_vars )
2022-05-04 16:01:34 +02:00
if ( eqn_vars . contains ( ev ) )
2021-12-14 17:24:14 +01:00
{
symbol_table . changeType ( ev , SymbolType : : exogenous ) ;
cerr < < " Variable ' " < < symbol_table . getName ( ev ) < < " ' turned into an exogenous, as its defining equation has been removed (but it still appears in an equation) " < < endl ;
}
else
{
symbol_table . changeType ( ev , SymbolType : : excludedVariable ) ;
cerr < < " Variable ' " < < symbol_table . getName ( ev ) < < " ' has been excluded from the model, as its defining equation has been removed and it appears nowhere else " < < endl ;
}
2019-11-18 17:13:49 +01:00
}
2021-12-14 17:24:14 +01:00
}
void
DynamicModel : : includeExcludeEquations ( const string & inc_exc_option_value , bool exclude_eqs )
{
if ( inc_exc_option_value . empty ( ) )
return ;
2019-11-18 17:13:49 +01:00
2021-12-14 17:24:14 +01:00
auto listed_eqs_by_tag = parseIncludeExcludeEquations ( inc_exc_option_value , exclude_eqs ) ;
2019-11-18 17:13:49 +01:00
2021-12-14 17:24:14 +01:00
removeEquations ( listed_eqs_by_tag , exclude_eqs , true ) ;
/* There is already a check about #static and #dynamic in
ModFile : : checkPass ( ) , but the present method is called from
ModFile : : transformPass ( ) , so we must do the check again */
if ( staticOnlyEquationsNbr ( ) ! = dynamicOnlyEquationsNbr ( ) )
2019-11-18 17:13:49 +01:00
{
2021-12-14 17:24:14 +01:00
cerr < < " ERROR: exclude_eqs/include_eqs: You must remove the same number of equations marked `static` as equations marked `dynamic`. " < < endl ;
exit ( EXIT_FAILURE ) ;
2019-11-18 17:13:49 +01:00
}
}
2020-05-20 11:35:14 +02:00
void
2023-01-13 12:05:04 +01:00
DynamicModel : : writeBlockDriverOutput ( ostream & output ) const
2020-05-20 11:35:14 +02:00
{
2022-11-30 14:43:44 +01:00
output < < " M_.block_structure.time_recursive = " < < boolalpha < < time_recursive_block_decomposition < < " ; " < < endl ;
2020-05-20 11:35:14 +02:00
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
{
int block_size = blocks [ blk ] . size ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).Simulation_Type = " < < static_cast < int > ( blocks [ blk ] . simulation_type ) < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).endo_nbr = " < < block_size < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).mfs = " < < blocks [ blk ] . mfs_size < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).equation = [ " ;
2020-05-20 11:35:14 +02:00
for ( int eq = 0 ; eq < block_size ; eq + + )
output < < " " < < getBlockEquationID ( blk , eq ) + 1 ;
output < < " ]; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).variable = [ " ;
2020-05-20 11:35:14 +02:00
for ( int var = 0 ; var < block_size ; var + + )
output < < " " < < getBlockVariableID ( blk , var ) + 1 ;
output < < " ]; " < < endl
2022-05-16 12:26:21 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).is_linear = " < < boolalpha < < blocks [ blk ] . linear < < ' ; ' < < endl
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).NNZDerivatives = " < < blocks_derivatives [ blk ] . size ( ) < < ' ; ' < < endl ;
2020-05-20 11:35:14 +02:00
}
2022-09-28 19:18:15 +02:00
writeBlockDriverSparseIndicesHelper < true > ( output ) ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.variable_reordered = [ " ;
2020-05-20 11:35:14 +02:00
for ( int i = 0 ; i < symbol_table . endo_nbr ( ) ; i + + )
output < < " " < < endo_idx_block2orig [ i ] + 1 ;
output < < " ]; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.equation_reordered = [ " ;
2020-05-20 11:35:14 +02:00
for ( int i = 0 ; i < symbol_table . endo_nbr ( ) ; i + + )
output < < " " < < eq_idx_block2orig [ i ] + 1 ;
output < < " ]; " < < endl ;
map < int , set < pair < int , int > > > lag_row_incidence ;
for ( const auto & [ indices , d1 ] : derivatives [ 1 ] )
if ( int deriv_id = indices [ 1 ] ;
getTypeByDerivID ( deriv_id ) = = SymbolType : : endogenous )
{
int eq = indices [ 0 ] ;
2022-07-12 15:28:52 +02:00
int var { getTypeSpecificIDByDerivID ( deriv_id ) } ;
2020-05-20 11:35:14 +02:00
int lag = getLagByDerivID ( deriv_id ) ;
lag_row_incidence [ lag ] . insert ( { eq , var } ) ;
}
for ( auto [ lag , eq_var_set ] : lag_row_incidence )
{
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.incidence( " < < max_endo_lag + lag + 1 < < " ).lead_lag = " < < lag < < " ; " < < endl
< < " M_.block_structure.incidence( " < < max_endo_lag + lag + 1 < < " ).sparse_IM = [ " < < endl ;
2020-05-20 11:35:14 +02:00
for ( auto [ eq , var ] : eq_var_set )
output < < " " < < eq + 1 < < " " < < var + 1 < < " ; " < < endl ;
output < < " ]; " < < endl ;
}
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.dyn_tmp_nbr = " < < blocks_temporary_terms_idxs . size ( ) < < ' ; ' < < endl ;
2020-05-20 11:35:14 +02:00
}
2009-04-14 16:39:53 +02:00
void
2023-01-13 12:05:04 +01:00
DynamicModel : : writeDriverOutput ( ostream & output , bool compute_xrefs ) const
2009-12-16 18:13:23 +01:00
{
/* Writing initialisation for M_.lead_lag_incidence matrix
M_ . lead_lag_incidence is a matrix with as many columns as there are
endogenous variables and as many rows as there are periods in the
models ( nbr of rows = M_ . max_lag + M_ . max_lead + 1 )
The matrix elements are equal to zero if a variable isn ' t present in the
model at a given period .
*/
2021-04-19 14:51:34 +02:00
output < < " M_.orig_maximum_endo_lag = " < < max_endo_lag_orig < < " ; " < < endl
< < " M_.orig_maximum_endo_lead = " < < max_endo_lead_orig < < " ; " < < endl
< < " M_.orig_maximum_exo_lag = " < < max_exo_lag_orig < < " ; " < < endl
< < " M_.orig_maximum_exo_lead = " < < max_exo_lead_orig < < " ; " < < endl
< < " M_.orig_maximum_exo_det_lag = " < < max_exo_det_lag_orig < < " ; " < < endl
< < " M_.orig_maximum_exo_det_lead = " < < max_exo_det_lead_orig < < " ; " < < endl
< < " M_.orig_maximum_lag = " < < max_lag_orig < < " ; " < < endl
< < " M_.orig_maximum_lead = " < < max_lead_orig < < " ; " < < endl
< < " M_.orig_maximum_lag_with_diffs_expanded = " < < max_lag_with_diffs_expanded_orig < < " ; " < < endl
< < " M_.lead_lag_incidence = [ " ;
2009-12-16 18:13:23 +01:00
// Loop on endogenous variables
2017-06-01 19:58:32 +02:00
int nstatic = 0 ,
2019-12-16 19:42:59 +01:00
nfwrd = 0 ,
npred = 0 ,
nboth = 0 ;
2009-12-16 18:13:23 +01:00
for ( int endoID = 0 ; endoID < symbol_table . endo_nbr ( ) ; endoID + + )
{
output < < endl ;
2017-06-01 19:58:32 +02:00
int sstatic = 1 ,
2019-12-16 19:42:59 +01:00
sfwrd = 0 ,
spred = 0 ,
sboth = 0 ;
2009-12-16 18:13:23 +01:00
// Loop on periods
for ( int lag = - max_endo_lag ; lag < = max_endo_lead ; lag + + )
{
// Print variableID if exists with current period, otherwise print 0
try
{
2018-07-17 18:34:07 +02:00
int varID = getDerivID ( symbol_table . getID ( SymbolType : : endogenous , endoID ) , lag ) ;
2022-09-14 17:07:08 +02:00
output < < " " < < getJacobianCol ( varID , false ) + 1 ;
2011-06-18 17:53:50 +02:00
if ( lag = = - 1 )
{
sstatic = 0 ;
spred = 1 ;
}
else if ( lag = = 1 )
{
if ( spred = = 1 )
{
sboth = 1 ;
spred = 0 ;
}
else
{
sstatic = 0 ;
sfwrd = 1 ;
}
}
2009-12-16 18:13:23 +01:00
}
catch ( UnknownDerivIDException & e )
{
output < < " 0 " ;
}
}
2011-06-18 17:53:50 +02:00
nstatic + = sstatic ;
2019-12-20 16:59:30 +01:00
nfwrd + = sfwrd ;
npred + = spred ;
nboth + = sboth ;
2009-12-16 18:13:23 +01:00
output < < " ; " ;
}
2022-06-02 10:50:21 +02:00
output < < " ]'; " < < endl
< < " M_.nstatic = " < < nstatic < < " ; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.nfwrd = " < < nfwrd < < " ; " < < endl
< < " M_.npred = " < < npred < < " ; " < < endl
< < " M_.nboth = " < < nboth < < " ; " < < endl
< < " M_.nsfwrd = " < < nfwrd + nboth < < " ; " < < endl
< < " M_.nspred = " < < npred + nboth < < " ; " < < endl
2022-06-02 10:50:21 +02:00
< < " M_.ndynamic = " < < npred + nboth + nfwrd < < " ; " < < endl
< < " M_.dynamic_tmp_nbr = [ " ;
2022-09-26 14:53:36 +02:00
for ( const auto & tts : temporary_terms_derivatives )
output < < tts . size ( ) < < " ; " ;
2021-04-19 14:51:34 +02:00
output < < " ]; " < < endl ;
2020-06-05 17:11:29 +02:00
2009-12-16 18:13:23 +01:00
// Write equation tags
2021-04-19 14:51:34 +02:00
equation_tags . writeOutput ( output ) ;
2009-12-16 18:13:23 +01:00
2019-10-16 17:34:27 +02:00
// Write mapping for variables and equations they are present in
2021-04-19 14:51:34 +02:00
for ( const auto & variable : variableMapping )
2019-10-16 17:34:27 +02:00
{
2021-04-19 14:51:34 +02:00
output < < " M_.mapping. " < < symbol_table . getName ( variable . first ) < < " .eqidx = [ " ;
for ( auto equation : variable . second )
output < < equation + 1 < < " " ;
output < < " ]; " < < endl ;
2019-10-16 17:34:27 +02:00
}
2013-04-11 17:07:39 +02:00
/* Say if static and dynamic models differ (because of [static] and [dynamic]
equation tags ) */
2021-04-19 14:51:34 +02:00
output < < " M_.static_and_dynamic_models_differ = "
2022-05-16 12:26:21 +02:00
< < boolalpha < < ( static_only_equations . size ( ) > 0 )
2013-04-11 17:07:39 +02:00
< < " ; " < < endl ;
2019-05-15 15:02:36 +02:00
// Say if model contains an external function call
bool has_external_function = false ;
2019-12-16 19:42:59 +01:00
for ( auto equation : equations )
if ( equation - > containsExternalFunction ( ) )
2019-05-15 15:02:36 +02:00
{
has_external_function = true ;
break ;
}
2022-05-16 12:26:21 +02:00
output < < " M_.has_external_function = " < < boolalpha < < has_external_function
2019-05-15 15:02:36 +02:00
< < ' ; ' < < endl ;
2020-05-20 11:35:14 +02:00
// Compute list of state variables, ordered in block-order
2016-07-20 23:09:46 +02:00
vector < int > state_var ;
for ( int endoID = 0 ; endoID < symbol_table . endo_nbr ( ) ; endoID + + )
2020-05-20 11:35:14 +02:00
// Loop on negative lags
2016-07-20 23:09:46 +02:00
for ( int lag = - max_endo_lag ; lag < 0 ; lag + + )
try
{
2020-04-17 14:55:55 +02:00
getDerivID ( symbol_table . getID ( SymbolType : : endogenous , endo_idx_block2orig [ endoID ] ) , lag ) ;
2020-05-20 11:35:14 +02:00
if ( find ( state_var . begin ( ) , state_var . end ( ) , endo_idx_block2orig [ endoID ] ) = = state_var . end ( ) )
state_var . push_back ( endo_idx_block2orig [ endoID ] ) ;
2016-07-20 23:09:46 +02:00
}
catch ( UnknownDerivIDException & e )
{
}
2020-05-20 11:35:14 +02:00
// Write the block structure of the model
2022-09-28 16:54:03 +02:00
if ( block_decomposed )
2023-01-13 12:05:04 +01:00
writeBlockDriverOutput ( output ) ;
2012-09-28 18:41:18 +02:00
2021-04-19 14:51:34 +02:00
output < < " M_.state_var = [ " ;
2018-11-23 17:19:59 +01:00
for ( int it : state_var )
2021-04-19 14:51:34 +02:00
output < < it + 1 < < " " ;
2016-07-20 23:09:46 +02:00
output < < " ]; " < < endl ;
2009-12-16 18:13:23 +01:00
// Writing initialization for some other variables
2021-04-19 14:51:34 +02:00
output < < " M_.exo_names_orig_ord = [1: " < < symbol_table . exo_nbr ( ) < < " ]; " < < endl ;
2013-11-04 16:02:28 +01:00
2021-04-19 14:51:34 +02:00
output < < " M_.maximum_lag = " < < max_lag < < " ; " < < endl
< < " M_.maximum_lead = " < < max_lead < < " ; " < < endl ;
2013-11-04 16:02:28 +01:00
2021-04-19 14:51:34 +02:00
output < < " M_.maximum_endo_lag = " < < max_endo_lag < < " ; " < < endl
< < " M_.maximum_endo_lead = " < < max_endo_lead < < " ; " < < endl
< < " oo_.steady_state = zeros( " < < symbol_table . endo_nbr ( ) < < " , 1); " < < endl ;
2013-11-04 16:02:28 +01:00
2021-04-19 14:51:34 +02:00
output < < " M_.maximum_exo_lag = " < < max_exo_lag < < " ; " < < endl
< < " M_.maximum_exo_lead = " < < max_exo_lead < < " ; " < < endl
< < " oo_.exo_steady_state = zeros( " < < symbol_table . exo_nbr ( ) < < " , 1); " < < endl ;
2013-11-04 16:02:28 +01:00
2009-12-16 18:13:23 +01:00
if ( symbol_table . exo_det_nbr ( ) )
{
2021-04-19 14:51:34 +02:00
output < < " M_.maximum_exo_det_lag = " < < max_exo_det_lag < < " ; " < < endl
< < " M_.maximum_exo_det_lead = " < < max_exo_det_lead < < " ; " < < endl
< < " oo_.exo_det_steady_state = zeros( " < < symbol_table . exo_det_nbr ( ) < < " , 1); " < < endl ;
2009-12-16 18:13:23 +01:00
}
2013-11-04 16:02:28 +01:00
2021-04-19 14:51:34 +02:00
output < < " M_.params = " < < " NaN( " < < symbol_table . param_nbr ( ) < < " , 1); " < < endl ;
2009-12-16 18:13:23 +01:00
2021-04-19 14:51:34 +02:00
string empty_cell = " cell( " + to_string ( symbol_table . endo_nbr ( ) ) + " , 1) " ;
output < < " M_.endo_trends = struct('deflator', " < < empty_cell
< < " , 'log_deflator', " < < empty_cell < < " , 'growth_factor', " < < empty_cell
< < " , 'log_growth_factor', " < < empty_cell < < " ); " < < endl ;
for ( int i = 0 ; i < symbol_table . endo_nbr ( ) ; i + + )
2019-12-13 17:27:50 +01:00
{
2021-04-19 14:51:34 +02:00
int symb_id = symbol_table . getID ( SymbolType : : endogenous , i ) ;
if ( auto it = nonstationary_symbols_map . find ( symb_id ) ; it ! = nonstationary_symbols_map . end ( ) )
2019-12-13 17:27:50 +01:00
{
2021-04-19 14:51:34 +02:00
auto [ is_log , deflator ] = it - > second ;
2022-12-14 12:05:12 +01:00
output < < " M_.endo_trends( " < < i + 1 < < " ). "
2021-04-19 14:51:34 +02:00
< < ( is_log ? " log_deflator " : " deflator " ) < < " = ' " ;
deflator - > writeJsonOutput ( output , { } , { } ) ;
output < < " '; " < < endl ;
auto growth_factor = const_cast < DynamicModel * > ( this ) - > AddDivide ( deflator , deflator - > decreaseLeadsLags ( 1 ) ) - > removeTrendLeadLag ( trend_symbols_map ) - > replaceTrendVar ( ) ;
2022-12-14 12:05:12 +01:00
output < < " M_.endo_trends( " < < i + 1 < < " ). "
2021-04-19 14:51:34 +02:00
< < ( is_log ? " log_growth_factor " : " growth_factor " ) < < " = ' " ;
growth_factor - > writeJsonOutput ( output , { } , { } ) ;
output < < " '; " < < endl ;
2019-12-13 17:27:50 +01:00
}
}
2016-02-23 13:55:02 +01:00
if ( compute_xrefs )
writeXrefs ( output ) ;
2015-12-18 15:17:32 +01:00
2009-12-16 18:13:23 +01:00
// Write number of non-zero derivatives
2010-07-17 10:14:22 +02:00
// Use -1 if the derivatives have not been computed
2021-04-19 14:51:34 +02:00
output < < " M_.NNZDerivatives = [ " ;
2019-04-12 15:41:52 +02:00
for ( int i = 1 ; i < static_cast < int > ( NNZDerivatives . size ( ) ) ; i + + )
2020-01-20 17:22:32 +01:00
output < < ( i > computed_derivs_order ? - 1 : NNZDerivatives [ i ] ) < < " ; " ;
2015-07-29 14:52:15 +02:00
output < < " ]; " < < endl ;
2022-09-14 17:07:08 +02:00
writeDriverSparseIndicesHelper < true > ( output ) ;
2022-11-30 14:43:44 +01:00
// Write LHS of each equation in text form
output < < " M_.lhs = { " < < endl ;
for ( auto eq : equations )
{
output < < " ' " ;
eq - > arg1 - > writeJsonOutput ( output , { } , { } ) ;
output < < " '; " < < endl ;
}
output < < " }; " < < endl ;
2009-12-16 18:13:23 +01:00
}
2009-05-13 01:03:40 +02:00
2010-10-15 19:05:16 +02:00
void
DynamicModel : : runTrendTest ( const eval_context_t & eval_context )
{
computeDerivIDs ( ) ;
testTrendDerivativesEqualToZero ( eval_context ) ;
}
2018-08-23 13:56:58 +02:00
void
2018-09-03 15:05:30 +02:00
DynamicModel : : updateVarAndTrendModel ( ) const
2018-08-23 13:56:58 +02:00
{
2021-07-16 12:26:57 +02:00
for ( bool var : { true , false } )
2018-08-23 13:56:58 +02:00
{
2022-05-05 18:39:04 +02:00
map < string , vector < optional < int > > > trend_varr ;
2018-08-23 13:56:58 +02:00
map < string , vector < set < pair < int , int > > > > rhsr ;
2021-07-16 12:26:57 +02:00
for ( const auto & [ model_name , eqns ] : ( var ? var_model_table . getEqNums ( )
: trend_component_model_table . getEqNums ( ) ) )
2018-08-23 13:56:58 +02:00
{
2022-05-05 18:39:04 +02:00
vector < int > lhs , trend_lhs ;
vector < optional < int > > trend_var ;
2018-08-23 13:56:58 +02:00
vector < set < pair < int , int > > > rhs ;
2018-09-03 15:05:30 +02:00
2021-07-16 12:26:57 +02:00
if ( ! var )
2018-09-03 15:05:30 +02:00
{
2021-07-16 12:26:57 +02:00
lhs = trend_component_model_table . getLhs ( model_name ) ;
for ( auto teqn : trend_component_model_table . getTargetEqNums ( ) . at ( model_name ) )
2018-09-03 15:05:30 +02:00
{
int eqnidx = 0 ;
2021-07-16 12:26:57 +02:00
for ( auto eqn : eqns )
2018-09-03 15:05:30 +02:00
{
if ( eqn = = teqn )
trend_lhs . push_back ( lhs [ eqnidx ] ) ;
eqnidx + + ;
}
}
}
int lhs_idx = 0 ;
2021-07-16 12:26:57 +02:00
for ( auto eqn : eqns )
2018-08-23 13:56:58 +02:00
{
set < pair < int , int > > rhs_set ;
2018-11-28 14:32:26 +01:00
equations [ eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : endogenous , rhs_set ) ;
2018-08-23 13:56:58 +02:00
rhs . push_back ( rhs_set ) ;
2018-09-03 15:05:30 +02:00
2021-07-16 12:26:57 +02:00
if ( ! var )
2018-08-31 12:35:51 +02:00
{
int lhs_symb_id = lhs [ lhs_idx + + ] ;
2022-01-28 16:28:14 +01:00
if ( symbol_table . isDiffAuxiliaryVariable ( lhs_symb_id ) )
2018-08-31 12:35:51 +02:00
try
{
lhs_symb_id = symbol_table . getOrigSymbIdForAuxVar ( lhs_symb_id ) ;
}
catch ( . . . )
{
}
2022-05-05 18:39:04 +02:00
optional < int > trend_var_symb_id = equations [ eqn ] - > arg2 - > findTargetVariable ( lhs_symb_id ) ;
if ( trend_var_symb_id )
2018-09-03 15:05:30 +02:00
{
2022-05-05 18:39:04 +02:00
if ( symbol_table . isDiffAuxiliaryVariable ( * trend_var_symb_id ) )
2018-09-03 15:05:30 +02:00
try
{
2022-05-05 18:39:04 +02:00
trend_var_symb_id = symbol_table . getOrigSymbIdForAuxVar ( * trend_var_symb_id ) ;
2018-09-03 15:05:30 +02:00
}
catch ( . . . )
{
}
2022-05-05 18:39:04 +02:00
if ( find ( trend_lhs . begin ( ) , trend_lhs . end ( ) , * trend_var_symb_id ) = = trend_lhs . end ( ) )
2018-09-03 15:05:30 +02:00
{
cerr < < " ERROR: trend found in trend_component equation # " < < eqn < < " ( "
2022-05-05 18:39:04 +02:00
< < symbol_table . getName ( * trend_var_symb_id ) < < " ) does not correspond to a trend equation " < < endl ;
2018-09-03 15:05:30 +02:00
exit ( EXIT_FAILURE ) ;
}
}
2022-05-05 18:39:04 +02:00
trend_var . push_back ( move ( trend_var_symb_id ) ) ;
2018-08-31 12:35:51 +02:00
}
2018-08-23 13:56:58 +02:00
}
2018-09-03 15:05:30 +02:00
2021-07-16 12:26:57 +02:00
rhsr [ model_name ] = rhs ;
if ( ! var )
trend_varr [ model_name ] = trend_var ;
2018-08-23 13:56:58 +02:00
}
2021-07-16 12:26:57 +02:00
if ( var )
2022-06-13 14:15:47 +02:00
var_model_table . setRhs ( move ( rhsr ) ) ;
2021-07-16 12:26:57 +02:00
else
2018-08-31 12:35:51 +02:00
{
2022-06-13 14:15:47 +02:00
trend_component_model_table . setRhs ( move ( rhsr ) ) ;
trend_component_model_table . setTargetVar ( move ( trend_varr ) ) ;
2018-08-31 12:35:51 +02:00
}
2018-08-23 13:56:58 +02:00
}
}
2018-08-21 11:46:59 +02:00
void
DynamicModel : : fillVarModelTable ( ) const
{
map < string , vector < int > > eqnums , lhsr ;
map < string , vector < expr_t > > lhs_expr_tr ;
map < string , vector < set < pair < int , int > > > > rhsr ;
2021-07-06 19:04:59 +02:00
for ( const auto & [ model_name , eqtags ] : var_model_table . getEqTags ( ) )
2018-08-21 11:46:59 +02:00
{
vector < int > eqnumber , lhs ;
vector < expr_t > lhs_expr_t ;
vector < set < pair < int , int > > > rhs ;
2021-07-06 19:04:59 +02:00
for ( const auto & eqtag : eqtags )
2018-08-21 11:46:59 +02:00
{
set < pair < int , int > > lhs_set , lhs_tmp_set , rhs_set ;
2023-01-04 16:44:52 +01:00
optional < int > eqn { equation_tags . getEqnByTag ( " name " , eqtag ) } ;
if ( ! eqn )
2018-08-21 11:46:59 +02:00
{
2021-07-01 16:16:04 +02:00
cerr < < " ERROR: no equation is named ' " < < eqtag < < " ' " < < endl ;
2018-08-21 11:46:59 +02:00
exit ( EXIT_FAILURE ) ;
}
2023-01-04 16:44:52 +01:00
equations [ * eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , lhs_set ) ;
equations [ * eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : exogenous , lhs_tmp_set ) ;
equations [ * eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : parameter , lhs_tmp_set ) ;
2018-08-21 11:46:59 +02:00
if ( lhs_set . size ( ) ! = 1 | | ! lhs_tmp_set . empty ( ) )
{
cerr < < " ERROR: in Equation " < < eqtag
< < " . A VAR may only have one endogenous variable on the LHS. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-08-23 13:03:52 +02:00
auto itlhs = lhs_set . begin ( ) ;
if ( itlhs - > second ! = 0 )
2018-08-21 11:46:59 +02:00
{
cerr < < " ERROR: in Equation " < < eqtag
< < " . The variable on the LHS of a VAR may not appear with a lead or a lag. "
< < endl ;
exit ( EXIT_FAILURE ) ;
}
2023-01-04 16:44:52 +01:00
eqnumber . push_back ( * eqn ) ;
2018-08-23 13:03:52 +02:00
lhs . push_back ( itlhs - > first ) ;
2018-08-21 11:46:59 +02:00
lhs_set . clear ( ) ;
set < expr_t > lhs_expr_t_set ;
2023-01-04 16:44:52 +01:00
equations [ * eqn ] - > arg1 - > collectVARLHSVariable ( lhs_expr_t_set ) ;
2018-08-21 11:46:59 +02:00
lhs_expr_t . push_back ( * ( lhs_expr_t_set . begin ( ) ) ) ;
2023-01-04 16:44:52 +01:00
equations [ * eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : endogenous , rhs_set ) ;
2018-08-21 11:46:59 +02:00
rhs . push_back ( rhs_set ) ;
}
2021-07-06 19:04:59 +02:00
eqnums [ model_name ] = eqnumber ;
lhsr [ model_name ] = lhs ;
lhs_expr_tr [ model_name ] = lhs_expr_t ;
rhsr [ model_name ] = rhs ;
2018-08-21 11:46:59 +02:00
}
2022-06-13 14:15:47 +02:00
var_model_table . setEqNums ( move ( eqnums ) ) ;
var_model_table . setLhs ( move ( lhsr ) ) ;
var_model_table . setRhs ( move ( rhsr ) ) ;
var_model_table . setLhsExprT ( move ( lhs_expr_tr ) ) ;
2018-08-21 11:46:59 +02:00
}
void
2019-10-22 16:04:24 +02:00
DynamicModel : : fillVarModelTableFromOrigModel ( ) const
2018-08-21 11:46:59 +02:00
{
2022-05-16 15:56:54 +02:00
map < string , vector < int > > lags ;
map < string , vector < optional < int > > > orig_diff_var ;
2018-08-21 11:46:59 +02:00
map < string , vector < bool > > diff ;
2021-07-06 19:04:59 +02:00
for ( const auto & [ model_name , eqns ] : var_model_table . getEqNums ( ) )
2018-08-21 11:46:59 +02:00
{
set < expr_t > lhs ;
2022-05-16 15:56:54 +02:00
vector < optional < int > > orig_diff_var_vec ;
2018-08-21 11:46:59 +02:00
vector < bool > diff_vec ;
2021-07-06 19:04:59 +02:00
for ( auto eqn : eqns )
2018-08-21 11:46:59 +02:00
{
2021-07-06 18:42:19 +02:00
// Perform some sanity checks on the RHS
2023-01-04 16:03:12 +01:00
optional < string > eqtag { equation_tags . getTagValueByEqnAndKey ( eqn , " name " ) } ;
2021-07-06 18:42:19 +02:00
set < pair < int , int > > rhs_endo_set , rhs_exo_set ;
equations [ eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : endogenous , rhs_endo_set ) ;
for ( const auto & [ symb_id , lag ] : rhs_endo_set )
2021-07-07 10:54:04 +02:00
if ( lag > 0 )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in Equation " < < eqtag . value_or ( to_string ( eqn + 1 ) )
2021-07-07 10:54:04 +02:00
< < " . A VAR model may not have leaded endogenous variables on the RHS. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
else if ( ! var_model_table . getStructural ( ) . at ( model_name ) & & lag = = 0 )
2021-07-06 18:42:19 +02:00
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in Equation " < < eqtag . value_or ( to_string ( eqn + 1 ) )
2021-07-07 10:54:04 +02:00
< < " . A non-structural VAR model may not have contemporaneous endogenous variables on the RHS. " < < endl ;
2021-07-06 18:42:19 +02:00
exit ( EXIT_FAILURE ) ;
}
2021-07-07 10:54:04 +02:00
2021-07-06 18:42:19 +02:00
equations [ eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : exogenous , rhs_exo_set ) ;
for ( const auto & [ symb_id , lag ] : rhs_exo_set )
if ( lag ! = 0 )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in Equation " < < eqtag . value_or ( to_string ( eqn + 1 ) )
2021-07-06 18:42:19 +02:00
< < " . A VAR model may not have lagged or leaded exogenous variables on the RHS. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-08-21 11:46:59 +02:00
// save lhs variables
2018-11-28 14:32:26 +01:00
equations [ eqn ] - > arg1 - > collectVARLHSVariable ( lhs ) ;
2018-08-21 11:46:59 +02:00
2018-11-28 14:32:26 +01:00
equations [ eqn ] - > arg1 - > countDiffs ( ) > 0 ?
2018-08-21 11:46:59 +02:00
diff_vec . push_back ( true ) : diff_vec . push_back ( false ) ;
if ( diff_vec . back ( ) )
{
set < pair < int , int > > diff_set ;
2018-11-28 14:32:26 +01:00
equations [ eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , diff_set ) ;
2018-08-21 11:46:59 +02:00
if ( diff_set . size ( ) ! = 1 )
{
cerr < < " ERROR: problem getting variable for LHS diff operator in equation "
< < eqn < < endl ;
exit ( EXIT_FAILURE ) ;
}
orig_diff_var_vec . push_back ( diff_set . begin ( ) - > first ) ;
}
else
2022-05-16 15:56:54 +02:00
orig_diff_var_vec . push_back ( nullopt ) ;
2018-08-21 11:46:59 +02:00
}
2021-07-06 19:04:59 +02:00
if ( eqns . size ( ) ! = lhs . size ( ) )
2018-08-21 11:46:59 +02:00
{
cerr < < " ERROR: The LHS variables of the VAR model are not unique " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2019-10-22 16:04:24 +02:00
set < expr_t > lhs_lag_equiv ;
2019-12-20 16:59:30 +01:00
for ( const auto & lh : lhs )
2019-10-22 16:04:24 +02:00
{
auto [ lag_equiv_repr , index ] = lh - > getLagEquivalenceClass ( ) ;
lhs_lag_equiv . insert ( lag_equiv_repr ) ;
}
2018-08-21 11:46:59 +02:00
vector < int > max_lag ;
2021-07-06 19:04:59 +02:00
for ( auto eqn : eqns )
2019-10-22 16:04:24 +02:00
max_lag . push_back ( equations [ eqn ] - > arg2 - > VarMaxLag ( lhs_lag_equiv ) ) ;
2021-07-06 19:04:59 +02:00
lags [ model_name ] = max_lag ;
diff [ model_name ] = diff_vec ;
orig_diff_var [ model_name ] = orig_diff_var_vec ;
2018-08-21 11:46:59 +02:00
}
2022-06-13 14:15:47 +02:00
var_model_table . setDiff ( move ( diff ) ) ;
var_model_table . setMaxLags ( move ( lags ) ) ;
var_model_table . setOrigDiffVar ( move ( orig_diff_var ) ) ;
2018-09-06 17:53:07 +02:00
}
2021-07-07 10:54:04 +02:00
vector < int >
DynamicModel : : getVARDerivIDs ( int lhs_symb_id , int lead_lag ) const
{
vector < int > deriv_ids ;
// First directly look for the variable itself
if ( auto it = deriv_id_table . find ( { lhs_symb_id , lead_lag } ) ;
it ! = deriv_id_table . end ( ) )
deriv_ids . push_back ( it - > second ) ;
// Then go through auxiliary variables
for ( auto & [ key , deriv_id2 ] : deriv_id_table )
{
auto [ symb_id2 , lead_lag2 ] = key ;
const AuxVarInfo * avi ;
try
{
avi = & symbol_table . getAuxVarInfo ( symb_id2 ) ;
}
catch ( SymbolTable : : UnknownSymbolIDException )
{
continue ;
}
2022-07-20 14:32:57 +02:00
if ( avi - > type = = AuxVarType : : endoLag & & avi - > orig_symb_id . value ( ) = = lhs_symb_id
& & avi - > orig_lead_lag . value ( ) + lead_lag2 = = lead_lag )
2021-07-07 10:54:04 +02:00
deriv_ids . push_back ( deriv_id2 ) ;
// Handle diff lag auxvar, possibly nested several times
int diff_lag_depth = 0 ;
2022-07-20 14:32:57 +02:00
while ( avi - > type = = AuxVarType : : diffLag )
2021-07-07 10:54:04 +02:00
{
diff_lag_depth + + ;
2022-07-20 14:32:57 +02:00
if ( avi - > orig_symb_id = = lhs_symb_id & & lead_lag2 - diff_lag_depth = = lead_lag )
2021-07-07 10:54:04 +02:00
{
deriv_ids . push_back ( deriv_id2 ) ;
break ;
}
try
{
2022-07-20 14:32:57 +02:00
avi = & symbol_table . getAuxVarInfo ( avi - > orig_symb_id . value ( ) ) ;
2021-07-07 10:54:04 +02:00
}
catch ( SymbolTable : : UnknownSymbolIDException )
{
break ;
}
}
}
return deriv_ids ;
}
void
DynamicModel : : fillVarModelTableMatrices ( )
{
map < string , map < tuple < int , int , int > , expr_t > > AR ;
map < string , map < tuple < int , int > , expr_t > > A0 ;
2021-07-16 15:12:37 +02:00
map < string , map < int , expr_t > > constants ;
2021-07-07 10:54:04 +02:00
for ( const auto & [ model_name , eqns ] : var_model_table . getEqNums ( ) )
{
const vector < int > & lhs = var_model_table . getLhs ( model_name ) ;
int max_lag = var_model_table . getMaxLag ( model_name ) ;
for ( auto lhs_symb_id : lhs )
{
// Fill autoregressive matrix (AR)
for ( int lag = 1 ; lag < = max_lag ; lag + + )
{
vector < int > deriv_ids = getVARDerivIDs ( lhs_symb_id , - lag ) ; ;
for ( size_t i = 0 ; i < eqns . size ( ) ; i + + )
{
expr_t d = Zero ;
for ( int deriv_id : deriv_ids )
d = AddPlus ( d , equations [ eqns [ i ] ] - > getDerivative ( deriv_id ) ) ;
if ( d ! = Zero )
{
if ( ! d - > isConstant ( ) )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: Equation " < < equation_tags . getTagValueByEqnAndKey ( eqns [ i ] , " name " ) . value_or ( to_string ( eqns [ i ] + 1 ) ) < < " is not linear " < < endl ;
2021-07-07 10:54:04 +02:00
exit ( EXIT_FAILURE ) ;
}
AR [ model_name ] [ { i , lag , lhs_symb_id } ] = AddUMinus ( d ) ;
}
}
}
// Fill A0 matrix (for contemporaneous variables)
int lhs_deriv_id = getDerivID ( lhs_symb_id , 0 ) ;
for ( size_t i = 0 ; i < eqns . size ( ) ; i + + )
{
expr_t d = equations [ eqns [ i ] ] - > getDerivative ( lhs_deriv_id ) ;
if ( d ! = Zero )
{
if ( ! d - > isConstant ( ) )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: Equation " < < equation_tags . getTagValueByEqnAndKey ( eqns [ i ] , " name " ) . value_or ( to_string ( eqns [ i ] + 1 ) ) < < " is not linear " < < endl ;
2021-07-07 10:54:04 +02:00
exit ( EXIT_FAILURE ) ;
}
A0 [ model_name ] [ { i , lhs_symb_id } ] = d ;
}
}
2021-07-16 15:12:37 +02:00
// Fill constants vector
// Constants are computed by replacing all (transformed) endos and exos by zero
constants [ model_name ] = { } ; // Ensure that the map exists, even if constants are all zero
for ( size_t i = 0 ; i < eqns . size ( ) ; i + + )
{
auto rhs = equations [ eqns [ i ] ] - > arg2 ;
map < VariableNode * , NumConstNode * > subst_table ;
auto rhs_vars = var_model_table . getRhs ( model_name ) [ i ] ; // All the (transformed) endogenous on RHS, as computed by updateVarAndTrendModel()
rhs - > collectDynamicVariables ( SymbolType : : exogenous , rhs_vars ) ; // Add exos
for ( auto [ symb_id , lag ] : rhs_vars )
subst_table [ AddVariable ( symb_id , lag ) ] = Zero ;
expr_t c = rhs - > replaceVarsInEquation ( subst_table ) ;
if ( c ! = Zero )
constants [ model_name ] [ i ] = c ;
}
2021-07-07 10:54:04 +02:00
}
}
2022-06-13 14:15:47 +02:00
var_model_table . setAR ( move ( AR ) ) ;
var_model_table . setA0 ( move ( A0 ) ) ;
var_model_table . setConstants ( move ( constants ) ) ;
2021-07-07 10:54:04 +02:00
}
2019-03-14 17:20:45 +01:00
map < string , map < tuple < int , int , int > , expr_t > >
2021-07-07 10:54:04 +02:00
DynamicModel : : computeAutoregressiveMatrices ( ) const
2019-03-14 17:20:45 +01:00
{
map < string , map < tuple < int , int , int > , expr_t > > ARr ;
2021-07-07 10:54:04 +02:00
for ( const auto & [ model_name , eqns ] : trend_component_model_table . getNonTargetEqNums ( ) )
2019-03-14 17:20:45 +01:00
{
map < tuple < int , int , int > , expr_t > AR ;
2021-07-07 10:54:04 +02:00
const vector < int > & lhs = trend_component_model_table . getNonTargetLhs ( model_name ) ;
2022-06-03 16:24:26 +02:00
for ( int i { 0 } ;
auto eqn : eqns )
2019-03-14 17:20:45 +01:00
{
2019-12-16 19:42:59 +01:00
auto bopn = dynamic_cast < BinaryOpNode * > ( equations [ eqn ] - > arg2 ) ;
2019-03-15 12:27:32 +01:00
bopn - > fillAutoregressiveRow ( i + + , lhs , AR ) ;
2019-03-14 17:20:45 +01:00
}
2021-07-06 19:04:59 +02:00
ARr [ model_name ] = AR ;
2019-03-14 17:20:45 +01:00
}
return ARr ;
}
2016-11-18 16:52:13 +01:00
void
2018-08-14 14:23:21 +02:00
DynamicModel : : fillTrendComponentModelTable ( ) const
2018-01-30 16:33:16 +01:00
{
2018-08-14 14:23:21 +02:00
map < string , vector < int > > eqnums , trend_eqnums , lhsr ;
map < string , vector < expr_t > > lhs_expr_tr ;
map < string , vector < set < pair < int , int > > > > rhsr ;
2021-07-06 19:04:59 +02:00
for ( const auto & [ model_name , eqtags ] : trend_component_model_table . getTargetEqTags ( ) )
2018-01-30 16:33:16 +01:00
{
2018-08-14 14:23:21 +02:00
vector < int > trend_eqnumber ;
2021-07-06 19:04:59 +02:00
for ( const auto & eqtag : eqtags )
2018-01-30 16:33:16 +01:00
{
2023-01-04 16:44:52 +01:00
optional < int > eqn { equation_tags . getEqnByTag ( " name " , eqtag ) } ;
if ( ! eqn )
2021-07-01 16:16:04 +02:00
{
cerr < < " ERROR: no equation is named ' " < < eqtag < < " ' " < < endl ;
2018-08-14 14:23:21 +02:00
exit ( EXIT_FAILURE ) ;
}
2023-01-04 16:44:52 +01:00
trend_eqnumber . push_back ( * eqn ) ;
2018-02-08 13:07:15 +01:00
}
2021-07-06 19:04:59 +02:00
trend_eqnums [ model_name ] = trend_eqnumber ;
2018-08-14 14:23:21 +02:00
}
2018-01-30 16:33:16 +01:00
2021-07-06 19:04:59 +02:00
for ( const auto & [ model_name , eqtags ] : trend_component_model_table . getEqTags ( ) )
2018-08-14 14:23:21 +02:00
{
vector < int > eqnumber , lhs ;
vector < expr_t > lhs_expr_t ;
vector < set < pair < int , int > > > rhs ;
2021-07-06 19:04:59 +02:00
for ( const auto & eqtag : eqtags )
2018-08-14 14:23:21 +02:00
{
set < pair < int , int > > lhs_set , lhs_tmp_set , rhs_set ;
2023-01-04 16:44:52 +01:00
optional < int > eqn { equation_tags . getEqnByTag ( " name " , eqtag ) } ;
if ( ! eqn )
2018-01-30 16:33:16 +01:00
{
2021-07-01 16:16:04 +02:00
cerr < < " ERROR: no equation is named ' " < < eqtag < < " ' " < < endl ;
2018-08-14 14:23:21 +02:00
exit ( EXIT_FAILURE ) ;
2018-01-30 16:33:16 +01:00
}
2023-01-04 16:44:52 +01:00
equations [ * eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , lhs_set ) ;
equations [ * eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : exogenous , lhs_tmp_set ) ;
equations [ * eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : parameter , lhs_tmp_set ) ;
2018-01-30 16:33:16 +01:00
2018-08-14 14:23:21 +02:00
if ( lhs_set . size ( ) ! = 1 | | ! lhs_tmp_set . empty ( ) )
{
cerr < < " ERROR: in Equation " < < eqtag
2018-09-17 14:34:25 +02:00
< < " . A trend component model may only have one endogenous variable on the LHS. " < < endl ;
2018-08-14 14:23:21 +02:00
exit ( EXIT_FAILURE ) ;
}
2018-08-23 13:03:52 +02:00
auto itlhs = lhs_set . begin ( ) ;
if ( itlhs - > second ! = 0 )
2018-08-14 14:23:21 +02:00
{
cerr < < " ERROR: in Equation " < < eqtag
2018-08-21 11:46:59 +02:00
< < " . The variable on the LHS of a trend component model may not appear with a lead or a lag. "
2018-08-14 14:23:21 +02:00
< < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-01-30 16:33:16 +01:00
2023-01-04 16:44:52 +01:00
eqnumber . push_back ( * eqn ) ;
2018-08-23 13:03:52 +02:00
lhs . push_back ( itlhs - > first ) ;
2018-08-14 14:23:21 +02:00
lhs_set . clear ( ) ;
set < expr_t > lhs_expr_t_set ;
2023-01-04 16:44:52 +01:00
equations [ * eqn ] - > arg1 - > collectVARLHSVariable ( lhs_expr_t_set ) ;
2018-08-14 14:23:21 +02:00
lhs_expr_t . push_back ( * ( lhs_expr_t_set . begin ( ) ) ) ;
2018-02-08 13:07:15 +01:00
2023-01-04 16:44:52 +01:00
equations [ * eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : endogenous , rhs_set ) ;
2018-08-14 14:23:21 +02:00
rhs . push_back ( rhs_set ) ;
}
2021-07-06 19:04:59 +02:00
eqnums [ model_name ] = eqnumber ;
lhsr [ model_name ] = lhs ;
lhs_expr_tr [ model_name ] = lhs_expr_t ;
rhsr [ model_name ] = rhs ;
2018-02-08 13:07:15 +01:00
}
2022-06-13 14:15:47 +02:00
trend_component_model_table . setRhs ( move ( rhsr ) ) ;
trend_component_model_table . setVals ( move ( eqnums ) , move ( trend_eqnums ) , move ( lhsr ) , move ( lhs_expr_tr ) ) ;
2018-09-10 17:13:51 +02:00
}
2022-01-28 16:38:50 +01:00
pair < map < string , map < tuple < int , int > , expr_t > > , map < string , map < tuple < int , int > , expr_t > > >
2021-07-01 16:16:04 +02:00
DynamicModel : : computeErrorComponentMatrices ( const ExprNode : : subst_table_t & diff_subst_table ) const
2018-09-10 17:13:51 +02:00
{
2022-01-28 16:38:50 +01:00
map < string , map < tuple < int , int > , expr_t > > A0r , A0starr ;
2019-08-19 14:51:21 +02:00
2021-07-06 19:04:59 +02:00
for ( const auto & [ model_name , eqns ] : trend_component_model_table . getEqNums ( ) )
2018-09-10 17:13:51 +02:00
{
2022-01-28 16:38:50 +01:00
map < tuple < int , int > , expr_t > A0 , A0star ;
2021-07-06 19:04:59 +02:00
vector < int > target_lhs = trend_component_model_table . getTargetLhs ( model_name ) ;
vector < int > nontarget_eqnums = trend_component_model_table . getNonTargetEqNums ( model_name ) ;
vector < int > undiff_nontarget_lhs = getUndiffLHSForPac ( model_name , diff_subst_table ) ;
2019-02-14 11:44:06 +01:00
vector < int > parsed_undiff_nontarget_lhs ;
2018-09-12 17:56:30 +02:00
2022-06-03 16:24:26 +02:00
for ( int i { 0 } ;
auto eqn : eqns )
2018-09-12 17:56:30 +02:00
{
2019-02-14 11:44:06 +01:00
if ( find ( nontarget_eqnums . begin ( ) , nontarget_eqnums . end ( ) , eqn ) ! = nontarget_eqnums . end ( ) )
parsed_undiff_nontarget_lhs . push_back ( undiff_nontarget_lhs . at ( i ) ) ;
2018-09-12 17:56:30 +02:00
i + + ;
}
2022-06-03 16:24:26 +02:00
for ( int i { 0 } ;
auto eqn : eqns )
2019-02-14 11:44:06 +01:00
if ( find ( nontarget_eqnums . begin ( ) , nontarget_eqnums . end ( ) , eqn ) ! = nontarget_eqnums . end ( ) )
2019-02-19 12:08:00 +01:00
equations [ eqn ] - > arg2 - > fillErrorCorrectionRow ( i + + , parsed_undiff_nontarget_lhs , target_lhs , A0 , A0star ) ;
2021-07-06 19:04:59 +02:00
A0r [ model_name ] = A0 ;
A0starr [ model_name ] = A0star ;
2018-09-10 17:13:51 +02:00
}
2019-08-19 14:51:21 +02:00
return { A0r , A0starr } ;
2018-02-08 13:07:15 +01:00
}
2018-05-16 12:17:06 +02:00
void
2019-10-22 16:04:24 +02:00
DynamicModel : : fillTrendComponentModelTableFromOrigModel ( ) const
2018-05-16 12:17:06 +02:00
{
2022-05-16 15:56:54 +02:00
map < string , vector < int > > lags ;
map < string , vector < optional < int > > > orig_diff_var ;
2018-08-14 14:23:21 +02:00
map < string , vector < bool > > diff ;
2021-07-06 19:04:59 +02:00
for ( const auto & [ model_name , eqns ] : trend_component_model_table . getEqNums ( ) )
2018-05-16 12:17:06 +02:00
{
2018-08-14 14:23:21 +02:00
set < expr_t > lhs ;
2022-05-16 15:56:54 +02:00
vector < optional < int > > orig_diff_var_vec ;
2018-08-14 14:23:21 +02:00
vector < bool > diff_vec ;
2021-07-06 19:04:59 +02:00
for ( auto eqn : eqns )
2018-05-16 12:17:06 +02:00
{
2021-07-06 18:42:19 +02:00
// Perform some sanity checks on the RHS
2023-01-04 16:03:12 +01:00
optional < string > eqtag { equation_tags . getTagValueByEqnAndKey ( eqn , " name " ) } ;
2021-07-06 18:42:19 +02:00
set < pair < int , int > > rhs_endo_set , rhs_exo_set ;
equations [ eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : endogenous , rhs_endo_set ) ;
for ( const auto & [ symb_id , lag ] : rhs_endo_set )
if ( lag > = 0 )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in Equation " < < eqtag . value_or ( to_string ( eqn + 1 ) )
2021-07-06 18:42:19 +02:00
< < " . A trend component model may not have leaded or contemporaneous endogenous variables on the RHS. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
equations [ eqn ] - > arg2 - > collectDynamicVariables ( SymbolType : : exogenous , rhs_exo_set ) ;
for ( const auto & [ symb_id , lag ] : rhs_exo_set )
if ( lag ! = 0 )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in Equation " < < eqtag . value_or ( to_string ( eqn + 1 ) )
2021-07-06 18:42:19 +02:00
< < " . A trend component model may not have lagged or leaded exogenous variables on the RHS. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-05-31 15:34:25 +02:00
2018-08-14 14:23:21 +02:00
// save lhs variables
2018-11-28 14:32:26 +01:00
equations [ eqn ] - > arg1 - > collectVARLHSVariable ( lhs ) ;
2018-04-16 13:50:31 +02:00
2019-12-16 19:42:59 +01:00
if ( equations [ eqn ] - > arg1 - > countDiffs ( ) > 0 )
diff_vec . push_back ( true ) ;
else
diff_vec . push_back ( false ) ;
2018-08-14 14:23:21 +02:00
if ( diff_vec . back ( ) )
{
set < pair < int , int > > diff_set ;
2018-11-28 14:32:26 +01:00
equations [ eqn ] - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , diff_set ) ;
2018-04-16 13:50:31 +02:00
2018-08-14 14:23:21 +02:00
if ( diff_set . size ( ) ! = 1 )
{
cerr < < " ERROR: problem getting variable for LHS diff operator in equation "
< < eqn < < endl ;
exit ( EXIT_FAILURE ) ;
}
orig_diff_var_vec . push_back ( diff_set . begin ( ) - > first ) ;
}
else
2022-05-16 15:56:54 +02:00
orig_diff_var_vec . push_back ( nullopt ) ;
2018-08-14 14:23:21 +02:00
}
2018-04-16 13:50:31 +02:00
2021-07-06 19:04:59 +02:00
if ( eqns . size ( ) ! = lhs . size ( ) )
2018-02-08 13:07:15 +01:00
{
2018-08-21 11:46:59 +02:00
cerr < < " ERROR: The LHS variables of the trend component model are not unique " < < endl ;
2018-08-14 14:23:21 +02:00
exit ( EXIT_FAILURE ) ;
2018-02-08 13:07:15 +01:00
}
2018-08-14 14:23:21 +02:00
2019-10-22 16:04:24 +02:00
set < expr_t > lhs_lag_equiv ;
2019-12-20 16:59:30 +01:00
for ( const auto & lh : lhs )
2019-10-22 16:04:24 +02:00
{
auto [ lag_equiv_repr , index ] = lh - > getLagEquivalenceClass ( ) ;
lhs_lag_equiv . insert ( lag_equiv_repr ) ;
}
2018-08-14 14:23:21 +02:00
vector < int > max_lag ;
2021-07-06 19:04:59 +02:00
for ( auto eqn : eqns )
2019-10-22 16:04:24 +02:00
max_lag . push_back ( equations [ eqn ] - > arg2 - > VarMaxLag ( lhs_lag_equiv ) ) ;
2021-07-06 19:04:59 +02:00
lags [ model_name ] = max_lag ;
diff [ model_name ] = diff_vec ;
orig_diff_var [ model_name ] = orig_diff_var_vec ;
2018-01-30 16:33:16 +01:00
}
2022-06-13 14:15:47 +02:00
trend_component_model_table . setDiff ( move ( diff ) ) ;
trend_component_model_table . setMaxLags ( move ( lags ) ) ;
trend_component_model_table . setOrigDiffVar ( move ( orig_diff_var ) ) ;
2018-01-30 16:33:16 +01:00
}
2018-08-21 11:46:59 +02:00
2018-09-12 17:56:30 +02:00
void
2021-07-01 16:16:04 +02:00
DynamicModel : : fillTrendComponentModelTableAREC ( const ExprNode : : subst_table_t & diff_subst_table ) const
2018-09-12 17:56:30 +02:00
{
2021-07-07 10:54:04 +02:00
auto ARr = computeAutoregressiveMatrices ( ) ;
2022-06-13 14:15:47 +02:00
trend_component_model_table . setAR ( move ( ARr ) ) ;
2021-07-01 16:16:04 +02:00
auto [ A0r , A0starr ] = computeErrorComponentMatrices ( diff_subst_table ) ;
2022-06-13 14:15:47 +02:00
trend_component_model_table . setA0 ( move ( A0r ) , move ( A0starr ) ) ;
2018-09-12 17:56:30 +02:00
}
2018-08-14 14:23:21 +02:00
vector < int >
DynamicModel : : getUndiffLHSForPac ( const string & aux_model_name ,
2019-08-19 14:51:21 +02:00
const ExprNode : : subst_table_t & diff_subst_table ) const
2018-03-28 18:46:15 +02:00
{
2018-08-14 14:23:21 +02:00
vector < expr_t > lhs_expr_t = trend_component_model_table . getLhsExprT ( aux_model_name ) ;
vector < int > lhs = trend_component_model_table . getLhs ( aux_model_name ) ;
vector < bool > diff = trend_component_model_table . getDiff ( aux_model_name ) ;
vector < int > eqnumber = trend_component_model_table . getEqNums ( aux_model_name ) ;
2018-09-13 12:21:23 +02:00
vector < int > nontrend_eqnums = trend_component_model_table . getNonTargetEqNums ( aux_model_name ) ;
2018-08-14 14:23:21 +02:00
for ( auto eqn : nontrend_eqnums )
2018-03-28 18:46:15 +02:00
{
2022-06-02 10:50:21 +02:00
auto i = distance ( eqnumber . begin ( ) , find ( eqnumber . begin ( ) , eqnumber . end ( ) , eqn ) ) ;
2018-03-28 18:46:15 +02:00
2018-04-17 15:17:28 +02:00
if ( eqnumber [ i ] ! = eqn )
2018-03-28 18:46:15 +02:00
{
2018-05-28 15:54:20 +02:00
cerr < < " ERROR: equation " < < eqn < < " not found in VAR " < < endl ;
2018-03-28 18:46:15 +02:00
exit ( EXIT_FAILURE ) ;
}
2018-05-28 15:55:01 +02:00
if ( diff . at ( i ) ! = true )
2018-03-28 18:46:15 +02:00
{
2018-08-14 14:23:21 +02:00
cerr < < " ERROR: the variable on the LHS of equation # " < < eqn
< < " does not have the diff operator applied to it yet you are trying to undiff it. "
< < endl ;
2018-03-28 18:46:15 +02:00
exit ( EXIT_FAILURE ) ;
}
2018-04-17 15:17:28 +02:00
bool printerr = false ;
2018-06-04 12:52:14 +02:00
expr_t node = nullptr ;
2018-04-17 15:17:28 +02:00
expr_t aux_var = lhs_expr_t . at ( i ) ;
2019-12-16 19:42:59 +01:00
for ( const auto & it : diff_subst_table )
if ( it . second = = aux_var )
2018-04-17 15:17:28 +02:00
{
2019-12-16 19:42:59 +01:00
node = const_cast < expr_t > ( it . first ) ;
2018-04-17 15:17:28 +02:00
break ;
}
2019-12-16 19:42:59 +01:00
if ( ! node )
2018-04-17 15:17:28 +02:00
{
cerr < < " Unexpected error encountered. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-08-14 14:23:21 +02:00
node = node - > undiff ( ) ;
2019-12-16 19:42:59 +01:00
auto it1 = diff_subst_table . find ( node ) ;
2018-08-14 14:23:21 +02:00
if ( it1 = = diff_subst_table . end ( ) )
printerr = true ;
2018-04-17 15:17:28 +02:00
if ( printerr )
{ // we have undiffed something like diff(x), hence x is not in diff_subst_table
lhs_expr_t . at ( i ) = node ;
2018-11-28 14:32:26 +01:00
lhs . at ( i ) = dynamic_cast < VariableNode * > ( node ) - > symb_id ;
2018-04-17 15:17:28 +02:00
}
else
{
lhs_expr_t . at ( i ) = const_cast < expr_t > ( it1 - > first ) ;
2018-11-28 14:32:26 +01:00
lhs . at ( i ) = const_cast < VariableNode * > ( it1 - > second ) - > symb_id ;
2018-04-17 15:17:28 +02:00
}
2018-03-28 18:46:15 +02:00
}
2018-08-14 14:23:21 +02:00
return lhs ;
2018-03-28 18:46:15 +02:00
}
2021-10-27 18:17:14 +02:00
void
2021-10-28 14:42:56 +02:00
DynamicModel : : analyzePacEquationStructure ( const string & name , map < string , string > & pac_eq_name , PacModelTable : : equation_info_t & pac_equation_info )
2018-02-12 17:37:53 +01:00
{
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2021-10-28 14:42:56 +02:00
if ( equation - > containsPacExpectation ( name ) )
{
if ( ! pac_eq_name [ name ] . empty ( ) )
{
cerr < < " It is not possible to use 'pac_expectation( " < < name < < " )' in several equations. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2023-01-04 16:03:12 +01:00
optional < string > eqn { equation_tags . getTagValueByEqnAndKey ( & equation - & equations [ 0 ] , " name " ) } ;
if ( ! eqn )
2021-10-28 14:42:56 +02:00
{
cerr < < " Every equation with a 'pac_expectation' operator must have been assigned an equation tag name " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2023-01-04 16:03:12 +01:00
pac_eq_name [ name ] = * eqn ;
2018-08-09 16:14:40 +02:00
2021-10-28 14:42:56 +02:00
set < pair < int , int > > lhss ;
equation - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , lhss ) ;
auto lhs = * lhss . begin ( ) ;
int lhs_symb_id = lhs . first ;
int lhs_orig_symb_id = lhs_symb_id ;
2022-01-28 16:28:14 +01:00
if ( symbol_table . isDiffAuxiliaryVariable ( lhs_orig_symb_id ) )
2021-10-28 14:42:56 +02:00
try
{
lhs_orig_symb_id = symbol_table . getOrigSymbIdForAuxVar ( lhs_orig_symb_id ) ;
}
catch ( . . . )
{
}
auto arg2 = dynamic_cast < BinaryOpNode * > ( equation - > arg2 ) ;
if ( ! arg2 )
{
cerr < < " Pac equation in incorrect format " < < endl ;
exit ( EXIT_FAILURE ) ;
}
auto [ optim_share_index , optim_part , non_optim_part , additive_part ]
2022-06-24 15:45:35 +02:00
= arg2 - > getPacOptimizingShareAndExprNodes ( lhs_orig_symb_id ) ;
2021-10-28 14:42:56 +02:00
pair < int , vector < tuple < int , bool , int > > > ec_params_and_vars ;
2022-05-16 17:42:24 +02:00
vector < tuple < optional < int > , optional < int > , int > > ar_params_and_vars ;
vector < tuple < int , int , optional < int > , double > > non_optim_vars_params_and_constants , optim_additive_vars_params_and_constants , additive_vars_params_and_constants ;
2021-10-28 14:42:56 +02:00
if ( ! optim_part )
{
auto bopn = dynamic_cast < BinaryOpNode * > ( equation - > arg2 ) ;
if ( ! bopn )
{
cerr < < " Error in PAC equation " < < endl ;
exit ( EXIT_FAILURE ) ;
}
bopn - > getPacAREC ( lhs_symb_id , lhs_orig_symb_id , ec_params_and_vars , ar_params_and_vars , additive_vars_params_and_constants ) ;
}
else
{
auto bopn = dynamic_cast < BinaryOpNode * > ( optim_part ) ;
if ( ! bopn )
{
cerr < < " Error in PAC equation " < < endl ;
exit ( EXIT_FAILURE ) ;
}
bopn - > getPacAREC ( lhs_symb_id , lhs_orig_symb_id , ec_params_and_vars , ar_params_and_vars , optim_additive_vars_params_and_constants ) ;
2018-09-04 10:39:05 +02:00
try
{
2021-10-28 14:42:56 +02:00
non_optim_vars_params_and_constants = non_optim_part - > matchLinearCombinationOfVariables ( ) ;
if ( additive_part )
additive_vars_params_and_constants = additive_part - > matchLinearCombinationOfVariables ( ) ;
2018-09-04 10:39:05 +02:00
}
2021-10-28 14:42:56 +02:00
catch ( ExprNode : : MatchFailureException & e )
2018-09-04 10:39:05 +02:00
{
2021-10-28 14:42:56 +02:00
cerr < < " Error in parsing non-optimizing agents or additive part of PAC equation: "
< < e . message < < endl ;
exit ( EXIT_FAILURE ) ;
2018-09-04 10:39:05 +02:00
}
2021-10-28 14:42:56 +02:00
}
2018-09-04 10:39:05 +02:00
2021-10-28 14:42:56 +02:00
if ( lhs . first = = - 1 )
{
cerr < < " analyzePacEquationStructure: error obtaining LHS variable. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( ec_params_and_vars . second . empty ( ) )
{
cerr < < " analyzePacEquationStructure: error obtaining RHS parameters. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2022-05-16 17:42:58 +02:00
pac_equation_info [ name ] = { lhs , move ( optim_share_index ) ,
move ( ar_params_and_vars ) , move ( ec_params_and_vars ) ,
move ( non_optim_vars_params_and_constants ) ,
move ( additive_vars_params_and_constants ) ,
move ( optim_additive_vars_params_and_constants ) } ;
2021-10-28 14:42:56 +02:00
}
2018-02-12 17:37:53 +01:00
}
2019-02-15 12:52:46 +01:00
int
DynamicModel : : getPacTargetSymbId ( const string & pac_model_name ) const
{
2020-07-23 14:45:32 +02:00
for ( auto equation : equations )
2019-02-15 12:52:46 +01:00
if ( equation - > containsPacExpectation ( pac_model_name ) )
{
2019-02-20 12:59:55 +01:00
set < pair < int , int > > lhss ;
equation - > arg1 - > collectDynamicVariables ( SymbolType : : endogenous , lhss ) ;
2020-07-23 14:45:32 +02:00
if ( lhss . size ( ) ! = 1 )
throw PacTargetNotIdentifiedException { pac_model_name , " LHS must contain a single endogenous " } ;
2020-07-10 14:55:28 +02:00
int lhs_symb_id = lhss . begin ( ) - > first ;
2020-07-23 14:45:32 +02:00
if ( ! symbol_table . isDiffAuxiliaryVariable ( lhs_symb_id ) )
throw PacTargetNotIdentifiedException { pac_model_name , " LHS must be a diff operator " } ;
int undiff_lhs_symb_id = symbol_table . getOrigSymbIdForAuxVar ( lhs_symb_id ) ;
auto barg2 = dynamic_cast < BinaryOpNode * > ( equation - > arg2 ) ;
if ( ! barg2 )
throw PacTargetNotIdentifiedException { pac_model_name , " RHS must be a binary operator " } ;
auto [ optim_share_index , optim_part , non_optim_part , additive_part ]
2022-06-24 15:45:35 +02:00
= barg2 - > getPacOptimizingShareAndExprNodes ( undiff_lhs_symb_id ) ;
2020-07-23 14:45:32 +02:00
/* If there is an optimization part, restrict the search to that part,
since it contains the MCE . */
expr_t mce = optim_part ? optim_part : equation - > arg2 ;
vector < pair < expr_t , int > > terms ;
mce - > decomposeAdditiveTerms ( terms ) ;
for ( auto [ term , sign ] : terms )
2019-02-15 12:52:46 +01:00
try
{
2020-07-23 14:45:32 +02:00
auto [ param_id , target_id ] = term - > matchParamTimesTargetMinusVariable ( undiff_lhs_symb_id ) ;
return target_id ;
2019-02-15 12:52:46 +01:00
}
2020-07-23 14:45:32 +02:00
catch ( ExprNode : : MatchFailureException & )
2019-02-15 12:52:46 +01:00
{
}
2020-07-23 14:45:32 +02:00
throw PacTargetNotIdentifiedException { pac_model_name , " No term of the form parameter*(target-LHS_level) " } ;
2019-02-15 12:52:46 +01:00
}
2020-07-23 14:45:32 +02:00
throw PacTargetNotIdentifiedException { pac_model_name , " No equation with the corresponding pac_expectation operator " } ;
2019-02-15 12:52:46 +01:00
}
2019-02-19 16:36:10 +01:00
void
2021-11-16 17:58:20 +01:00
DynamicModel : : computePacModelConsistentExpectationSubstitution ( const string & name ,
int discount_symb_id ,
int pac_eq_max_lag ,
expr_t growth_correction_term ,
2021-11-18 17:08:08 +01:00
string auxname ,
2021-11-16 17:58:20 +01:00
ExprNode : : subst_table_t & diff_subst_table ,
map < string , int > & pac_aux_var_symb_ids ,
2021-11-17 18:12:29 +01:00
map < string , vector < int > > & pac_aux_param_symb_ids ,
2021-11-16 17:58:20 +01:00
map < string , expr_t > & pac_expectation_substitution )
2019-02-15 12:52:46 +01:00
{
2020-07-23 14:45:32 +02:00
int pac_target_symb_id ;
try
{
pac_target_symb_id = getPacTargetSymbId ( name ) ;
}
catch ( PacTargetNotIdentifiedException & e )
{
cerr < < " Can't identify target for PAC model " < < name < < " : " < < e . message ;
exit ( EXIT_FAILURE ) ;
}
2019-02-19 16:36:10 +01:00
int neqs = 0 ;
2021-10-27 18:17:14 +02:00
2021-11-17 12:15:49 +01:00
// Create the endogenous representing Z₁ (no orig_expr is given since its definition is recursive)
2021-11-18 17:08:08 +01:00
if ( auxname . empty ( ) )
auxname = " mce_Z1_ " + name ;
int mce_z1_symb_id = symbol_table . addPacExpectationAuxiliaryVar ( auxname , nullptr ) ;
2021-11-16 17:58:20 +01:00
pac_aux_var_symb_ids [ name ] = mce_z1_symb_id ;
2021-10-27 18:17:14 +02:00
2021-10-28 14:42:56 +02:00
expr_t A = One ;
expr_t fp = Zero ;
expr_t beta = AddVariable ( discount_symb_id ) ;
for ( int i = 1 ; i < = pac_eq_max_lag + 1 ; i + + )
{
string param_name = " mce_alpha_ " + name + " _ " + to_string ( i ) ;
2021-10-27 18:17:14 +02:00
try
2019-02-19 16:36:10 +01:00
{
2021-10-28 14:42:56 +02:00
int alpha_i_symb_id = symbol_table . addSymbol ( param_name , SymbolType : : parameter ) ;
2021-11-17 18:12:29 +01:00
pac_aux_param_symb_ids [ name ] . push_back ( alpha_i_symb_id ) ;
2021-10-28 14:42:56 +02:00
A = AddPlus ( A , AddVariable ( alpha_i_symb_id ) ) ;
fp = AddPlus ( fp ,
AddTimes ( AddTimes ( AddVariable ( alpha_i_symb_id ) ,
AddPower ( beta , AddPossiblyNegativeConstant ( i ) ) ) ,
AddVariable ( mce_z1_symb_id , i ) ) ) ;
2021-10-27 18:17:14 +02:00
}
catch ( SymbolTable : : AlreadyDeclaredException & e )
{
2021-10-28 14:42:56 +02:00
cerr < < " The variable/parameter ' " < < param_name < < " ' conflicts with a parameter that will be generated for the ' " < < name < < " ' PAC model. Please rename it. " < < endl ;
2019-02-19 16:36:10 +01:00
exit ( EXIT_FAILURE ) ;
}
2021-10-28 14:42:56 +02:00
}
2019-02-15 12:52:46 +01:00
2021-10-28 14:42:56 +02:00
// Add diff nodes and eqs for pac_target_symb_id
const VariableNode * target_base_diff_node ;
auto create_target_lag = [ & ] ( int lag )
{
if ( symbol_table . isAuxiliaryVariable ( pac_target_symb_id ) )
2022-01-28 16:28:14 +01:00
// We know it is a log, see ExprNode::matchParamTimesTargetMinusVariable()
return AddLog ( AddVariable ( symbol_table . getOrigSymbIdForAuxVar ( pac_target_symb_id ) , lag ) ) ;
2021-10-28 14:42:56 +02:00
else
return dynamic_cast < ExprNode * > ( AddVariable ( pac_target_symb_id , lag ) ) ;
} ;
2020-07-24 12:28:13 +02:00
2021-10-28 14:42:56 +02:00
expr_t diff_node_to_search = AddDiff ( create_target_lag ( 0 ) ) ;
if ( auto sit = diff_subst_table . find ( diff_node_to_search ) ;
sit ! = diff_subst_table . end ( ) )
target_base_diff_node = sit - > second ;
else
{
int symb_id = symbol_table . addDiffAuxiliaryVar ( diff_node_to_search - > idx , diff_node_to_search ) ;
target_base_diff_node = AddVariable ( symb_id ) ;
auto neweq = AddEqual ( const_cast < VariableNode * > ( target_base_diff_node ) ,
AddMinus ( create_target_lag ( 0 ) ,
create_target_lag ( - 1 ) ) ) ;
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2021-10-28 14:42:56 +02:00
addAuxEquation ( neweq ) ;
neqs + + ;
}
2019-02-15 12:52:46 +01:00
2021-10-28 14:42:56 +02:00
map < int , VariableNode * > target_aux_var_to_add ;
const VariableNode * last_aux_var = target_base_diff_node ;
for ( int i = 1 ; i < = pac_eq_max_lag ; i + + , neqs + + )
{
expr_t this_diff_node = AddDiff ( create_target_lag ( i ) ) ;
int symb_id = symbol_table . addDiffLeadAuxiliaryVar ( this_diff_node - > idx , this_diff_node ,
2022-01-27 18:38:25 +01:00
last_aux_var - > symb_id , 1 ) ;
2021-10-28 14:42:56 +02:00
VariableNode * current_aux_var = AddVariable ( symb_id ) ;
auto neweq = AddEqual ( current_aux_var , AddVariable ( last_aux_var - > symb_id , 1 ) ) ;
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2021-10-28 14:42:56 +02:00
addAuxEquation ( neweq ) ;
last_aux_var = current_aux_var ;
target_aux_var_to_add [ i ] = current_aux_var ;
}
2019-02-15 12:52:46 +01:00
2021-10-28 14:42:56 +02:00
expr_t fs = Zero ;
for ( int k = 1 ; k < = pac_eq_max_lag ; k + + )
{
expr_t ssum = Zero ;
for ( int j = k + 1 ; j < = pac_eq_max_lag + 1 ; j + + )
2019-02-15 12:52:46 +01:00
{
2021-10-28 14:42:56 +02:00
int alpha_j_symb_id = - 1 ;
string param_name = " mce_alpha_ " + name + " _ " + to_string ( j ) ;
try
2019-02-15 12:52:46 +01:00
{
2021-10-28 14:42:56 +02:00
alpha_j_symb_id = symbol_table . getID ( param_name ) ;
2019-02-15 12:52:46 +01:00
}
2021-10-28 14:42:56 +02:00
catch ( SymbolTable : : UnknownSymbolNameException & e )
{
alpha_j_symb_id = symbol_table . addSymbol ( param_name , SymbolType : : parameter ) ;
}
ssum = AddPlus ( ssum ,
AddTimes ( AddVariable ( alpha_j_symb_id ) , AddPower ( beta , AddPossiblyNegativeConstant ( j ) ) ) ) ;
2019-02-15 12:52:46 +01:00
}
2021-10-28 14:42:56 +02:00
fs = AddPlus ( fs , AddTimes ( ssum , target_aux_var_to_add [ k ] ) ) ;
2019-02-15 12:52:46 +01:00
}
2021-10-28 14:42:56 +02:00
auto neweq = AddEqual ( AddVariable ( mce_z1_symb_id ) ,
AddMinus ( AddTimes ( A , AddMinus ( const_cast < VariableNode * > ( target_base_diff_node ) , fs ) ) , fp ) ) ;
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2021-11-17 12:15:49 +01:00
/* This equation is not added to the list of auxiliary equations, because it
is recursive , and this would in particular break dynamic_set_auxiliary_series . m */
2021-10-28 14:42:56 +02:00
neqs + + ;
2021-10-27 18:17:14 +02:00
cout < < " PAC Model Consistent Expectation: added " < < neqs < < " auxiliary variables and equations for model " < < name < < " . " < < endl ;
2019-02-15 12:52:46 +01:00
2021-10-28 14:42:56 +02:00
/* The growth correction term is not added to the definition of Z₁
because the latter is recursive . Rather put it at the level of the
substition of pac_expectation operator . */
2021-11-16 17:58:20 +01:00
pac_expectation_substitution [ name ] = AddPlus ( AddVariable ( mce_z1_symb_id ) , growth_correction_term ) ;
2021-08-31 17:54:20 +02:00
}
2018-01-30 16:33:16 +01:00
void
2021-10-27 18:17:14 +02:00
DynamicModel : : computePacBackwardExpectationSubstitution ( const string & name ,
const vector < int > & lhs ,
int max_lag ,
const string & aux_model_type ,
2021-10-28 14:42:56 +02:00
expr_t growth_correction_term ,
2021-11-18 17:08:08 +01:00
string auxname ,
2021-11-16 17:58:20 +01:00
map < string , int > & pac_aux_var_symb_ids ,
2021-11-17 18:12:29 +01:00
map < string , vector < int > > & pac_aux_param_symb_ids ,
2021-10-28 14:42:56 +02:00
map < string , expr_t > & pac_expectation_substitution )
2018-01-30 16:33:16 +01:00
{
2021-11-09 14:34:21 +01:00
auto create_aux_param = [ & ] ( const string & param_name )
{
try
{
return symbol_table . addSymbol ( param_name , SymbolType : : parameter ) ;
}
catch ( SymbolTable : : AlreadyDeclaredException )
{
cerr < < " ERROR: the variable/parameter ' " < < param_name < < " ' conflicts with some auxiliary parameter that will be generated for the ' " < < name < < " ' PAC model. Please rename that parameter. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
} ;
2021-10-28 14:42:56 +02:00
expr_t subExpr = Zero ;
2021-11-17 18:12:29 +01:00
if ( aux_model_type = = " var " )
2021-10-28 14:42:56 +02:00
{
2021-11-17 18:12:29 +01:00
/* If the auxiliary model is a VAR, add a parameter corresponding
to the constant . */
int new_param_symb_id = create_aux_param ( " h_ " + name + " _constant " ) ;
pac_aux_param_symb_ids [ name ] . push_back ( new_param_symb_id ) ;
subExpr = AddPlus ( subExpr , AddVariable ( new_param_symb_id ) ) ;
2018-01-30 16:33:16 +01:00
}
2021-11-17 18:12:29 +01:00
for ( int i = 1 ; i < max_lag + 1 ; i + + )
for ( auto lhsit : lhs )
{
int new_param_symb_id = create_aux_param ( " h_ " + name + " _var_ "
+ symbol_table . getName ( lhsit )
+ " _lag_ " + to_string ( i ) ) ;
pac_aux_param_symb_ids [ name ] . push_back ( new_param_symb_id ) ;
subExpr = AddPlus ( subExpr ,
AddTimes ( AddVariable ( new_param_symb_id ) ,
AddVariable ( lhsit , - i ) ) ) ;
}
2021-10-28 14:42:56 +02:00
2021-11-17 12:15:49 +01:00
subExpr = AddPlus ( subExpr , growth_correction_term ) ;
2021-11-16 17:58:20 +01:00
2021-11-18 17:08:08 +01:00
if ( auxname . empty ( ) )
auxname = " pac_expectation_ " + name ;
int expect_var_id = symbol_table . addPacExpectationAuxiliaryVar ( auxname , subExpr ) ;
2021-11-17 12:15:49 +01:00
expr_t neweq = AddEqual ( AddVariable ( expect_var_id ) , subExpr ) ;
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2021-11-17 12:15:49 +01:00
addAuxEquation ( neweq ) ;
2021-11-16 17:58:20 +01:00
pac_aux_var_symb_ids [ name ] = expect_var_id ;
pac_expectation_substitution [ name ] = AddVariable ( expect_var_id ) ;
2019-02-20 12:59:55 +01:00
}
2021-10-26 18:06:26 +02:00
void
DynamicModel : : computePacBackwardExpectationSubstitutionWithComponents ( const string & name ,
const vector < int > & lhs ,
int max_lag ,
const string & aux_model_type ,
vector < PacModelTable : : target_component_t > & pac_target_components ,
map < string , expr_t > & pac_expectation_substitution )
{
auto create_aux_param = [ & ] ( const string & param_name )
{
try
{
return symbol_table . addSymbol ( param_name , SymbolType : : parameter ) ;
}
catch ( SymbolTable : : AlreadyDeclaredException )
{
cerr < < " ERROR: the variable/parameter ' " < < param_name < < " ' conflicts with some auxiliary parameter that will be generated for the ' " < < name < < " ' PAC model. Please rename that parameter. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
} ;
expr_t substexpr = Zero ;
2022-06-03 16:24:26 +02:00
for ( int component_idx { 1 } ;
auto & [ component , growth , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth , growth_info ] : pac_target_components )
2021-10-26 18:06:26 +02:00
{
string name_component = name + " _component " + to_string ( component_idx ) ;
// Create the linear combination of the variables from the auxiliary model
expr_t auxdef = Zero ;
if ( aux_model_type = = " var " )
{
/* If the auxiliary model is a VAR, add a parameter corresponding
to the constant . */
int new_param_symb_id = create_aux_param ( " h_ " + name_component + " _constant " ) ;
h_indices . push_back ( new_param_symb_id ) ;
auxdef = AddPlus ( auxdef , AddVariable ( new_param_symb_id ) ) ;
}
for ( int i = 1 ; i < max_lag + 1 ; i + + )
for ( auto lhsit : lhs )
{
int new_param_symb_id = create_aux_param ( " h_ " + name_component + " _var_ " + symbol_table . getName ( lhsit ) + " _lag_ " + to_string ( i ) ) ;
h_indices . push_back ( new_param_symb_id ) ;
auxdef = AddPlus ( auxdef , AddTimes ( AddVariable ( new_param_symb_id ) ,
AddVariable ( lhsit , - i ) ) ) ;
}
// If needed, add the growth neutrality correction for this component
if ( growth )
{
growth_neutrality_param = create_aux_param ( name_component + " _pac_growth_neutrality_correction " ) ;
auxdef = AddPlus ( auxdef , AddTimes ( growth , AddVariable ( growth_neutrality_param ) ) ) ;
}
else
growth_neutrality_param = - 1 ;
// Create the auxiliary variable for this component
int aux_id = symbol_table . addPacExpectationAuxiliaryVar ( auxname , auxdef ) ;
expr_t auxvar = AddVariable ( aux_id ) ;
// Add the equation defining the auxiliary variable for this component
expr_t neweq = AddEqual ( auxvar , auxdef ) ;
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2021-10-26 18:06:26 +02:00
addAuxEquation ( neweq ) ;
// Update the expression to be substituted for the pac_expectation operator
substexpr = AddPlus ( substexpr , AddTimes ( coeff , auxvar ) ) ;
component_idx + + ;
}
pac_expectation_substitution [ name ] = substexpr ;
}
2019-02-20 12:59:55 +01:00
void
2021-10-28 14:42:56 +02:00
DynamicModel : : substitutePacExpectation ( const map < string , expr_t > & pac_expectation_substitution ,
const map < string , string > & pac_eq_name )
2019-02-20 12:59:55 +01:00
{
2021-10-28 14:42:56 +02:00
for ( auto & [ model_name , substexpr ] : pac_expectation_substitution )
2021-10-27 18:17:14 +02:00
{
2023-01-04 16:44:52 +01:00
optional < int > eq { equation_tags . getEqnByTag ( " name " , pac_eq_name . at ( model_name ) ) } ;
auto substeq = dynamic_cast < BinaryOpNode * > ( equations [ eq . value ( ) ] - > substitutePacExpectation ( model_name , substexpr ) ) ;
2021-10-27 18:17:14 +02:00
assert ( substeq ) ;
2023-01-04 16:44:52 +01:00
equations [ eq . value ( ) ] = substeq ;
2021-10-27 18:17:14 +02:00
}
2018-01-30 16:33:16 +01:00
}
2021-10-26 18:06:26 +02:00
void
DynamicModel : : substitutePacTargetNonstationary ( const string & pac_model_name , expr_t substexpr )
{
for ( auto & eq : equations )
eq = dynamic_cast < BinaryOpNode * > ( eq - > substitutePacTargetNonstationary ( pac_model_name , substexpr ) ) ;
}
2009-04-14 16:39:53 +02:00
void
2022-10-07 14:37:25 +02:00
DynamicModel : : computingPass ( int derivsOrder , int paramsDerivsOrder , const eval_context_t & eval_context ,
bool no_tmp_terms , bool block , bool use_dll )
2009-04-14 16:39:53 +02:00
{
2011-06-22 11:34:25 +02:00
initializeVariablesAndEquations ( ) ;
2017-06-01 19:58:32 +02:00
2009-09-30 17:10:31 +02:00
// Prepare for derivation
computeDerivIDs ( ) ;
// Computes dynamic jacobian columns, must be done after computeDerivIDs()
2022-10-07 14:37:25 +02:00
computeDynJacobianCols ( ) ;
2009-04-14 16:39:53 +02:00
2022-01-21 14:31:29 +01:00
/* In both MATLAB and Julia, tensors for higher-order derivatives are stored
in matrices whose columns correspond to variable multi - indices . Since we
currently are limited to 32 - bit signed integers ( hence 31 bits ) for matrix
indices , check that we will not overflow ( see # 89 ) . Note that such a check
is not needed for parameter derivatives , since tensors for those are not
stored as matrices . This check cannot be done before since
2022-09-14 17:07:08 +02:00
getJacobianColsNbr ( ) is not yet set .
We only do the check for the legacy representation , since the sparse
representation is not affected by this problem ( TODO : thus the check can be
removed once the legacy representation is dropped ) . */
if ( log2 ( getJacobianColsNbr ( false ) ) * derivsOrder > = numeric_limits < int > : : digits )
2022-01-21 14:31:29 +01:00
{
2022-09-14 17:48:33 +02:00
cerr < < " ERROR: The derivatives matrix of the " < < modelClassName ( ) < < " is too large. Please decrease the approximation order. " < < endl ;
2022-01-21 14:31:29 +01:00
exit ( EXIT_FAILURE ) ;
}
2022-10-07 14:37:25 +02:00
// Compute derivatives w.r. to all endogenous, exogenous and exogenous deterministic
2009-04-20 12:48:54 +02:00
set < int > vars ;
2019-12-20 16:59:30 +01:00
for ( auto & it : deriv_id_table )
2009-04-20 12:48:54 +02:00
{
2019-12-16 19:42:59 +01:00
SymbolType type = symbol_table . getType ( it . first . first ) ;
2022-10-07 14:37:25 +02:00
if ( type = = SymbolType : : endogenous | | type = = SymbolType : : exogenous
| | type = = SymbolType : : exogenousDet )
2019-12-16 19:42:59 +01:00
vars . insert ( it . second ) ;
2009-04-20 12:48:54 +02:00
}
2009-04-14 16:39:53 +02:00
// Launch computations
2022-09-14 17:48:33 +02:00
cout < < " Computing " < < modelClassName ( ) < < " derivatives (order " < < derivsOrder < < " ). " < < endl ;
2009-04-20 12:48:54 +02:00
2018-11-22 14:32:40 +01:00
computeDerivatives ( derivsOrder , vars ) ;
2009-04-20 12:48:54 +02:00
2019-12-13 17:15:03 +01:00
if ( derivsOrder > 1 )
2020-01-20 17:22:32 +01:00
for ( const auto & [ indices , d2 ] : derivatives [ 2 ] )
nonzero_hessian_eqs . insert ( indices [ 0 ] ) ;
2019-12-13 17:15:03 +01:00
2016-05-18 12:26:19 +02:00
if ( paramsDerivsOrder > 0 )
2009-04-20 15:58:15 +02:00
{
2022-09-14 17:48:33 +02:00
cout < < " Computing " < < modelClassName ( ) < < " derivatives w.r.t. parameters (order " < < paramsDerivsOrder < < " ). " < < endl ;
2016-05-18 12:26:19 +02:00
computeParamsDerivatives ( paramsDerivsOrder ) ;
2009-04-20 15:58:15 +02:00
}
2022-09-13 15:43:13 +02:00
computeTemporaryTerms ( ! use_dll , no_tmp_terms ) ;
2018-09-21 17:13:19 +02:00
2022-09-13 15:43:13 +02:00
if ( paramsDerivsOrder > 0 & & ! no_tmp_terms )
computeParamsDerivativesTemporaryTerms ( ) ;
2009-08-25 11:43:01 +02:00
2022-11-30 14:43:44 +01:00
if ( ! block & & ( max_endo_lag = = 0 | | max_endo_lead = = 0 ) )
{
time_recursive_block_decomposition = true ;
mfs = 3 ; // FIXME: remove this line when mfs=3 becomes the global default
}
2022-09-28 16:31:51 +02:00
computingPassBlock ( eval_context , no_tmp_terms ) ;
if ( block_decomposed )
computeBlockDynJacobianCols ( ) ;
if ( ! block_decomposed & & block )
2018-09-25 15:56:52 +02:00
{
2022-09-13 15:43:13 +02:00
cerr < < " ERROR: Block decomposition requested but failed. " < < endl ;
exit ( EXIT_FAILURE ) ;
2018-09-25 15:56:52 +02:00
}
2017-03-06 16:34:08 +01:00
}
2015-12-18 15:17:32 +01:00
2017-03-06 16:34:08 +01:00
void
DynamicModel : : computeXrefs ( )
{
2022-06-03 16:24:26 +02:00
for ( int i { 0 } ;
auto & equation : equations )
2017-03-06 16:34:08 +01:00
{
ExprNode : : EquationInfo ei ;
2018-06-04 12:26:16 +02:00
equation - > computeXrefs ( ei ) ;
2017-03-06 16:34:08 +01:00
xrefs [ i + + ] = ei ;
}
2022-06-03 16:24:26 +02:00
for ( int i { 0 } ;
const auto & [ eq , eqinfo ] : xrefs )
2017-03-06 16:34:08 +01:00
{
2022-06-03 16:24:26 +02:00
computeRevXref ( xref_param , eqinfo . param , i ) ;
computeRevXref ( xref_endo , eqinfo . endo , i ) ;
computeRevXref ( xref_exo , eqinfo . exo , i ) ;
computeRevXref ( xref_exo_det , eqinfo . exo_det , i ) ;
i + + ;
2017-03-06 16:34:08 +01:00
}
}
void
2018-06-04 14:17:36 +02:00
DynamicModel : : computeRevXref ( map < pair < int , int > , set < int > > & xrefset , const set < pair < int , int > > & eiref , int eqn )
2017-03-06 16:34:08 +01:00
{
2019-12-20 16:59:30 +01:00
for ( const auto & it : eiref )
2017-03-06 16:34:08 +01:00
{
set < int > eq ;
2022-05-04 16:01:34 +02:00
if ( xrefset . contains ( it ) )
2018-06-04 12:26:16 +02:00
eq = xrefset [ it ] ;
2017-03-06 16:34:08 +01:00
eq . insert ( eqn ) ;
2018-06-04 12:26:16 +02:00
xrefset [ it ] = eq ;
2017-03-06 16:34:08 +01:00
}
}
void
DynamicModel : : writeXrefs ( ostream & output ) const
{
output < < " M_.xref1.param = cell(1, M_.eq_nbr); " < < endl
< < " M_.xref1.endo = cell(1, M_.eq_nbr); " < < endl
< < " M_.xref1.exo = cell(1, M_.eq_nbr); " < < endl
< < " M_.xref1.exo_det = cell(1, M_.eq_nbr); " < < endl ;
2022-06-03 16:24:26 +02:00
for ( int i { 1 } ;
const auto & [ eq , eqinfo ] : xrefs )
2017-03-06 16:34:08 +01:00
{
output < < " M_.xref1.param{ " < < i < < " } = [ " ;
2022-06-03 16:24:26 +02:00
for ( const auto & [ id , lag ] : eqinfo . param )
output < < symbol_table . getTypeSpecificID ( id ) + 1 < < " " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
output < < " M_.xref1.endo{ " < < i < < " } = [ " ;
2022-06-03 16:24:26 +02:00
for ( const auto & [ id , lag ] : eqinfo . endo )
output < < " struct('id', " < < symbol_table . getTypeSpecificID ( id ) + 1 < < " , 'shift', " < < lag < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
output < < " M_.xref1.exo{ " < < i < < " } = [ " ;
2022-06-03 16:24:26 +02:00
for ( const auto & [ id , lag ] : eqinfo . exo )
output < < " struct('id', " < < symbol_table . getTypeSpecificID ( id ) + 1 < < " , 'shift', " < < lag < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
output < < " M_.xref1.exo_det{ " < < i < < " } = [ " ;
2022-06-03 16:24:26 +02:00
for ( const auto & [ id , lag ] : eqinfo . exo_det )
output < < " struct('id', " < < symbol_table . getTypeSpecificID ( id ) + 1 < < " , 'shift', " < < lag < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
2022-06-03 16:24:26 +02:00
i + + ;
2017-03-06 16:34:08 +01:00
}
output < < " M_.xref2.param = cell(1, M_.param_nbr); " < < endl
< < " M_.xref2.endo = cell(1, M_.endo_nbr); " < < endl
< < " M_.xref2.exo = cell(1, M_.exo_nbr); " < < endl
< < " M_.xref2.exo_det = cell(1, M_.exo_det_nbr); " < < endl ;
writeRevXrefs ( output , xref_param , " param " ) ;
writeRevXrefs ( output , xref_endo , " endo " ) ;
writeRevXrefs ( output , xref_exo , " exo " ) ;
writeRevXrefs ( output , xref_exo_det , " exo_det " ) ;
}
void
2018-06-04 14:17:36 +02:00
DynamicModel : : writeRevXrefs ( ostream & output , const map < pair < int , int > , set < int > > & xrefmap , const string & type ) const
2017-03-06 16:34:08 +01:00
{
2022-06-03 16:24:26 +02:00
for ( int last_tsid { - 1 } ;
const auto & [ key , eqs ] : xrefmap )
2017-03-06 16:34:08 +01:00
{
2022-06-03 16:24:26 +02:00
auto & [ id , lag ] = key ;
int tsid = symbol_table . getTypeSpecificID ( id ) + 1 ;
2017-03-06 16:34:08 +01:00
output < < " M_.xref2. " < < type < < " { " < < tsid < < " } = [ " ;
if ( last_tsid = = tsid )
output < < " M_.xref2. " < < type < < " { " < < tsid < < " }; " ;
else
last_tsid = tsid ;
2022-06-03 16:24:26 +02:00
for ( int eq : eqs )
2017-03-06 16:34:08 +01:00
if ( type = = " param " )
2022-06-03 16:24:26 +02:00
output < < eq + 1 < < " " ;
2017-03-06 16:34:08 +01:00
else
2022-06-03 16:24:26 +02:00
output < < " struct('shift', " < < lag < < " , 'eq', " < < eq + 1 < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
}
2009-04-14 16:39:53 +02:00
}
2009-12-16 14:21:31 +01:00
2020-04-24 12:29:02 +02:00
map < tuple < int , int , int > , DynamicModel : : BlockDerivativeType >
DynamicModel : : determineBlockDerivativesType ( int blk )
{
map < tuple < int , int , int > , BlockDerivativeType > derivType ;
int size = blocks [ blk ] . size ;
int nb_recursive = blocks [ blk ] . getRecursiveSize ( ) ;
2022-11-30 14:43:44 +01:00
for ( int lag { time_recursive_block_decomposition ? 0 : - blocks [ blk ] . max_lag } ;
lag < = ( time_recursive_block_decomposition ? 0 : blocks [ blk ] . max_lead ) ;
lag + + )
2020-04-24 12:29:02 +02:00
for ( int eq = 0 ; eq < size ; eq + + )
2020-04-28 18:00:26 +02:00
{
set < pair < int , int > > endos_and_lags ;
int eq_orig = getBlockEquationID ( blk , eq ) ;
equations [ eq_orig ] - > collectEndogenous ( endos_and_lags ) ;
for ( int var = 0 ; var < size ; var + + )
if ( int var_orig = getBlockVariableID ( blk , var ) ;
2022-05-04 16:01:34 +02:00
endos_and_lags . contains ( { var_orig , lag } ) )
2020-04-28 18:00:26 +02:00
{
2020-05-20 11:49:32 +02:00
if ( getBlockEquationType ( blk , eq ) = = EquationType : : evaluateRenormalized
2020-04-28 18:00:26 +02:00
& & eq < nb_recursive )
/* It’ s a normalized recursive equation, we have to recompute
the derivative using the chain rule */
derivType [ { lag , eq , var } ] = BlockDerivativeType : : normalizedChainRule ;
2022-05-04 16:01:34 +02:00
else if ( ! derivType . contains ( { lag , eq , var } ) )
2020-04-28 18:00:26 +02:00
derivType [ { lag , eq , var } ] = BlockDerivativeType : : standard ;
if ( var < nb_recursive )
for ( int feedback_var = nb_recursive ; feedback_var < size ; feedback_var + + )
2022-05-04 16:01:34 +02:00
if ( derivType . contains ( { lag , var , feedback_var } ) )
2020-04-28 18:00:26 +02:00
/* A new derivative needs to be computed using the chain rule
( a feedback variable appears in the recursive equation
defining the current variable ) */
derivType [ { lag , eq , feedback_var } ] = BlockDerivativeType : : chainRule ;
}
}
2020-04-24 12:29:02 +02:00
return derivType ;
2009-12-16 14:21:31 +01:00
}
void
2020-03-19 17:46:10 +01:00
DynamicModel : : computeChainRuleJacobian ( )
2009-12-16 14:21:31 +01:00
{
2022-09-28 16:31:51 +02:00
size_t nb_blocks { blocks . size ( ) } ;
2020-03-19 17:46:10 +01:00
blocks_derivatives . resize ( nb_blocks ) ;
2022-09-28 19:18:15 +02:00
blocks_jacobian_sparse_column_major_order . resize ( nb_blocks ) ;
blocks_jacobian_sparse_colptr . resize ( nb_blocks ) ;
2022-09-28 16:31:51 +02:00
for ( int blk { 0 } ; blk < static_cast < int > ( nb_blocks ) ; blk + + )
2009-12-16 14:21:31 +01:00
{
2020-04-24 12:29:02 +02:00
int nb_recursives = blocks [ blk ] . getRecursiveSize ( ) ;
2022-09-28 19:18:15 +02:00
int mfs_size { blocks [ blk ] . mfs_size } ;
BlockSimulationType simulation_type { blocks [ blk ] . simulation_type } ;
2020-04-24 12:29:02 +02:00
// Create a map from recursive vars to their defining (normalized) equation
2020-10-02 18:31:55 +02:00
map < int , BinaryOpNode * > recursive_vars ;
2020-04-24 12:29:02 +02:00
for ( int i = 0 ; i < nb_recursives ; i + + )
2009-12-16 14:21:31 +01:00
{
2020-04-24 12:29:02 +02:00
int deriv_id = getDerivID ( symbol_table . getID ( SymbolType : : endogenous , getBlockVariableID ( blk , i ) ) , 0 ) ;
2020-05-20 11:49:32 +02:00
if ( getBlockEquationType ( blk , i ) = = EquationType : : evaluateRenormalized )
2020-04-24 12:29:02 +02:00
recursive_vars [ deriv_id ] = getBlockEquationRenormalizedExpr ( blk , i ) ;
2010-07-23 11:20:24 +02:00
else
2020-04-24 12:29:02 +02:00
recursive_vars [ deriv_id ] = getBlockEquationExpr ( blk , i ) ;
2009-12-16 14:21:31 +01:00
}
2020-04-24 12:29:02 +02:00
// Compute the block derivatives
2022-11-08 12:28:48 +01:00
map < pair < expr_t , int > , expr_t > chain_rule_deriv_cache ;
2020-04-24 12:29:02 +02:00
for ( const auto & [ indices , derivType ] : determineBlockDerivativesType ( blk ) )
2009-12-16 14:21:31 +01:00
{
2020-04-24 12:29:02 +02:00
auto [ lag , eq , var ] = indices ;
int eq_orig = getBlockEquationID ( blk , eq ) , var_orig = getBlockVariableID ( blk , var ) ;
int deriv_id = getDerivID ( symbol_table . getID ( SymbolType : : endogenous , var_orig ) , lag ) ;
expr_t d { nullptr } ;
switch ( derivType )
2009-12-16 14:21:31 +01:00
{
2020-04-24 12:29:02 +02:00
case BlockDerivativeType : : standard :
2022-06-13 16:24:33 +02:00
if ( auto it = derivatives [ 1 ] . find ( { eq_orig , deriv_id } ) ;
it ! = derivatives [ 1 ] . end ( ) )
d = it - > second ;
else
d = Zero ;
2020-04-24 12:29:02 +02:00
break ;
case BlockDerivativeType : : chainRule :
2022-11-08 12:28:48 +01:00
d = equations [ eq_orig ] - > getChainRuleDerivative ( deriv_id , recursive_vars , chain_rule_deriv_cache ) ;
2020-04-24 12:29:02 +02:00
break ;
case BlockDerivativeType : : normalizedChainRule :
2022-11-08 12:28:48 +01:00
d = equation_type_and_normalized_equation [ eq_orig ] . second - > getChainRuleDerivative ( deriv_id , recursive_vars , chain_rule_deriv_cache ) ;
2020-04-24 12:29:02 +02:00
break ;
2009-12-16 14:21:31 +01:00
}
2020-04-24 12:29:02 +02:00
2020-05-06 14:21:33 +02:00
if ( d ! = Zero )
blocks_derivatives [ blk ] [ { eq , var , lag } ] = d ;
2009-12-16 14:21:31 +01:00
}
2022-09-28 19:18:15 +02:00
// Compute the sparse representation of the Jacobian
if ( simulation_type ! = BlockSimulationType : : evaluateForward
& & simulation_type ! = BlockSimulationType : : evaluateBackward )
{
const bool one_boundary { simulation_type = = BlockSimulationType : : solveBackwardSimple
| | simulation_type = = BlockSimulationType : : solveForwardSimple
| | simulation_type = = BlockSimulationType : : solveBackwardComplete
| | simulation_type = = BlockSimulationType : : solveForwardComplete } ;
for ( const auto & [ indices , d1 ] : blocks_derivatives [ blk ] )
{
auto & [ eq , var , lag ] { indices } ;
assert ( lag > = - 1 & & lag < = 1 ) ;
if ( eq > = nb_recursives & & var > = nb_recursives
& & ! ( one_boundary & & lag ! = 0 ) )
blocks_jacobian_sparse_column_major_order [ blk ] . emplace ( pair { eq - nb_recursives , var - nb_recursives + static_cast < int > ( ! one_boundary ) * ( lag + 1 ) * mfs_size } , d1 ) ;
}
blocks_jacobian_sparse_colptr [ blk ] = computeCSCColPtr ( blocks_jacobian_sparse_column_major_order [ blk ] , ( one_boundary ? 1 : 3 ) * mfs_size ) ;
}
2009-12-16 14:21:31 +01:00
}
2022-09-28 16:31:51 +02:00
/* Also store information and derivatives w.r.t. other types of variables
( for the stochastic mode ) */
2020-04-30 16:00:16 +02:00
blocks_derivatives_other_endo . resize ( nb_blocks ) ;
blocks_derivatives_exo . resize ( nb_blocks ) ;
blocks_derivatives_exo_det . resize ( nb_blocks ) ;
2020-05-06 14:02:58 +02:00
blocks_other_endo . resize ( nb_blocks ) ;
blocks_exo . resize ( nb_blocks ) ;
blocks_exo_det . resize ( nb_blocks ) ;
2022-09-28 16:31:51 +02:00
for ( auto & [ indices , d1 ] : derivatives [ 1 ] )
{
auto [ eq_orig , deriv_id ] { vectorToTuple < 2 > ( indices ) } ;
int block_eq { eq2block [ eq_orig ] } ;
int eq { getBlockInitialEquationID ( block_eq , eq_orig ) } ;
int var { getTypeSpecificIDByDerivID ( deriv_id ) } ;
int lag { getLagByDerivID ( deriv_id ) } ;
switch ( getTypeByDerivID ( indices [ 1 ] ) )
{
case SymbolType : : endogenous :
if ( block_eq ! = endo2block [ var ] )
{
blocks_derivatives_other_endo [ block_eq ] [ { eq , var , lag } ] = d1 ;
blocks_other_endo [ block_eq ] . insert ( var ) ;
}
break ;
case SymbolType : : exogenous :
blocks_derivatives_exo [ block_eq ] [ { eq , var , lag } ] = d1 ;
blocks_exo [ block_eq ] . insert ( var ) ;
break ;
case SymbolType : : exogenousDet :
blocks_derivatives_exo_det [ block_eq ] [ { eq , var , lag } ] = d1 ;
blocks_exo_det [ block_eq ] . insert ( var ) ;
break ;
default :
break ;
}
}
}
void
DynamicModel : : computeBlockDynJacobianCols ( )
{
size_t nb_blocks { blocks . size ( ) } ;
2020-05-06 14:02:58 +02:00
// Structures used for lexicographic ordering over (lag, var ID)
vector < set < pair < int , int > > > dynamic_endo ( nb_blocks ) , dynamic_other_endo ( nb_blocks ) ,
dynamic_exo ( nb_blocks ) , dynamic_exo_det ( nb_blocks ) ;
2019-12-16 19:42:59 +01:00
for ( auto & [ indices , d1 ] : derivatives [ 1 ] )
2009-12-16 14:21:31 +01:00
{
2022-09-28 16:31:51 +02:00
auto [ eq_orig , deriv_id ] { vectorToTuple < 2 > ( indices ) } ;
int block_eq { eq2block [ eq_orig ] } ;
int var { getTypeSpecificIDByDerivID ( deriv_id ) } ;
int lag { getLagByDerivID ( deriv_id ) } ;
switch ( getTypeByDerivID ( deriv_id ) )
2009-12-16 14:21:31 +01:00
{
2018-07-17 18:34:07 +02:00
case SymbolType : : endogenous :
2020-05-06 14:02:58 +02:00
if ( block_eq = = endo2block [ var ] )
2022-09-28 16:31:51 +02:00
dynamic_endo [ block_eq ] . emplace ( lag , getBlockInitialVariableID ( block_eq , var ) ) ;
2020-05-06 14:02:58 +02:00
else
2022-09-28 16:31:51 +02:00
dynamic_other_endo [ block_eq ] . emplace ( lag , var ) ;
2009-12-16 18:13:23 +01:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenous :
2020-05-06 14:02:58 +02:00
dynamic_exo [ block_eq ] . emplace ( lag , var ) ;
2009-12-16 18:13:23 +01:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenousDet :
2020-05-06 14:02:58 +02:00
dynamic_exo_det [ block_eq ] . emplace ( lag , var ) ;
2009-12-16 18:13:23 +01:00
break ;
default :
break ;
2009-12-16 14:21:31 +01:00
}
}
2020-05-06 14:02:58 +02:00
// Compute Jacobian column indices
blocks_jacob_cols_endo . resize ( nb_blocks ) ;
blocks_jacob_cols_other_endo . resize ( nb_blocks ) ;
blocks_jacob_cols_exo . resize ( nb_blocks ) ;
blocks_jacob_cols_exo_det . resize ( nb_blocks ) ;
2022-09-28 16:31:51 +02:00
for ( size_t blk { 0 } ; blk < nb_blocks ; blk + + )
2020-05-06 14:02:58 +02:00
{
2022-06-03 16:24:26 +02:00
for ( int index { 0 } ;
auto [ lag , var ] : dynamic_endo [ blk ] )
2020-05-06 14:02:58 +02:00
blocks_jacob_cols_endo [ blk ] [ { var , lag } ] = index + + ;
2022-06-03 16:24:26 +02:00
for ( int index { 0 } ;
auto [ lag , var ] : dynamic_other_endo [ blk ] )
2020-05-06 14:02:58 +02:00
blocks_jacob_cols_other_endo [ blk ] [ { var , lag } ] = index + + ;
2022-06-03 16:24:26 +02:00
for ( int index { 0 } ;
auto [ lag , var ] : dynamic_exo [ blk ] )
2020-05-06 14:02:58 +02:00
blocks_jacob_cols_exo [ blk ] [ { var , lag } ] = index + + ;
2022-06-03 16:24:26 +02:00
for ( int index { 0 } ;
auto [ lag , var ] : dynamic_exo_det [ blk ] )
2020-05-06 14:02:58 +02:00
blocks_jacob_cols_exo_det [ blk ] [ { var , lag } ] = index + + ;
}
2009-12-16 14:21:31 +01:00
}
2009-04-14 16:39:53 +02:00
void
2022-05-19 14:15:43 +02:00
DynamicModel : : writeDynamicFile ( const string & basename , bool block , bool use_dll , const string & mexext , const filesystem : : path & matlabroot , const filesystem : : path & dynareroot , bool julia ) const
2009-12-16 18:13:23 +01:00
{
2020-06-23 15:13:04 +02:00
filesystem : : path model_dir { basename } ;
model_dir / = " model " ;
if ( use_dll )
2022-10-05 17:45:18 +02:00
{
create_directories ( model_dir / " src " / " sparse " ) ;
if ( block_decomposed )
create_directories ( model_dir / " src " / " sparse " / " block " ) ;
}
2022-09-20 18:28:30 +02:00
if ( julia )
create_directories ( model_dir / " julia " ) ;
else
2022-10-11 15:59:56 +02:00
{
auto plusfolder { packageDir ( basename ) } ;
/* The following is not a duplicate of the same call from
ModFile : : writeMOutput ( ) , because of planner_objective which needs its
+ objective subdirectory */
create_directories ( plusfolder ) ;
if ( block & & ! use_dll )
create_directories ( plusfolder / " +block " ) ;
2022-09-30 17:26:43 +02:00
auto sparsefolder { plusfolder / " +sparse " } ;
create_directories ( sparsefolder ) ;
if ( ! use_dll )
create_directories ( sparsefolder / " private " ) ;
if ( block_decomposed )
create_directories ( sparsefolder / " +block " ) ;
2022-11-09 14:46:02 +01:00
create_directories ( plusfolder / " +debug " ) ;
2022-10-11 15:59:56 +02:00
}
2023-01-09 13:35:49 +01:00
create_directories ( model_dir / " bytecode " / " block " ) ;
2020-06-23 15:13:04 +02:00
2022-09-20 18:28:30 +02:00
// Legacy representation
2023-01-13 12:05:04 +01:00
if ( use_dll )
writeModelCFile < true > ( basename , mexext , matlabroot , dynareroot ) ;
else if ( ! julia ) // M-files
writeDynamicMFile ( basename ) ;
// The legacy representation is no longer produced for Julia
2023-01-09 13:35:49 +01:00
writeDynamicBytecode ( basename ) ;
if ( block_decomposed )
writeDynamicBlockBytecode ( basename ) ;
2020-06-23 15:13:04 +02:00
2022-09-20 18:28:30 +02:00
// Sparse representation
2022-09-30 17:26:43 +02:00
if ( use_dll )
2022-10-05 17:45:18 +02:00
writeSparseModelCFiles < true > ( basename , mexext , matlabroot , dynareroot ) ;
2022-09-30 17:26:43 +02:00
else if ( julia )
2022-09-20 18:28:30 +02:00
writeSparseModelJuliaFiles < true > ( basename ) ;
2022-09-30 17:26:43 +02:00
else // MATLAB/Octave
writeSparseModelMFiles < true > ( basename ) ;
2022-09-20 18:28:30 +02:00
2019-10-17 15:03:26 +02:00
writeSetAuxiliaryVariables ( basename , julia ) ;
2022-11-09 14:46:02 +01:00
// Support for model debugging
if ( ! julia )
writeDebugModelMFiles < true > ( basename ) ;
2018-03-02 17:50:35 +01:00
}
void
2019-12-16 19:42:59 +01:00
DynamicModel : : writeSetAuxiliaryVariables ( const string & basename , bool julia ) const
2018-03-02 17:50:35 +01:00
{
ostringstream output_func_body ;
2022-04-01 17:34:18 +02:00
writeAuxVarRecursiveDefinitions ( output_func_body , julia ? ExprNodeOutputType : : juliaTimeDataFrame
: ExprNodeOutputType : : matlabDseries ) ;
2018-03-02 17:50:35 +01:00
if ( output_func_body . str ( ) . empty ( ) )
return ;
2021-08-18 16:52:35 +02:00
string func_name = julia ? " dynamic_set_auxiliary_series! " : " dynamic_set_auxiliary_series " ;
2018-03-02 17:50:35 +01:00
string comment = julia ? " # " : " % " ;
2021-04-23 17:30:38 +02:00
stringstream output ;
2021-04-23 17:55:28 +02:00
output < < " function " ;
if ( ! julia )
output < < " ds = " ;
output < < func_name + " (ds, params) " < < endl
2018-03-02 17:50:35 +01:00
< < comment < < endl
2022-09-14 17:48:33 +02:00
< < comment < < " Status : Computes Auxiliary variables of the " < < modelClassName ( ) < < " and returns a dseries " < < endl
2018-03-02 17:50:35 +01:00
< < comment < < endl
< < comment < < " Warning : this file is generated automatically by Dynare " < < endl
2022-07-12 14:31:30 +02:00
< < comment < < " from model file (.mod) " < < endl < < endl ;
2021-04-23 17:55:28 +02:00
if ( julia )
2022-07-12 14:31:30 +02:00
output < < " @inbounds begin " < < endl ;
output < < output_func_body . str ( )
< < " end " < < endl ;
if ( julia )
2022-10-26 21:19:03 +02:00
output < < " end " < < endl ;
2018-03-02 18:39:16 +01:00
2022-10-11 15:59:56 +02:00
if ( julia )
2022-11-02 15:47:15 +01:00
writeToFileIfModified ( output , filesystem : : path { basename } / " model " / " julia " / " DynamicSetAuxiliarySeries.jl " ) ;
2022-10-11 15:59:56 +02:00
else
{
/* Calling writeToFileIfModified() is useless here since we write inside
a subdirectory deleted at each preprocessor run . */
filesystem : : path filename { packageDir ( basename ) / ( func_name + " .m " ) } ;
ofstream output_file { filename , ios : : out | ios : : binary } ;
if ( ! output_file . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output_file < < output . str ( ) ;
output_file . close ( ) ;
}
2018-03-02 17:50:35 +01:00
}
void
DynamicModel : : writeAuxVarRecursiveDefinitions ( ostream & output , ExprNodeOutputType output_type ) const
{
deriv_node_temp_terms_t tef_terms ;
2019-12-16 19:42:59 +01:00
for ( auto aux_eq : aux_equations )
2020-07-08 18:46:09 +02:00
if ( aux_eq - > containsExternalFunction ( ) )
aux_eq - > writeExternalFunctionOutput ( output , output_type , { } , { } , tef_terms ) ;
2019-12-16 19:42:59 +01:00
for ( auto aux_eq : aux_equations )
{
2020-07-08 18:46:09 +02:00
aux_eq - > writeOutput ( output , output_type , { } , { } , tef_terms ) ;
2018-03-02 17:50:35 +01:00
output < < " ; " < < endl ;
}
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
2020-01-06 18:26:35 +01:00
void
DynamicModel : : clearEquations ( )
{
equations . clear ( ) ;
equations_lineno . clear ( ) ;
equation_tags . clear ( ) ;
}
2011-03-21 18:40:57 +01:00
void
DynamicModel : : replaceMyEquations ( DynamicModel & dynamic_model ) const
{
2020-01-06 18:26:35 +01:00
dynamic_model . clearEquations ( ) ;
2014-01-27 16:41:43 +01:00
for ( size_t i = 0 ; i < equations . size ( ) ; i + + )
2020-01-06 18:26:35 +01:00
dynamic_model . addEquation ( equations [ i ] - > clone ( dynamic_model ) , equations_lineno [ i ] ) ;
dynamic_model . equation_tags = equation_tags ;
2011-03-21 18:40:57 +01:00
}
void
2018-12-20 17:04:28 +01:00
DynamicModel : : computeRamseyPolicyFOCs ( const StaticModel & static_model )
2011-03-21 18:40:57 +01:00
{
// Add aux LM to constraints in equations
2011-05-25 06:43:59 +02:00
// equation[i]->lhs = rhs becomes equation[i]->MULT_(i+1)*(lhs-rhs) = 0
2011-03-21 18:40:57 +01:00
int i ;
2019-04-23 11:07:32 +02:00
for ( i = 0 ; i < static_cast < int > ( equations . size ( ) ) ; i + + )
2011-03-21 18:40:57 +01:00
{
2019-12-16 19:42:59 +01:00
auto substeq = dynamic_cast < BinaryOpNode * > ( equations [ i ] - > addMultipliersToConstraints ( i ) ) ;
assert ( substeq ) ;
2011-03-21 18:40:57 +01:00
equations [ i ] = substeq ;
}
2018-12-20 17:04:28 +01:00
cout < < " Ramsey Problem: added " < < i < < " Multipliers. " < < endl ;
2011-03-21 18:40:57 +01:00
2020-01-06 18:26:35 +01:00
// Add Planner Objective to equations so that it appears in Lagrangian
2011-03-21 18:40:57 +01:00
assert ( static_model . equations . size ( ) = = 1 ) ;
2022-05-05 18:39:27 +02:00
addEquation ( static_model . equations [ 0 ] - > clone ( * this ) , nullopt ) ;
2011-03-21 18:40:57 +01:00
// Get max endo lead and max endo lag
2018-06-04 14:17:36 +02:00
set < pair < int , int > > dynvars ;
2011-03-21 18:40:57 +01:00
int max_eq_lead = 0 ;
int max_eq_lag = 0 ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-07-17 18:34:07 +02:00
equation - > collectDynamicVariables ( SymbolType : : endogenous , dynvars ) ;
2011-03-21 18:40:57 +01:00
2020-01-06 18:26:35 +01:00
for ( const auto & [ symb_id , lag ] : dynvars )
2011-03-21 18:40:57 +01:00
{
2022-06-02 10:50:21 +02:00
max_eq_lead = max ( lag , max_eq_lead ) ;
max_eq_lag = max ( - lag , max_eq_lag ) ;
2011-03-21 18:40:57 +01:00
}
2011-03-29 18:18:32 +02:00
// Get Discount Factor
2011-05-24 15:34:03 +02:00
assert ( symbol_table . exists ( " optimal_policy_discount_factor " ) ) ;
int symb_id = symbol_table . getID ( " optimal_policy_discount_factor " ) ;
2018-07-17 18:34:07 +02:00
assert ( symbol_table . getType ( symb_id ) = = SymbolType : : parameter ) ;
2011-03-29 18:18:32 +02:00
expr_t discount_factor_node = AddVariable ( symb_id , 0 ) ;
2011-03-21 18:40:57 +01:00
// Create (modified) Lagrangian (so that we can take the derivative once at time t)
expr_t lagrangian = Zero ;
2019-04-23 11:07:32 +02:00
for ( i = 0 ; i < static_cast < int > ( equations . size ( ) ) ; i + + )
2011-03-21 18:40:57 +01:00
for ( int lag = - max_eq_lag ; lag < = max_eq_lead ; lag + + )
{
2018-06-04 12:52:14 +02:00
expr_t dfpower = nullptr ;
2019-12-16 19:42:59 +01:00
stringstream lagstream ;
2011-03-21 18:40:57 +01:00
lagstream < < abs ( lag ) ;
if ( lag < 0 )
dfpower = AddNonNegativeConstant ( lagstream . str ( ) ) ;
else if ( lag = = 0 )
dfpower = Zero ;
else
dfpower = AddMinus ( Zero , AddNonNegativeConstant ( lagstream . str ( ) ) ) ;
lagrangian = AddPlus ( AddTimes ( AddPower ( discount_factor_node , dfpower ) ,
equations [ i ] - > getNonZeroPartofEquation ( ) - > decreaseLeadsLags ( lag ) ) , lagrangian ) ;
}
2020-01-06 18:26:35 +01:00
// Save line numbers and tags, see below
auto old_equations_lineno = equations_lineno ;
auto old_equation_tags = equation_tags ;
// Prepare derivation of the Lagrangian
clearEquations ( ) ;
2022-05-05 18:39:27 +02:00
addEquation ( AddEqual ( lagrangian , Zero ) , nullopt ) ;
2011-03-21 18:40:57 +01:00
computeDerivIDs ( ) ;
2020-01-06 18:26:35 +01:00
/* Compute Lagrangian derivatives.
Also restore line numbers and tags for FOCs w . r . t . a Lagrange multiplier
( i . e . a FOC identical to an equation of the original model ) */
2011-03-21 18:40:57 +01:00
vector < expr_t > neweqs ;
2022-05-05 18:39:27 +02:00
vector < optional < int > > neweqs_lineno ;
2020-02-20 15:29:10 +01:00
map < int , map < string , string > > neweqs_tags ;
2020-01-06 18:26:35 +01:00
for ( auto & [ symb_id_and_lag , deriv_id ] : deriv_id_table )
{
auto & [ symb_id , lag ] = symb_id_and_lag ;
if ( symbol_table . getType ( symb_id ) = = SymbolType : : endogenous & & lag = = 0 )
{
neweqs . push_back ( AddEqual ( equations [ 0 ] - > getNonZeroPartofEquation ( ) - > getDerivative ( deriv_id ) , Zero ) ) ;
2022-05-16 15:23:35 +02:00
if ( optional < int > i = symbol_table . getEquationNumberForMultiplier ( symb_id ) ;
i )
2020-01-06 18:26:35 +01:00
{
// This is a derivative w.r.t. a Lagrange multiplier
2022-05-16 15:23:35 +02:00
neweqs_lineno . push_back ( old_equations_lineno [ * i ] ) ;
2022-06-02 10:50:21 +02:00
neweqs_tags [ neweqs . size ( ) - 1 ] = old_equation_tags . getTagsByEqn ( * i ) ;
2020-01-06 18:26:35 +01:00
}
else
2022-05-05 18:39:27 +02:00
neweqs_lineno . push_back ( nullopt ) ;
2020-01-06 18:26:35 +01:00
}
}
2011-03-21 18:40:57 +01:00
2020-01-06 18:26:35 +01:00
// Overwrite equations with the Lagrangian derivatives
clearEquations ( ) ;
for ( size_t i = 0 ; i < neweqs . size ( ) ; i + + )
addEquation ( neweqs [ i ] , neweqs_lineno [ i ] , neweqs_tags [ i ] ) ;
2011-03-21 18:40:57 +01:00
}
2015-07-30 14:40:03 +02:00
bool
DynamicModel : : ParamUsedWithLeadLag ( ) const
{
return ParamUsedWithLeadLagInternal ( ) ;
}
2019-10-16 17:34:27 +02:00
void
2021-11-23 12:35:43 +01:00
DynamicModel : : createVariableMapping ( )
2019-10-16 17:34:27 +02:00
{
2021-11-23 12:35:43 +01:00
for ( size_t ii = 0 ; ii < equations . size ( ) ; ii + + )
2019-10-16 17:34:27 +02:00
{
set < int > eqvars ;
equations [ ii ] - > collectVariables ( SymbolType : : endogenous , eqvars ) ;
equations [ ii ] - > collectVariables ( SymbolType : : exogenous , eqvars ) ;
for ( auto eqvar : eqvars )
2022-01-27 15:52:59 +01:00
variableMapping [ symbol_table . getUltimateOrigSymbID ( eqvar ) ] . emplace ( ii ) ;
2019-10-16 17:34:27 +02:00
}
}
void
DynamicModel : : expandEqTags ( )
{
2020-02-20 15:29:10 +01:00
set < int > existing_tags = equation_tags . getEqnsByKey ( " name " ) ;
2019-10-16 17:34:27 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2022-05-04 16:01:34 +02:00
if ( ! existing_tags . contains ( eq ) )
2020-02-20 15:29:10 +01:00
if ( auto lhs_expr = dynamic_cast < VariableNode * > ( equations [ eq ] - > arg1 ) ;
lhs_expr
& & ! equation_tags . exists ( " name " , symbol_table . getName ( lhs_expr - > symb_id ) ) )
equation_tags . add ( eq , " name " , symbol_table . getName ( lhs_expr - > symb_id ) ) ;
else if ( ! equation_tags . exists ( " name " , to_string ( eq + 1 ) ) )
equation_tags . add ( eq , " name " , to_string ( eq + 1 ) ) ;
2019-10-16 17:34:27 +02:00
else
{
cerr < < " Error creating default equation tag: cannot assign default tag to equation number " < < eq + 1 < < " because it is already in use " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2013-11-29 15:32:49 +01:00
set < int >
DynamicModel : : findUnusedEndogenous ( )
2013-09-13 20:37:31 +02:00
{
2013-11-29 15:32:49 +01:00
set < int > usedEndo , unusedEndo ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-07-17 18:34:07 +02:00
equation - > collectVariables ( SymbolType : : endogenous , usedEndo ) ;
2021-12-06 16:30:38 +01:00
for ( auto & equation : static_only_equations )
equation - > collectVariables ( SymbolType : : endogenous , usedEndo ) ;
2013-11-29 15:32:49 +01:00
set < int > allEndo = symbol_table . getEndogenous ( ) ;
set_difference ( allEndo . begin ( ) , allEndo . end ( ) ,
usedEndo . begin ( ) , usedEndo . end ( ) ,
inserter ( unusedEndo , unusedEndo . begin ( ) ) ) ;
return unusedEndo ;
2013-09-13 20:37:31 +02:00
}
2013-11-29 16:03:15 +01:00
set < int >
DynamicModel : : findUnusedExogenous ( )
{
2016-10-14 16:35:15 +02:00
set < int > usedExo , unusedExo , unobservedExo ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-07-17 18:34:07 +02:00
equation - > collectVariables ( SymbolType : : exogenous , usedExo ) ;
2021-12-06 16:30:38 +01:00
for ( auto & equation : static_only_equations )
equation - > collectVariables ( SymbolType : : exogenous , usedExo ) ;
2018-03-13 09:20:14 +01:00
set < int > observedExo = symbol_table . getObservedExogenous ( ) ;
2013-11-29 16:03:15 +01:00
set < int > allExo = symbol_table . getExogenous ( ) ;
set_difference ( allExo . begin ( ) , allExo . end ( ) ,
2016-10-14 16:35:15 +02:00
observedExo . begin ( ) , observedExo . end ( ) ,
inserter ( unobservedExo , unobservedExo . begin ( ) ) ) ;
set_difference ( unobservedExo . begin ( ) , unobservedExo . end ( ) ,
2013-11-29 16:03:15 +01:00
usedExo . begin ( ) , usedExo . end ( ) ,
inserter ( unusedExo , unusedExo . begin ( ) ) ) ;
return unusedExo ;
}
2017-07-27 18:33:19 +02:00
void
DynamicModel : : setLeadsLagsOrig ( )
{
2018-06-04 14:17:36 +02:00
set < pair < int , int > > dynvars ;
2017-07-27 18:33:19 +02:00
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2017-07-27 18:33:19 +02:00
{
2018-07-17 18:34:07 +02:00
equation - > collectDynamicVariables ( SymbolType : : endogenous , dynvars ) ;
equation - > collectDynamicVariables ( SymbolType : : exogenous , dynvars ) ;
equation - > collectDynamicVariables ( SymbolType : : exogenousDet , dynvars ) ;
2018-12-11 17:26:50 +01:00
max_lag_with_diffs_expanded_orig = max ( equation - > maxLagWithDiffsExpanded ( ) ,
max_lag_with_diffs_expanded_orig ) ;
2017-07-27 18:33:19 +02:00
}
2022-06-02 10:50:21 +02:00
for ( const auto & [ symb_id , lag ] : dynvars )
2017-07-27 18:33:19 +02:00
{
2022-06-02 10:50:21 +02:00
SymbolType type = symbol_table . getType ( symb_id ) ;
2017-07-27 18:33:19 +02:00
2019-03-21 17:21:06 +01:00
max_lead_orig = max ( lag , max_lead_orig ) ;
max_lag_orig = max ( - lag , max_lag_orig ) ;
2017-07-27 18:33:19 +02:00
2019-09-24 14:03:38 +02:00
switch ( type )
2017-07-27 18:33:19 +02:00
{
2018-07-17 18:34:07 +02:00
case SymbolType : : endogenous :
2019-09-24 14:03:38 +02:00
max_endo_lead_orig = max ( lag , max_endo_lead_orig ) ;
max_endo_lag_orig = max ( - lag , max_endo_lag_orig ) ;
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenous :
2019-09-24 14:03:38 +02:00
max_exo_lead_orig = max ( lag , max_exo_lead_orig ) ;
max_exo_lag_orig = max ( - lag , max_exo_lag_orig ) ;
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenousDet :
2019-03-21 17:21:06 +01:00
max_exo_det_lead_orig = max ( lag , max_exo_det_lead_orig ) ;
max_exo_det_lag_orig = max ( - lag , max_exo_det_lag_orig ) ;
2017-07-27 18:33:19 +02:00
break ;
default :
break ;
}
}
}
2009-09-30 17:10:31 +02:00
void
DynamicModel : : computeDerivIDs ( )
2009-04-17 18:26:23 +02:00
{
2018-06-04 14:17:36 +02:00
set < pair < int , int > > dynvars ;
2009-04-17 18:26:23 +02:00
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2009-04-17 18:26:23 +02:00
{
2022-07-11 17:33:09 +02:00
equation - > collectDynamicVariables ( SymbolType : : endogenous , dynvars ) ;
2018-07-17 18:34:07 +02:00
equation - > collectDynamicVariables ( SymbolType : : exogenous , dynvars ) ;
equation - > collectDynamicVariables ( SymbolType : : exogenousDet , dynvars ) ;
equation - > collectDynamicVariables ( SymbolType : : parameter , dynvars ) ;
equation - > collectDynamicVariables ( SymbolType : : trend , dynvars ) ;
equation - > collectDynamicVariables ( SymbolType : : logTrend , dynvars ) ;
2009-04-17 18:26:23 +02:00
}
2022-06-02 10:50:21 +02:00
for ( const auto & [ symb_id , lag ] : dynvars )
2009-09-30 17:10:31 +02:00
{
2022-06-02 10:50:21 +02:00
SymbolType type = symbol_table . getType ( symb_id ) ;
2009-04-17 18:26:23 +02:00
2010-11-18 11:21:20 +01:00
/* Setting maximum and minimum lags.
We don ' t want these to be affected by lead / lags on parameters : they
are accepted for facilitating variable flipping , but are simply
ignored . */
2019-03-21 17:21:06 +01:00
if ( type ! = SymbolType : : parameter )
{
max_lead = max ( lag , max_lead ) ;
max_lag = max ( - lag , max_lag ) ;
}
2009-04-17 18:26:23 +02:00
2009-09-30 17:10:31 +02:00
switch ( type )
{
2018-07-17 18:34:07 +02:00
case SymbolType : : endogenous :
2019-03-21 17:21:06 +01:00
max_endo_lead = max ( lag , max_endo_lead ) ;
max_endo_lag = max ( - lag , max_endo_lag ) ;
2009-09-30 17:10:31 +02:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenous :
2019-03-21 17:21:06 +01:00
max_exo_lead = max ( lag , max_exo_lead ) ;
max_exo_lag = max ( - lag , max_exo_lag ) ;
2009-09-30 17:10:31 +02:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenousDet :
2019-03-21 17:21:06 +01:00
max_exo_det_lead = max ( lag , max_exo_det_lead ) ;
max_exo_det_lag = max ( - lag , max_exo_det_lag ) ;
2009-09-30 17:10:31 +02:00
break ;
default :
break ;
}
2009-04-17 18:26:23 +02:00
2009-09-30 17:10:31 +02:00
// Create a new deriv_id
int deriv_id = deriv_id_table . size ( ) ;
2009-04-17 18:26:23 +02:00
2022-06-02 10:50:21 +02:00
deriv_id_table [ { symb_id , lag } ] = deriv_id ;
inv_deriv_id_table . emplace_back ( symb_id , lag ) ;
2009-09-30 17:10:31 +02:00
}
2009-04-17 18:26:23 +02:00
}
2009-04-20 12:48:54 +02:00
SymbolType
2018-06-04 12:50:53 +02:00
DynamicModel : : getTypeByDerivID ( int deriv_id ) const noexcept ( false )
2009-04-17 18:26:23 +02:00
{
return symbol_table . getType ( getSymbIDByDerivID ( deriv_id ) ) ;
}
int
2018-06-04 12:50:53 +02:00
DynamicModel : : getLagByDerivID ( int deriv_id ) const noexcept ( false )
2009-04-17 18:26:23 +02:00
{
2019-04-23 11:07:32 +02:00
if ( deriv_id < 0 | | deriv_id > = static_cast < int > ( inv_deriv_id_table . size ( ) ) )
2009-04-17 18:26:23 +02:00
throw UnknownDerivIDException ( ) ;
return inv_deriv_id_table [ deriv_id ] . second ;
}
int
2018-06-04 12:50:53 +02:00
DynamicModel : : getSymbIDByDerivID ( int deriv_id ) const noexcept ( false )
2009-04-17 18:26:23 +02:00
{
2019-04-23 11:07:32 +02:00
if ( deriv_id < 0 | | deriv_id > = static_cast < int > ( inv_deriv_id_table . size ( ) ) )
2009-04-17 18:26:23 +02:00
throw UnknownDerivIDException ( ) ;
return inv_deriv_id_table [ deriv_id ] . first ;
}
2022-07-12 15:28:52 +02:00
int
DynamicModel : : getTypeSpecificIDByDerivID ( int deriv_id ) const
{
return symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( deriv_id ) ) ;
}
2009-04-17 18:26:23 +02:00
int
2018-06-04 12:50:53 +02:00
DynamicModel : : getDerivID ( int symb_id , int lag ) const noexcept ( false )
2009-04-17 18:26:23 +02:00
{
2022-06-02 10:50:21 +02:00
if ( auto it = deriv_id_table . find ( { symb_id , lag } ) ;
it = = deriv_id_table . end ( ) )
2009-04-17 18:26:23 +02:00
throw UnknownDerivIDException ( ) ;
else
return it - > second ;
}
2011-01-13 18:08:26 +01:00
void
DynamicModel : : addAllParamDerivId ( set < int > & deriv_id_set )
{
for ( size_t i = 0 ; i < inv_deriv_id_table . size ( ) ; i + + )
2018-07-17 18:34:07 +02:00
if ( symbol_table . getType ( inv_deriv_id_table [ i ] . first ) = = SymbolType : : parameter )
2011-01-13 18:08:26 +01:00
deriv_id_set . insert ( i ) ;
}
2009-04-17 18:26:23 +02:00
void
2022-10-07 14:37:25 +02:00
DynamicModel : : computeDynJacobianCols ( )
2009-04-17 18:26:23 +02:00
{
2022-07-11 17:33:09 +02:00
// Sort the dynamic endogenous variables by lexicographic order over (lag, type_specific_symbol_id)
2009-04-17 18:26:23 +02:00
map < pair < int , int > , int > ordered_dyn_endo ;
2022-07-11 17:33:09 +02:00
for ( const auto & [ symb_lag , deriv_id ] : deriv_id_table )
if ( const auto & [ symb_id , lag ] = symb_lag ;
symbol_table . getType ( symb_id ) = = SymbolType : : endogenous )
ordered_dyn_endo [ { lag , symbol_table . getTypeSpecificID ( symb_id ) } ] = deriv_id ;
2009-04-17 18:26:23 +02:00
2022-09-14 17:07:08 +02:00
// Fill the dynamic jacobian columns for endogenous (legacy representation)
2022-06-03 16:24:26 +02:00
for ( int sorted_id { 0 } ;
2022-07-11 17:33:09 +02:00
const auto & [ ignore , deriv_id ] : ordered_dyn_endo )
dyn_jacobian_cols_table [ deriv_id ] = sorted_id + + ;
2009-04-20 12:48:54 +02:00
2022-09-14 17:07:08 +02:00
/* Fill the dynamic columns for exogenous and exogenous deterministic (legacy
representation ) */
2022-10-07 14:37:25 +02:00
for ( const auto & [ symb_lag , deriv_id ] : deriv_id_table )
{
int symb_id { symb_lag . first } ;
int tsid { symbol_table . getTypeSpecificID ( symb_id ) } ;
if ( SymbolType type { symbol_table . getType ( symb_id ) } ;
type = = SymbolType : : exogenous )
dyn_jacobian_cols_table [ deriv_id ] = ordered_dyn_endo . size ( ) + tsid ;
else if ( type = = SymbolType : : exogenousDet )
dyn_jacobian_cols_table [ deriv_id ] = ordered_dyn_endo . size ( ) + symbol_table . exo_nbr ( ) + tsid ;
}
2009-04-17 18:26:23 +02:00
}
2010-10-15 19:05:16 +02:00
void
DynamicModel : : testTrendDerivativesEqualToZero ( const eval_context_t & eval_context )
{
2022-06-02 10:50:21 +02:00
for ( auto & [ symb_lag1 , deriv_id1 ] : deriv_id_table )
if ( auto & [ symb_id1 , lag1 ] = symb_lag1 ;
symbol_table . getType ( symb_id1 ) = = SymbolType : : trend
| | symbol_table . getType ( symb_id1 ) = = SymbolType : : logTrend )
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2010-10-15 19:05:16 +02:00
{
2018-11-28 14:32:26 +01:00
expr_t homogeneq = AddMinus ( equations [ eq ] - > arg1 ,
equations [ eq ] - > arg2 ) ;
2013-10-29 11:46:54 +01:00
// Do not run the test if the term inside the log is zero
2018-07-17 16:32:00 +02:00
if ( fabs ( homogeneq - > eval ( eval_context ) ) > zero_band )
2013-10-29 11:46:54 +01:00
{
expr_t testeq = AddLog ( homogeneq ) ; // F = log(lhs-rhs)
2022-06-02 10:50:21 +02:00
testeq = testeq - > getDerivative ( deriv_id1 ) ; // d F / d Trend
for ( auto & [ symb_lag2 , deriv_id2 ] : deriv_id_table )
if ( auto & [ symb_id2 , lag2 ] = symb_lag2 ;
symbol_table . getType ( symb_id2 ) = = SymbolType : : endogenous )
2010-10-15 19:05:16 +02:00
{
2022-06-02 10:50:21 +02:00
double nearZero = testeq - > getDerivative ( deriv_id2 ) - > eval ( eval_context ) ; // eval d F / d Trend d Endog
2019-11-14 17:51:16 +01:00
if ( fabs ( nearZero ) > balanced_growth_test_tol )
2013-10-29 11:46:54 +01:00
{
2022-05-05 18:39:27 +02:00
cerr < < " ERROR: trends not compatible with balanced growth path; the second-order cross partial of equation " < < eq + 1 ;
if ( equations_lineno [ eq ] )
2022-08-03 10:52:08 +02:00
cerr < < " (line " < < * equations_lineno [ eq ] < < " ) " ;
2022-05-05 18:39:27 +02:00
cerr < < " w.r.t. trend variable "
2022-06-02 10:50:21 +02:00
< < symbol_table . getName ( symb_id1 ) < < " and endogenous variable "
< < symbol_table . getName ( symb_id2 ) < < " is not null (abs. value = "
2019-11-14 17:51:16 +01:00
< < fabs ( nearZero ) < < " ). If you are confident that your trends are correctly specified, you can raise the value of option 'balanced_growth_test_tol' in the 'model' block. " < < endl ;
exit ( EXIT_FAILURE ) ;
2013-10-29 11:46:54 +01:00
}
2010-10-15 19:05:16 +02:00
}
2013-10-29 11:46:54 +01:00
}
2010-10-15 19:05:16 +02:00
}
}
2009-04-30 15:14:33 +02:00
void
2019-12-16 19:42:59 +01:00
DynamicModel : : writeLatexFile ( const string & basename , bool write_equation_tags ) const
2009-12-16 18:13:23 +01:00
{
2019-07-11 17:33:53 +02:00
writeLatexModelFile ( basename , " dynamic " , ExprNodeOutputType : : latexDynamicModel , write_equation_tags ) ;
2009-12-16 18:13:23 +01:00
}
2009-07-07 16:20:48 +02:00
2015-02-16 08:31:30 +01:00
void
2019-12-16 19:42:59 +01:00
DynamicModel : : writeLatexOriginalFile ( const string & basename , bool write_equation_tags ) const
2015-02-16 08:31:30 +01:00
{
2019-07-11 17:33:53 +02:00
writeLatexModelFile ( basename , " original " , ExprNodeOutputType : : latexDynamicModel , write_equation_tags ) ;
2015-02-16 08:31:30 +01:00
}
2009-09-30 17:10:31 +02:00
void
2018-12-20 17:04:28 +01:00
DynamicModel : : substituteEndoLeadGreaterThanTwo ( bool deterministic_model )
2009-09-30 17:10:31 +02:00
{
2018-12-20 17:04:28 +01:00
substituteLeadLagInternal ( AuxVarType : : endoLead , deterministic_model , { } ) ;
2009-10-07 16:07:13 +02:00
}
2009-09-30 17:10:31 +02:00
2009-10-07 16:07:13 +02:00
void
2018-12-20 17:04:28 +01:00
DynamicModel : : substituteEndoLagGreaterThanTwo ( bool deterministic_model )
2009-10-07 16:07:13 +02:00
{
2018-12-20 17:04:28 +01:00
substituteLeadLagInternal ( AuxVarType : : endoLag , deterministic_model , { } ) ;
2009-10-07 16:07:13 +02:00
}
2009-09-30 17:10:31 +02:00
2009-10-07 16:07:13 +02:00
void
2018-12-20 17:04:28 +01:00
DynamicModel : : substituteExoLead ( bool deterministic_model )
2009-10-07 16:07:13 +02:00
{
2018-12-20 17:04:28 +01:00
substituteLeadLagInternal ( AuxVarType : : exoLead , deterministic_model , { } ) ;
2009-09-30 17:10:31 +02:00
}
void
2018-12-20 17:04:28 +01:00
DynamicModel : : substituteExoLag ( bool deterministic_model )
2009-10-07 18:34:42 +02:00
{
2018-12-20 17:04:28 +01:00
substituteLeadLagInternal ( AuxVarType : : exoLag , deterministic_model , { } ) ;
2009-10-07 18:34:42 +02:00
}
void
2018-12-20 17:04:28 +01:00
DynamicModel : : substituteLeadLagInternal ( AuxVarType type , bool deterministic_model , const vector < string > & subset )
2009-09-30 17:10:31 +02:00
{
ExprNode : : subst_table_t subst_table ;
vector < BinaryOpNode * > neweqs ;
2010-10-11 12:52:27 +02:00
// Substitute in used model local variables
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 ) ;
2010-10-11 12:52:27 +02:00
2018-06-04 12:26:16 +02:00
for ( int used_local_var : used_local_vars )
2009-10-07 16:07:13 +02:00
{
2022-09-27 12:51:22 +02:00
const expr_t value = local_variables_table . at ( used_local_var ) ;
2010-09-16 19:18:45 +02:00
expr_t subst ;
2009-12-16 18:13:23 +01:00
switch ( type )
2009-10-07 16:07:13 +02:00
{
2018-07-17 17:38:26 +02:00
case AuxVarType : : endoLead :
2010-10-11 12:52:27 +02:00
subst = value - > substituteEndoLeadGreaterThanTwo ( subst_table , neweqs , deterministic_model ) ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : endoLag :
2010-10-11 12:52:27 +02:00
subst = value - > substituteEndoLagGreaterThanTwo ( subst_table , neweqs ) ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : exoLead :
2010-10-11 12:52:27 +02:00
subst = value - > substituteExoLead ( subst_table , neweqs , deterministic_model ) ;
2009-10-07 18:34:42 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : exoLag :
2010-10-11 12:52:27 +02:00
subst = value - > substituteExoLag ( subst_table , neweqs ) ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : diffForward :
2013-05-17 16:51:34 +02:00
subst = value - > differentiateForwardVars ( subset , subst_table , neweqs ) ;
2013-04-25 18:09:31 +02:00
break ;
2009-11-02 19:31:50 +01:00
default :
cerr < < " DynamicModel::substituteLeadLagInternal: impossible case " < < endl ;
exit ( EXIT_FAILURE ) ;
2009-10-07 16:07:13 +02:00
}
2018-06-04 12:26:16 +02:00
local_variables_table [ used_local_var ] = subst ;
2009-10-07 16:07:13 +02:00
}
2009-09-30 17:10:31 +02:00
// Substitute in equations
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2009-09-30 17:10:31 +02:00
{
2010-09-16 19:18:45 +02:00
expr_t subst ;
2009-12-16 18:13:23 +01:00
switch ( type )
2009-10-07 16:07:13 +02:00
{
2018-07-17 17:38:26 +02:00
case AuxVarType : : endoLead :
2018-06-04 12:26:16 +02:00
subst = equation - > substituteEndoLeadGreaterThanTwo ( subst_table , neweqs , deterministic_model ) ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : endoLag :
2018-06-04 12:26:16 +02:00
subst = equation - > substituteEndoLagGreaterThanTwo ( subst_table , neweqs ) ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : exoLead :
2018-06-04 12:26:16 +02:00
subst = equation - > substituteExoLead ( subst_table , neweqs , deterministic_model ) ;
2009-10-07 18:34:42 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : exoLag :
2018-06-04 12:26:16 +02:00
subst = equation - > substituteExoLag ( subst_table , neweqs ) ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : diffForward :
2018-06-04 12:26:16 +02:00
subst = equation - > differentiateForwardVars ( subset , subst_table , neweqs ) ;
2013-04-25 18:09:31 +02:00
break ;
2009-11-02 19:31:50 +01:00
default :
cerr < < " DynamicModel::substituteLeadLagInternal: impossible case " < < endl ;
exit ( EXIT_FAILURE ) ;
2009-10-07 16:07:13 +02:00
}
2019-12-16 19:42:59 +01:00
auto substeq = dynamic_cast < BinaryOpNode * > ( subst ) ;
assert ( substeq ) ;
2018-06-04 12:26:16 +02:00
equation = substeq ;
2009-09-30 17:10:31 +02:00
}
// Add new equations
2019-12-20 16:59:30 +01:00
for ( auto & neweq : neweqs )
2019-12-03 14:19:32 +01:00
{
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2019-12-03 14:19:32 +01:00
aux_equations . push_back ( neweq ) ;
}
2009-09-30 17:10:31 +02:00
2018-12-20 17:04:28 +01:00
if ( neweqs . size ( ) > 0 )
2009-10-07 16:07:13 +02:00
{
cout < < " Substitution of " ;
2009-12-16 18:13:23 +01:00
switch ( type )
2009-10-07 16:07:13 +02:00
{
2018-07-17 17:38:26 +02:00
case AuxVarType : : endoLead :
2009-10-07 16:07:13 +02:00
cout < < " endo leads >= 2 " ;
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : endoLag :
2009-10-07 16:07:13 +02:00
cout < < " endo lags >= 2 " ;
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : exoLead :
2009-10-07 18:34:42 +02:00
cout < < " exo leads " ;
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : exoLag :
2009-10-07 18:34:42 +02:00
cout < < " exo lags " ;
2009-10-07 16:07:13 +02:00
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : expectation :
2009-10-30 06:21:54 +01:00
cout < < " expectation " ;
break ;
2018-07-17 17:38:26 +02:00
case AuxVarType : : diffForward :
2013-04-25 18:09:31 +02:00
cout < < " forward vars " ;
break ;
2016-11-25 17:15:13 +01:00
default :
cerr < < " DynamicModel::substituteLeadLagInternal: impossible case " < < endl ;
2011-03-21 18:40:57 +01:00
exit ( EXIT_FAILURE ) ;
2009-10-07 16:07:13 +02:00
}
cout < < " : added " < < neweqs . size ( ) < < " auxiliary variables and equations. " < < endl ;
}
2009-09-30 17:10:31 +02:00
}
2017-06-12 14:56:44 +02:00
void
2018-01-30 10:06:56 +01:00
DynamicModel : : substituteAdl ( )
2017-06-12 14:56:44 +02:00
{
2021-02-19 17:45:02 +01:00
/* Contrary to other substitution methods, we do the substitution in MLV
definitions here , instead of doing it at the ExprNode method level ,
because otherwise this would substitute MLV in the original model ( see
# 65). * /
for ( auto & [ id , definition ] : local_variables_table )
definition = definition - > substituteAdl ( ) ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-06-04 12:26:16 +02:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteAdl ( ) ) ;
2021-12-06 16:34:57 +01:00
for ( auto & equation : static_only_equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteAdl ( ) ) ;
2018-01-30 10:06:56 +01:00
}
2020-11-10 18:04:05 +01:00
void
DynamicModel : : substituteModelLocalVariables ( )
{
for ( auto & equation : equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteModelLocalVariables ( ) ) ;
2021-12-06 15:35:01 +01:00
for ( auto & equation : static_only_equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteModelLocalVariables ( ) ) ;
2020-11-10 18:04:05 +01:00
/* We can’ t clear local_variables_table at this point, because in case of
ramsey_policy , the original model is saved via DynamicModel : : operator = ( )
before computing the FOC . But since DataTree : : operator = ( ) clones all
nodes , it will try to clone nodes containing model - local variables , and
this will fail at the point where DataTree methods try to evaluate those
nodes to a numerical value . */
}
2020-02-20 15:29:10 +01:00
set < int >
2019-08-19 14:51:21 +02:00
DynamicModel : : getEquationNumbersFromTags ( const set < string > & eqtags ) const
2018-05-30 16:48:08 +02:00
{
2020-02-20 15:29:10 +01:00
set < int > eqnumbers ;
2019-12-20 16:59:30 +01:00
for ( auto & eqtag : eqtags )
2019-11-18 17:13:49 +01:00
{
2020-02-20 15:29:10 +01:00
set < int > tmp = equation_tags . getEqnsByTag ( " name " , eqtag ) ;
if ( tmp . empty ( ) )
2018-06-05 16:38:37 +02:00
{
2019-11-18 17:13:49 +01:00
cerr < < " ERROR: looking for equation tag " < < eqtag < < " failed. " < < endl ;
exit ( EXIT_FAILURE ) ;
2018-06-05 16:38:37 +02:00
}
2020-02-20 15:29:10 +01:00
eqnumbers . insert ( tmp . begin ( ) , tmp . end ( ) ) ;
2019-11-18 17:13:49 +01:00
}
2019-08-19 14:51:21 +02:00
return eqnumbers ;
2018-06-05 18:38:53 +02:00
}
2022-01-19 15:53:45 +01:00
set < int >
DynamicModel : : findPacExpectationEquationNumbers ( ) const
2018-06-05 18:38:53 +02:00
{
2022-01-19 15:53:45 +01:00
set < int > eqnumbers ;
2022-06-03 16:24:26 +02:00
for ( int i { 0 } ;
auto & equation : equations )
2018-06-05 18:38:53 +02:00
{
2022-01-19 15:53:45 +01:00
if ( equation - > containsPacExpectation ( ) )
2020-02-20 15:29:10 +01:00
eqnumbers . insert ( i ) ;
2018-06-05 18:38:53 +02:00
i + + ;
}
2022-01-19 15:53:45 +01:00
return eqnumbers ;
2018-06-05 18:38:53 +02:00
}
2019-10-22 14:56:28 +02:00
pair < lag_equivalence_table_t , ExprNode : : subst_table_t >
2022-01-20 16:15:43 +01:00
DynamicModel : : substituteUnaryOps ( VarExpectationModelTable & var_expectation_model_table , PacModelTable & pac_model_table )
2018-06-07 12:53:00 +02:00
{
vector < int > eqnumbers ( equations . size ( ) ) ;
iota ( eqnumbers . begin ( ) , eqnumbers . end ( ) , 0 ) ;
2022-07-12 16:39:17 +02:00
return substituteUnaryOps ( { eqnumbers . begin ( ) , eqnumbers . end ( ) } , var_expectation_model_table , pac_model_table ) ;
2018-06-07 12:53:00 +02:00
}
2019-10-22 14:56:28 +02:00
pair < lag_equivalence_table_t , ExprNode : : subst_table_t >
2022-01-20 16:15:43 +01:00
DynamicModel : : substituteUnaryOps ( const set < int > & eqnumbers , VarExpectationModelTable & var_expectation_model_table , PacModelTable & pac_model_table )
2018-06-05 18:38:53 +02:00
{
2019-10-22 14:56:28 +02:00
lag_equivalence_table_t nodes ;
2019-08-19 14:51:21 +02:00
ExprNode : : subst_table_t subst_table ;
2019-08-19 18:22:55 +02:00
// Mark unary ops to be substituted in model local variables that appear in selected equations
2018-06-05 16:38:37 +02:00
set < int > used_local_vars ;
2018-06-07 12:53:00 +02:00
for ( int eqnumber : eqnumbers )
2018-07-17 18:34:07 +02:00
equations [ eqnumber ] - > collectVariables ( SymbolType : : modelLocalVariable , used_local_vars ) ;
2020-07-08 12:13:35 +02:00
for ( int mlv : used_local_vars )
local_variables_table [ mlv ] - > findUnaryOpNodesForAuxVarCreation ( nodes ) ;
2018-05-30 16:48:08 +02:00
2019-08-19 18:22:55 +02:00
// Mark unary ops to be substituted in selected equations
2018-06-07 12:53:00 +02:00
for ( int eqnumber : eqnumbers )
2019-10-22 14:56:28 +02:00
equations [ eqnumber ] - > findUnaryOpNodesForAuxVarCreation ( nodes ) ;
2018-05-30 16:48:08 +02:00
// Substitute in model local variables
vector < BinaryOpNode * > neweqs ;
2020-07-08 12:13:35 +02:00
for ( int mlv : used_local_vars )
local_variables_table [ mlv ] = local_variables_table [ mlv ] - > substituteUnaryOpNodes ( nodes , subst_table , neweqs ) ;
2018-05-30 16:48:08 +02:00
// Substitute in equations
2020-07-08 12:13:35 +02:00
for ( int eq : eqnumbers )
2018-05-30 16:48:08 +02:00
{
2020-07-08 12:13:35 +02:00
auto substeq = dynamic_cast < BinaryOpNode * > ( equations [ eq ] - >
2019-12-16 19:42:59 +01:00
substituteUnaryOpNodes ( nodes , subst_table , neweqs ) ) ;
assert ( substeq ) ;
2020-07-08 12:13:35 +02:00
equations [ eq ] = substeq ;
2018-05-30 16:48:08 +02:00
}
2022-01-20 16:15:43 +01:00
// Substitute in expressions of var_expectation_model
var_expectation_model_table . substituteUnaryOpsInExpression ( nodes , subst_table , neweqs ) ;
2022-01-18 12:40:15 +01:00
// Substitute in growth terms in pac_model and pac_target_info
pac_model_table . substituteUnaryOpsInGrowth ( nodes , subst_table , neweqs ) ;
2018-05-30 16:48:08 +02:00
// Add new equations
2019-12-20 16:59:30 +01:00
for ( auto & neweq : neweqs )
2019-12-03 14:19:32 +01:00
{
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2019-12-03 14:19:32 +01:00
aux_equations . push_back ( neweq ) ;
}
2018-05-30 16:48:08 +02:00
2018-12-20 17:04:28 +01:00
if ( subst_table . size ( ) > 0 )
2018-05-30 16:48:08 +02:00
cout < < " Substitution of Unary Ops: added " < < neweqs . size ( ) < < " auxiliary variables and equations. " < < endl ;
2019-08-19 14:51:21 +02:00
return { nodes , subst_table } ;
2018-05-30 16:48:08 +02:00
}
2019-10-22 14:56:28 +02:00
pair < lag_equivalence_table_t , ExprNode : : subst_table_t >
2022-01-20 16:15:43 +01:00
DynamicModel : : substituteDiff ( VarExpectationModelTable & var_expectation_model_table , PacModelTable & pac_model_table )
2018-01-30 10:06:56 +01:00
{
2019-08-20 12:50:41 +02:00
/* Note: at this point, we know that there is no diff operator with a lead,
because they have been expanded by DataTree : : AddDiff ( ) .
Hence we can go forward with the substitution without worrying about the
expectation operator . */
2019-10-22 14:56:28 +02:00
lag_equivalence_table_t diff_nodes ;
2019-08-19 14:51:21 +02:00
ExprNode : : subst_table_t diff_subst_table ;
2019-08-20 12:50:41 +02:00
// Mark diff operators to be substituted in model local variables
2018-06-05 18:38:53 +02:00
set < int > used_local_vars ;
2022-06-02 10:50:21 +02:00
for ( auto equation : equations )
2018-07-17 18:34:07 +02:00
equation - > collectVariables ( SymbolType : : modelLocalVariable , used_local_vars ) ;
2022-06-02 10:50:21 +02:00
for ( auto & [ symb_id , expr ] : local_variables_table )
if ( used_local_vars . contains ( symb_id ) )
expr - > findDiffNodes ( diff_nodes ) ;
2018-03-02 12:32:01 +01:00
2019-08-20 12:50:41 +02:00
// Mark diff operators to be substituted in equations
2022-06-02 10:50:21 +02:00
for ( auto equation : equations )
2019-10-22 14:56:28 +02:00
equation - > findDiffNodes ( diff_nodes ) ;
2018-01-30 10:06:56 +01:00
2021-10-27 16:26:52 +02:00
pac_model_table . findDiffNodesInGrowth ( diff_nodes ) ;
2019-11-07 20:17:49 +01:00
2018-01-30 10:06:56 +01:00
// Substitute in model local variables
2018-02-28 17:33:00 +01:00
vector < BinaryOpNode * > neweqs ;
2022-06-02 10:50:21 +02:00
for ( auto & [ symb_id , expr ] : local_variables_table )
expr = expr - > substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ;
2018-01-30 10:06:56 +01:00
// Substitute in equations
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-01-30 10:06:56 +01:00
{
2019-12-16 19:42:59 +01:00
auto substeq = dynamic_cast < BinaryOpNode * > ( equation - >
substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ) ;
assert ( substeq ) ;
2018-06-04 12:26:16 +02:00
equation = substeq ;
2018-01-30 10:06:56 +01:00
}
2022-01-20 16:15:43 +01:00
var_expectation_model_table . substituteDiffNodesInExpression ( diff_nodes , diff_subst_table , neweqs ) ;
2021-10-27 16:26:52 +02:00
pac_model_table . substituteDiffNodesInGrowth ( diff_nodes , diff_subst_table , neweqs ) ;
2019-02-28 19:22:34 +01:00
2018-01-30 10:06:56 +01:00
// Add new equations
2022-06-02 10:50:21 +02:00
for ( auto neweq : neweqs )
2019-12-03 14:19:32 +01:00
{
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2019-12-03 14:19:32 +01:00
aux_equations . push_back ( neweq ) ;
}
2018-03-02 16:40:19 +01:00
2018-12-20 17:04:28 +01:00
if ( diff_subst_table . size ( ) > 0 )
2018-01-30 10:06:56 +01:00
cout < < " Substitution of Diff operator: added " < < neweqs . size ( ) < < " auxiliary variables and equations. " < < endl ;
2019-08-19 14:51:21 +02:00
2019-10-22 14:56:28 +02:00
return { diff_nodes , diff_subst_table } ;
2017-06-12 14:56:44 +02:00
}
2009-10-29 18:16:10 +01:00
void
2018-12-20 17:04:28 +01:00
DynamicModel : : substituteExpectation ( bool partial_information_model )
2009-10-29 18:16:10 +01:00
{
ExprNode : : subst_table_t subst_table ;
vector < BinaryOpNode * > neweqs ;
2009-11-09 16:13:47 +01:00
// Substitute in model local variables
2022-06-02 10:50:21 +02:00
for ( auto & [ symb_id , expr ] : local_variables_table )
expr = expr - > substituteExpectation ( subst_table , neweqs , partial_information_model ) ;
2009-10-29 18:16:10 +01:00
// Substitute in equations
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2009-10-29 18:16:10 +01:00
{
2021-12-06 16:20:17 +01:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteExpectation ( subst_table , neweqs , partial_information_model ) ) ;
assert ( equation ) ;
2009-10-29 18:16:10 +01:00
}
2021-12-06 16:20:17 +01:00
/* No need to substitute in static_only_equations, since expectation()
operators in [ static ] equations are forbidden at the parsing level . */
2009-10-29 18:16:10 +01:00
// Add new equations
2022-06-02 10:50:21 +02:00
for ( auto neweq : neweqs )
2019-12-03 14:19:32 +01:00
{
2022-05-05 18:39:27 +02:00
addEquation ( neweq , nullopt ) ;
2019-12-03 14:19:32 +01:00
aux_equations . push_back ( neweq ) ;
}
2009-10-29 18:16:10 +01:00
2018-12-20 17:04:28 +01:00
if ( subst_table . size ( ) > 0 )
2009-11-09 16:13:47 +01:00
{
if ( partial_information_model )
cout < < " Substitution of Expectation operator: added " < < subst_table . size ( ) < < " auxiliary variables and " < < neweqs . size ( ) < < " auxiliary equations. " < < endl ;
else
cout < < " Substitution of Expectation operator: added " < < neweqs . size ( ) < < " auxiliary variables and equations. " < < endl ;
}
2009-10-29 18:16:10 +01:00
}
2009-11-07 19:37:11 +01:00
void
DynamicModel : : transformPredeterminedVariables ( )
{
2021-02-19 20:09:48 +01:00
for ( auto & [ id , definition ] : local_variables_table )
definition = definition - > decreaseLeadsLagsPredeterminedVariables ( ) ;
2018-04-18 14:29:40 +02:00
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2009-11-07 19:37:11 +01:00
{
2021-12-06 12:58:48 +01:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > decreaseLeadsLagsPredeterminedVariables ( ) ) ;
assert ( equation ) ;
2009-11-07 19:37:11 +01:00
}
2021-12-06 12:58:48 +01:00
// No need to handle static_only_equations, since there are no leads/lags there
2009-11-07 19:37:11 +01:00
}
2022-03-30 17:40:01 +02:00
void
DynamicModel : : substituteLogTransform ( )
{
for ( int symb_id : symbol_table . getVariablesWithLogTransform ( ) )
{
expr_t aux_def = AddLog ( AddVariable ( symb_id ) ) ;
int aux_symb_id = symbol_table . addLogTransformAuxiliaryVar ( symb_id , 0 , aux_def ) ;
for ( auto & [ id , definition ] : local_variables_table )
definition = definition - > substituteLogTransform ( symb_id , aux_symb_id ) ;
for ( auto & equation : equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteLogTransform ( symb_id , aux_symb_id ) ) ;
for ( auto & equation : static_only_equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteLogTransform ( symb_id , aux_symb_id ) ) ;
/*
We add the following new equations :
+ X = exp ( log_X ) to the model
+ log_X = log ( X ) to the list of auxiliary equations
In this way :
+ statements like X = 1 in initval / endval blocks will be correctly
handled ( i . e . log_X will be initialized to 0 in this case ) , through
the set_auxiliary_variables . m and dynamic_set_auxiliary_series . m files
+ computation of X in perfect foresight simulations will be done by
simple evaluation when using block decomposition ( X will belong to an
block of type “ evaluate ” , or maybe even the epilogue )
*/
addAuxEquation ( AddEqual ( AddVariable ( aux_symb_id ) , aux_def ) ) ;
addEquation ( AddEqual ( AddVariable ( symb_id ) , AddExp ( AddVariable ( aux_symb_id ) ) ) ,
2022-05-05 18:39:27 +02:00
nullopt , { } ) ;
2022-03-30 17:40:01 +02:00
}
}
void
DynamicModel : : checkNoWithLogTransform ( const set < int > & eqnumbers )
{
set < int > endos ;
for ( int eq : eqnumbers )
equations [ eq ] - > collectVariables ( SymbolType : : endogenous , endos ) ;
const set < int > & with_log_transform = symbol_table . getVariablesWithLogTransform ( ) ;
vector < int > intersect ;
set_intersection ( endos . begin ( ) , endos . end ( ) ,
with_log_transform . begin ( ) , with_log_transform . end ( ) ,
back_inserter ( intersect ) ) ;
if ( ! intersect . empty ( ) )
{
cerr < < " ERROR: the following variables are declared with var(log) and therefore cannot appear in a VAR/TCM/PAC equation: " ;
for ( int symb_id : intersect )
cerr < < symbol_table . getName ( symb_id ) < < " " ;
cerr < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2010-10-15 19:05:16 +02:00
void
DynamicModel : : detrendEquations ( )
{
2013-10-29 11:46:54 +01:00
// We go backwards in the list of trend_vars, to deal correctly with I(2) processes
2019-12-11 16:21:18 +01:00
for ( auto it = nonstationary_symbols_map . crbegin ( ) ;
it ! = nonstationary_symbols_map . crend ( ) ; + + it )
2021-12-06 12:53:35 +01:00
{
for ( auto & equation : equations )
{
equation = dynamic_cast < BinaryOpNode * > ( equation - > detrend ( it - > first , it - > second . first , it - > second . second ) ) ;
assert ( equation ) ;
}
for ( auto & equation : static_only_equations )
{
equation = dynamic_cast < BinaryOpNode * > ( equation - > detrend ( it - > first , it - > second . first , it - > second . second ) ) ;
assert ( equation ) ;
}
}
2010-10-15 19:05:16 +02:00
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2010-10-15 19:05:16 +02:00
{
2021-12-06 12:53:35 +01:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > removeTrendLeadLag ( trend_symbols_map ) ) ;
assert ( equation ) ;
}
for ( auto & equation : static_only_equations )
{
equation = dynamic_cast < BinaryOpNode * > ( equation - > removeTrendLeadLag ( trend_symbols_map ) ) ;
assert ( equation ) ;
2010-10-15 19:05:16 +02:00
}
}
void
DynamicModel : : removeTrendVariableFromEquations ( )
{
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2010-10-15 19:05:16 +02:00
{
2021-12-06 12:53:35 +01:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > replaceTrendVar ( ) ) ;
assert ( equation ) ;
}
for ( auto & equation : static_only_equations )
{
equation = dynamic_cast < BinaryOpNode * > ( equation - > replaceTrendVar ( ) ) ;
assert ( equation ) ;
2010-10-15 19:05:16 +02:00
}
}
2013-04-25 18:09:31 +02:00
void
2018-12-20 17:04:28 +01:00
DynamicModel : : differentiateForwardVars ( const vector < string > & subset )
2013-04-25 18:09:31 +02:00
{
2018-12-20 17:04:28 +01:00
substituteLeadLagInternal ( AuxVarType : : diffForward , true , subset ) ;
2013-04-25 18:09:31 +02:00
}
2009-09-30 17:10:31 +02:00
void
2010-09-16 19:00:48 +02:00
DynamicModel : : fillEvalContext ( eval_context_t & eval_context ) const
2009-09-30 17:10:31 +02:00
{
// First, auxiliary variables
2018-06-04 12:26:16 +02:00
for ( auto aux_equation : aux_equations )
2009-09-30 17:10:31 +02:00
{
2018-11-28 14:32:26 +01:00
assert ( aux_equation - > op_code = = BinaryOpcode : : equal ) ;
2019-12-16 19:42:59 +01:00
auto auxvar = dynamic_cast < VariableNode * > ( aux_equation - > arg1 ) ;
assert ( auxvar ) ;
2009-09-30 17:10:31 +02:00
try
{
2018-11-28 14:32:26 +01:00
double val = aux_equation - > arg2 - > eval ( eval_context ) ;
eval_context [ auxvar - > symb_id ] = val ;
2009-09-30 17:10:31 +02:00
}
2009-12-16 18:13:23 +01:00
catch ( ExprNode : : EvalException & e )
2009-09-30 17:10:31 +02:00
{
// Do nothing
}
}
2009-07-10 17:37:51 +02:00
2009-09-30 17:10:31 +02:00
// Second, model local variables
2022-06-02 10:50:21 +02:00
for ( auto & [ symb_id , expression ] : local_variables_table )
2009-09-30 17:10:31 +02:00
{
try
{
double val = expression - > eval ( eval_context ) ;
2022-06-02 10:50:21 +02:00
eval_context [ symb_id ] = val ;
2009-09-30 17:10:31 +02:00
}
2009-12-16 18:13:23 +01:00
catch ( ExprNode : : EvalException & e )
2009-09-30 17:10:31 +02:00
{
// Do nothing
}
}
2010-10-15 19:05:16 +02:00
//Third, trend variables
2020-01-30 12:47:59 +01:00
for ( int trendVar : symbol_table . getTrendVarIds ( ) )
2019-12-20 16:59:30 +01:00
eval_context [ trendVar ] = 2 ; //not <= 0 bc of log, not 1 bc of powers
2009-09-30 17:10:31 +02:00
}
2011-10-14 14:35:32 +02:00
2013-04-11 17:07:39 +02:00
void
2022-05-05 18:39:27 +02:00
DynamicModel : : addStaticOnlyEquation ( expr_t eq , optional < int > lineno , const map < string , string > & eq_tags )
2013-04-11 17:07:39 +02:00
{
2019-12-16 19:42:59 +01:00
auto beq = dynamic_cast < BinaryOpNode * > ( eq ) ;
assert ( beq & & beq - > op_code = = BinaryOpcode : : equal ) ;
2013-04-11 17:07:39 +02:00
2020-02-20 15:29:10 +01:00
static_only_equations_equation_tags . add ( static_only_equations . size ( ) , eq_tags ) ;
2013-04-11 17:07:39 +02:00
static_only_equations . push_back ( beq ) ;
2022-05-05 18:39:27 +02:00
static_only_equations_lineno . push_back ( move ( lineno ) ) ;
2013-04-11 17:07:39 +02:00
}
size_t
DynamicModel : : staticOnlyEquationsNbr ( ) const
{
return static_only_equations . size ( ) ;
}
size_t
DynamicModel : : dynamicOnlyEquationsNbr ( ) const
{
2020-02-20 15:29:10 +01:00
return equation_tags . getDynamicEqns ( ) . size ( ) ;
2013-04-11 17:07:39 +02:00
}
2021-07-20 18:18:24 +02:00
void
2022-05-05 18:39:27 +02:00
DynamicModel : : addOccbinEquation ( expr_t eq , optional < int > lineno , const map < string , string > & eq_tags , const vector < string > & regimes_bind , const vector < string > & regimes_relax )
2021-07-20 18:18:24 +02:00
{
auto beq = dynamic_cast < BinaryOpNode * > ( eq ) ;
assert ( beq & & beq - > op_code = = BinaryOpcode : : equal ) ;
// Construct the term to be added to the corresponding equation
expr_t basic_term = AddMinus ( beq - > arg1 , beq - > arg2 ) ;
expr_t term = basic_term ;
for ( auto & regime : regimes_bind )
{
int param_id = symbol_table . getID ( ParsingDriver : : buildOccbinBindParamName ( regime ) ) ;
term = AddTimes ( term , AddVariable ( param_id ) ) ;
}
for ( auto & regime : regimes_relax )
{
int param_id = symbol_table . getID ( ParsingDriver : : buildOccbinBindParamName ( regime ) ) ;
term = AddTimes ( term , AddMinus ( One , AddVariable ( param_id ) ) ) ;
}
// Create or update the dynamic equation
2023-01-04 16:44:52 +01:00
optional < int > eqn { equation_tags . getEqnByTag ( " name " , eq_tags . at ( " name " ) ) } ;
if ( eqn )
2021-07-20 18:18:24 +02:00
{
2023-01-04 16:44:52 +01:00
BinaryOpNode * orig_eq { equations [ * eqn ] } ;
2021-07-20 18:18:24 +02:00
/* In the following, we could have kept only orig_eq->arg1, but the
following adds a ( somewhat bizarre ) support for equation snippets
without “ bind ” nor “ relax ” */
2023-01-04 16:44:52 +01:00
equations [ * eqn ] = AddEqual ( AddPlus ( AddMinus ( orig_eq - > arg1 , orig_eq - > arg2 ) , term ) , Zero ) ;
2021-07-20 18:18:24 +02:00
// It’ s unclear how to update lineno and tags, so don’ t do it
}
2023-01-04 16:44:52 +01:00
else
2021-07-20 18:18:24 +02:00
{
auto eq_tags_dynamic = eq_tags ;
eq_tags_dynamic [ " dynamic " ] = " " ;
addEquation ( AddEqual ( term , Zero ) , lineno , eq_tags_dynamic ) ;
}
// Create or update the static equation (corresponding to the pure relax regime)
if ( regimes_bind . empty ( ) )
{
2023-01-04 16:44:52 +01:00
/* Similar remark as above. We could have entirely skipped this
equation updating , since normally there is only one such clause ,
but the following adds a ( somewhat bizarre ) support for equation
snippets without “ bind ” nor “ relax ” */
optional < int > eqn_static { static_only_equations_equation_tags . getEqnByTag ( " name " , eq_tags . at ( " name " ) ) } ;
if ( eqn_static )
2021-07-20 18:18:24 +02:00
{
2023-01-04 16:44:52 +01:00
BinaryOpNode * orig_eq { static_only_equations [ * eqn_static ] } ;
static_only_equations [ * eqn_static ] = AddEqual ( AddPlus ( AddMinus ( orig_eq - > arg1 , orig_eq - > arg2 ) , basic_term ) , Zero ) ;
2021-07-20 18:18:24 +02:00
// It’ s unclear how to update lineno and tags, so don’ t do it
}
2023-01-04 16:44:52 +01:00
else
2021-07-20 18:18:24 +02:00
{
auto eq_tags_static = eq_tags ;
eq_tags_static [ " static " ] = " " ;
addStaticOnlyEquation ( AddEqual ( basic_term , Zero ) , lineno , eq_tags_static ) ;
}
}
}
2015-05-10 18:16:11 +02:00
bool
2022-06-24 15:45:35 +02:00
DynamicModel : : isChecksumMatching ( const string & basename ) const
2015-05-10 18:16:11 +02:00
{
2019-10-07 15:20:07 +02:00
stringstream buffer ;
2015-05-10 18:16:11 +02:00
// Write equation tags
2020-02-20 15:29:10 +01:00
equation_tags . writeCheckSumInfo ( buffer ) ;
2013-09-17 15:11:57 +02:00
2022-07-12 14:13:27 +02:00
constexpr ExprNodeOutputType buffer_type { ExprNodeOutputType : : CDynamicModel } ;
2013-09-17 15:11:57 +02:00
2019-10-07 15:57:19 +02:00
deriv_node_temp_terms_t tef_terms ;
temporary_terms_t temp_term_union ;
2015-05-10 18:16:11 +02:00
2022-07-12 14:13:27 +02:00
writeTemporaryTerms < buffer_type > ( temporary_terms_derivatives [ 0 ] ,
temp_term_union , temporary_terms_idxs ,
buffer , tef_terms ) ;
2015-05-10 18:16:11 +02:00
2022-07-12 14:13:27 +02:00
writeModelEquations < buffer_type > ( buffer , temp_term_union ) ;
2013-09-17 15:11:57 +02:00
2019-10-07 15:20:07 +02:00
size_t result = hash < string > { } ( buffer . str ( ) ) ;
2015-05-13 17:11:39 +02:00
2015-05-11 08:52:50 +02:00
// check whether basename directory exist. If not, create it.
2019-10-07 15:20:07 +02:00
// If it does, read old checksum if it exists, return if equal to result
2015-05-10 18:16:11 +02:00
fstream checksum_file ;
2019-10-07 15:20:07 +02:00
auto filename = filesystem : : path { basename } / " checksum " ;
if ( ! filesystem : : create_directory ( basename ) )
2015-05-11 08:52:50 +02:00
{
2018-06-27 15:12:12 +02:00
checksum_file . open ( filename , ios : : in | ios : : binary ) ;
2015-05-11 08:52:50 +02:00
if ( checksum_file . is_open ( ) )
2017-06-01 19:58:32 +02:00
{
2019-10-07 15:20:07 +02:00
size_t old_checksum ;
2017-06-01 19:58:32 +02:00
checksum_file > > old_checksum ;
checksum_file . close ( ) ;
2019-10-07 15:20:07 +02:00
if ( old_checksum = = result )
return true ;
2017-06-01 19:58:32 +02:00
}
2015-05-11 08:52:50 +02:00
}
2019-10-07 15:20:07 +02:00
2015-05-11 08:52:50 +02:00
// write new checksum file if none or different from old checksum
2019-10-07 15:20:07 +02:00
checksum_file . open ( filename , ios : : out | ios : : binary ) ;
if ( ! checksum_file . is_open ( ) )
2017-06-01 19:58:32 +02:00
{
2022-10-11 11:00:50 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < endl ;
2019-10-07 15:20:07 +02:00
exit ( EXIT_FAILURE ) ;
2017-06-01 19:58:32 +02:00
}
2019-10-07 15:20:07 +02:00
checksum_file < < result ;
checksum_file . close ( ) ;
return false ;
2015-05-10 18:16:11 +02:00
}
2015-07-21 17:26:08 +02:00
2017-02-02 15:09:43 +01:00
void
DynamicModel : : writeJsonOutput ( ostream & output ) const
{
2020-06-05 16:07:52 +02:00
deriv_node_temp_terms_t tef_terms ;
writeJsonModelLocalVariables ( output , false , tef_terms ) ;
output < < " , " ;
2017-02-20 12:18:11 +01:00
writeJsonModelEquations ( output , false ) ;
2017-03-10 17:23:35 +01:00
output < < " , " ;
writeJsonXrefs ( output ) ;
2018-09-18 14:50:31 +02:00
output < < " , " ;
writeJsonAST ( output ) ;
2019-10-16 17:34:27 +02:00
output < < " , " ;
writeJsonVariableMapping ( output ) ;
2022-09-26 13:07:18 +02:00
output < < R " (, " dynamic_tmp_nbr " : [) " ;
for ( bool printed_something { false } ;
const auto & tts : temporary_terms_derivatives )
{
if ( exchange ( printed_something , true ) )
output < < " , " ;
output < < tts . size ( ) ;
}
output < < " ], " ;
2022-09-14 17:07:08 +02:00
writeJsonSparseIndicesHelper < true > ( output ) ;
2018-09-18 14:50:31 +02:00
}
void
DynamicModel : : writeJsonAST ( ostream & output ) const
{
vector < pair < string , string > > eqtags ;
2019-04-03 16:32:52 +02:00
output < < R " ( " abstract_syntax_tree " :[) " < < endl ;
2019-04-23 11:07:32 +02:00
for ( int eq = 0 ; eq < static_cast < int > ( equations . size ( ) ) ; eq + + )
2018-09-18 14:50:31 +02:00
{
if ( eq ! = 0 )
output < < " , " ;
2022-05-05 18:39:27 +02:00
output < < R " ({ " number " :) " < < eq ;
if ( equations_lineno [ eq ] )
output < < R " (, " line " :) " < < * equations_lineno [ eq ] ;
2018-09-18 14:50:31 +02:00
2020-02-20 15:29:10 +01:00
equation_tags . writeJsonAST ( output , eq ) ;
2018-09-18 14:50:31 +02:00
2019-04-03 16:32:52 +02:00
output < < R " (, " AST " : ) " ;
2018-09-18 14:50:31 +02:00
equations [ eq ] - > writeJsonAST ( output ) ;
output < < " } " ;
}
output < < " ] " ;
2017-03-10 17:23:35 +01:00
}
2019-10-16 17:34:27 +02:00
void
DynamicModel : : writeJsonVariableMapping ( ostream & output ) const
{
output < < R " ( " variable_mapping " :[) " < < endl ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & [ var , eqs ] : variableMapping )
2020-12-09 16:45:30 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2020-12-09 16:45:30 +01:00
output < < " , " ;
output < < R " ({ " name " : " ) " << symbol_table.getName(var) << R " ( " , " equations " :[) " ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something2 { false } ;
int it2 : eqs )
2021-02-10 16:48:46 +01:00
if ( auto tmp = equation_tags . getTagValueByEqnAndKey ( it2 , " name " ) ;
2023-01-04 16:03:12 +01:00
tmp )
2020-12-09 16:45:30 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something2 , true ) )
2020-12-09 16:45:30 +01:00
output < < " , " ;
2023-01-04 16:03:12 +01:00
output < < ' " ' < < * tmp < < ' " ' ;
2020-12-09 16:45:30 +01:00
}
output < < " ]} " < < endl ;
2019-10-16 17:34:27 +02:00
}
output < < " ] " ;
}
2017-03-10 17:23:35 +01:00
void
2022-06-01 21:57:04 +02:00
DynamicModel : : writeJsonXrefsHelper ( ostream & output , const map < pair < int , int > , set < int > > & xrefmap ) const
2017-03-10 17:23:35 +01:00
{
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & [ symb_lag , eqs ] : xrefmap )
2017-03-10 17:23:35 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2017-03-10 17:23:35 +01:00
output < < " , " ;
2022-06-03 16:24:26 +02:00
output < < R " ({ " name " : " ) " << symbol_table.getName(symb_lag.first) << R " ( " ) "
< < R " (, " shift " : ) " < < symb_lag . second
2019-04-03 16:32:52 +02:00
< < R " (, " equations " : [) " ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something2 { false } ;
int eq : eqs )
2017-03-10 17:23:35 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something2 , true ) )
2017-03-10 17:23:35 +01:00
output < < " , " ;
2022-06-03 16:24:26 +02:00
output < < eq + 1 ;
2017-03-10 17:23:35 +01:00
}
output < < " ]} " ;
}
2017-10-13 16:21:13 +02:00
}
void
DynamicModel : : writeJsonXrefs ( ostream & output ) const
{
2019-04-03 16:32:52 +02:00
output < < R " ( " xrefs " : {) "
< < R " ( " parameters " : [) " ;
2017-10-13 16:21:13 +02:00
writeJsonXrefsHelper ( output , xref_param ) ;
2017-03-10 17:23:35 +01:00
output < < " ] "
2019-04-03 16:32:52 +02:00
< < R " (, " endogenous " : [) " ;
2017-10-13 16:21:13 +02:00
writeJsonXrefsHelper ( output , xref_endo ) ;
2017-03-10 17:23:35 +01:00
output < < " ] "
2019-04-03 16:32:52 +02:00
< < R " (, " exogenous " : [) " ;
2019-12-16 19:42:59 +01:00
writeJsonXrefsHelper ( output , xref_exo ) ;
2017-03-10 17:23:35 +01:00
output < < " ] "
2019-04-03 16:32:52 +02:00
< < R " (, " exogenous_deterministic " : [) " ;
2017-10-13 16:21:13 +02:00
writeJsonXrefsHelper ( output , xref_exo_det ) ;
2017-03-10 17:23:35 +01:00
output < < " ]} " < < endl ;
2017-02-20 12:18:11 +01:00
}
2017-06-23 14:20:48 +02:00
void
DynamicModel : : writeJsonOriginalModelOutput ( ostream & output ) const
{
writeJsonModelEquations ( output , false ) ;
2018-09-18 14:50:31 +02:00
output < < " , " ;
writeJsonAST ( output ) ;
2017-06-23 14:20:48 +02:00
}
2017-06-28 17:11:24 +02:00
void
DynamicModel : : writeJsonDynamicModelInfo ( ostream & output ) const
{
2019-04-03 16:32:52 +02:00
output < < R " ( " model_info " : {) "
< < R " ( " lead_lag_incidence " : [) " ;
2017-06-28 17:11:24 +02:00
// Loop on endogenous variables
int nstatic = 0 ,
2019-12-16 19:42:59 +01:00
nfwrd = 0 ,
npred = 0 ,
nboth = 0 ;
2017-06-28 17:11:24 +02:00
for ( int endoID = 0 ; endoID < symbol_table . endo_nbr ( ) ; endoID + + )
{
if ( endoID ! = 0 )
output < < " , " ;
output < < " [ " ;
int sstatic = 1 ,
2019-12-16 19:42:59 +01:00
sfwrd = 0 ,
spred = 0 ,
sboth = 0 ;
2017-06-28 17:11:24 +02:00
// Loop on periods
for ( int lag = - max_endo_lag ; lag < = max_endo_lead ; lag + + )
{
// Print variableID if exists with current period, otherwise print 0
try
{
if ( lag ! = - max_endo_lag )
output < < " , " ;
2018-07-17 18:34:07 +02:00
int varID = getDerivID ( symbol_table . getID ( SymbolType : : endogenous , endoID ) , lag ) ;
2022-09-14 17:07:08 +02:00
output < < " " < < getJacobianCol ( varID , false ) + 1 ;
2017-06-28 17:11:24 +02:00
if ( lag = = - 1 )
{
sstatic = 0 ;
spred = 1 ;
}
else if ( lag = = 1 )
{
if ( spred = = 1 )
{
sboth = 1 ;
spred = 0 ;
}
else
{
sstatic = 0 ;
sfwrd = 1 ;
}
}
}
catch ( UnknownDerivIDException & e )
{
output < < " 0 " ;
}
}
nstatic + = sstatic ;
2019-12-20 16:59:30 +01:00
nfwrd + = sfwrd ;
npred + = spred ;
nboth + = sboth ;
2017-06-28 17:11:24 +02:00
output < < " ] " ;
}
output < < " ], "
2020-07-02 09:32:50 +02:00
< < R " ( " nstatic " : ) " < < nstatic < < " , " < < endl
< < R " ( " nfwrd " : ) " < < nfwrd < < " , " < < endl
< < R " ( " npred " : ) " < < npred < < " , " < < endl
< < R " ( " nboth " : ) " < < nboth < < " , " < < endl
< < R " ( " nsfwrd " : ) " < < nfwrd + nboth < < " , " < < endl
< < R " ( " nspred " : ) " < < npred + nboth < < " , " < < endl
< < R " ( " ndynamic " : ) " < < npred + nboth + nfwrd < < " , " < < endl
< < R " ( " maximum_endo_lag " : ) " < < max_endo_lag < < " , " < < endl
< < R " ( " maximum_endo_lead " : ) " < < max_endo_lead < < " , " < < endl
< < R " ( " maximum_exo_lag " : ) " < < max_exo_lag < < " , " < < endl
< < R " ( " maximum_exo_lead " : ) " < < max_exo_lead < < " , " < < endl
< < R " ( " maximum_exo_det_lag " : ) " < < max_exo_det_lag < < " , " < < endl
< < R " ( " maximum_exo_det_lead " : ) " < < max_exo_det_lead < < " , " < < endl
< < R " ( " maximum_lag " : ) " < < max_lag < < " , " < < endl
< < R " ( " maximum_lead " : ) " < < max_lead < < " , " < < endl
< < R " ( " orig_maximum_endo_lag " : ) " < < max_endo_lag_orig < < " , " < < endl
< < R " ( " orig_maximum_endo_lead " : ) " < < max_endo_lead_orig < < " , " < < endl
< < R " ( " orig_maximum_exo_lag " : ) " < < max_exo_lag_orig < < " , " < < endl
< < R " ( " orig_maximum_exo_lead " : ) " < < max_exo_lead_orig < < " , " < < endl
< < R " ( " orig_maximum_exo_det_lag " : ) " < < max_exo_det_lag_orig < < " , " < < endl
< < R " ( " orig_maximum_exo_det_lead " : ) " < < max_exo_det_lead_orig < < " , " < < endl
< < R " ( " orig_maximum_lag " : ) " < < max_lag_orig < < " , " < < endl
< < R " ( " orig_maximum_lead " : ) " < < max_lead_orig < < " , " < < endl
< < R " ( " orig_maximum_lag_with_diffs_expanded " : ) " < < max_lag_with_diffs_expanded_orig
2021-08-18 16:52:35 +02:00
< < " , " < < endl
< < R " ( " NNZDerivatives " : [) " ;
for ( int i = 1 ; i < static_cast < int > ( NNZDerivatives . size ( ) ) ; i + + )
{
output < < ( i > computed_derivs_order ? - 1 : NNZDerivatives [ i ] ) ;
if ( i < static_cast < int > ( NNZDerivatives . size ( ) ) - 1 )
output < < " , " ;
}
output < < " ]} "
< < endl ;
2017-06-28 17:11:24 +02:00
}
2017-02-20 12:18:11 +01:00
void
2017-03-02 18:34:18 +01:00
DynamicModel : : writeJsonComputingPassOutput ( ostream & output , bool writeDetails ) const
2017-02-20 12:18:11 +01:00
{
2022-07-12 17:47:02 +02:00
auto [ mlv_output , d_output ] { writeJsonComputingPassOutputHelper < true > ( writeDetails ) } ;
2017-02-20 12:18:11 +01:00
2017-03-02 18:34:18 +01:00
if ( writeDetails )
2019-04-03 16:32:52 +02:00
output < < R " ( " dynamic_model " : {) " ;
2017-03-02 18:34:18 +01:00
else
2019-04-03 16:32:52 +02:00
output < < R " ( " dynamic_model_simple " : {) " ;
2022-07-12 17:47:02 +02:00
output < < mlv_output . str ( ) ;
2019-04-18 17:07:55 +02:00
for ( const auto & it : d_output )
output < < " , " < < it . str ( ) ;
output < < " } " ;
2017-02-20 12:18:11 +01:00
}
void
2022-07-12 17:47:02 +02:00
DynamicModel : : writeJsonParamsDerivatives ( ostream & output , bool writeDetails ) const
2017-02-20 12:18:11 +01:00
{
2018-11-15 16:39:53 +01:00
if ( ! params_derivatives . size ( ) )
2017-02-20 12:18:11 +01:00
return ;
2022-07-12 17:47:02 +02:00
auto [ mlv_output , tt_output , rp_output , gp_output , rpp_output , gpp_output , hp_output , g3p_output ]
{ writeJsonParamsDerivativesHelper < true > ( writeDetails ) } ;
2019-08-22 17:00:36 +02:00
2017-03-02 18:34:18 +01:00
if ( writeDetails )
2019-04-03 16:32:52 +02:00
output < < R " ( " dynamic_model_params_derivative " : {) " ;
2017-03-02 18:34:18 +01:00
else
2019-04-03 16:32:52 +02:00
output < < R " ( " dynamic_model_params_derivatives_simple " : {) " ;
2022-07-12 17:47:02 +02:00
output < < mlv_output . str ( )
< < " , " < < tt_output . str ( )
2019-08-22 15:55:00 +02:00
< < " , " < < rp_output . str ( )
< < " , " < < gp_output . str ( )
< < " , " < < rpp_output . str ( )
< < " , " < < gpp_output . str ( )
< < " , " < < hp_output . str ( )
2019-08-22 17:00:36 +02:00
< < " , " < < g3p_output . str ( )
2017-02-20 12:18:11 +01:00
< < " } " ;
2017-02-02 15:09:43 +01:00
}
2018-08-01 19:41:44 +02:00
void
DynamicModel : : substituteVarExpectation ( const map < string , expr_t > & subst_table )
{
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2018-08-01 19:41:44 +02:00
equation = dynamic_cast < BinaryOpNode * > ( equation - > substituteVarExpectation ( subst_table ) ) ;
}
2020-09-10 14:24:20 +02:00
void
DynamicModel : : checkNoRemainingPacExpectation ( ) const
{
for ( size_t eq = 0 ; eq < equations . size ( ) ; eq + + )
if ( equations [ eq ] - > containsPacExpectation ( ) )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in equation " < < equation_tags . getTagValueByEqnAndKey ( eq , " name " ) . value_or ( to_string ( eq + 1 ) )
2020-09-10 14:24:20 +02:00
< < " , the pac_expectation operator references an unknown pac_model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2021-12-06 16:29:24 +01:00
void
DynamicModel : : simplifyEquations ( )
{
size_t last_subst_table_size = 0 ;
map < VariableNode * , NumConstNode * > subst_table ;
// Equations with “mcp” tag are excluded, see dynare#1697
findConstantEquationsWithoutMcpTag ( subst_table ) ;
while ( subst_table . size ( ) ! = last_subst_table_size )
{
last_subst_table_size = subst_table . size ( ) ;
for ( auto & [ id , definition ] : local_variables_table )
definition = definition - > replaceVarsInEquation ( subst_table ) ;
for ( auto & equation : equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > replaceVarsInEquation ( subst_table ) ) ;
for ( auto & equation : static_only_equations )
equation = dynamic_cast < BinaryOpNode * > ( equation - > replaceVarsInEquation ( subst_table ) ) ;
subst_table . clear ( ) ;
findConstantEquationsWithoutMcpTag ( subst_table ) ;
}
}
2021-10-26 18:06:26 +02:00
void
DynamicModel : : checkNoRemainingPacTargetNonstationary ( ) const
{
for ( size_t eq = 0 ; eq < equations . size ( ) ; eq + + )
if ( equations [ eq ] - > containsPacTargetNonstationary ( ) )
{
2023-01-04 16:03:12 +01:00
cerr < < " ERROR: in equation " < < equation_tags . getTagValueByEqnAndKey ( eq , " name " ) . value_or ( to_string ( eq + 1 ) )
2021-10-26 18:06:26 +02:00
< < " , the pac_target_nonstationary operator does not match a corresponding 'pac_target_info' block " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2023-01-04 16:18:53 +01:00
void
DynamicModel : : checkIsLinear ( ) const
{
if ( ! nonzero_hessian_eqs . empty ( ) )
{
cerr < < " ERROR: If the model is declared linear the second derivatives must be equal to zero. " < < endl
< < " The following equations have non-zero second derivatives: " < < endl ;
for ( auto it : nonzero_hessian_eqs )
{
cerr < < " * Eq # " < < it + 1 ;
if ( optional < string > eqname { equation_tags . getTagValueByEqnAndKey ( it , " name " ) } ;
eqname )
cerr < < " [ " < < * eqname < < " ] " ;
cerr < < endl ;
}
exit ( EXIT_FAILURE ) ;
}
}