2009-04-14 16:39:53 +02:00
/*
2022-01-06 14:46:38 +01:00
* Copyright © 2003 - 2022 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>
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 )
dt2 [ it . first ] = f ( it . second ) ;
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
dynJacobianColsNbr { m . dynJacobianColsNbr } ,
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
dynJacobianColsNbr = m . dynJacobianColsNbr ;
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
2022-05-20 11:43:02 +02:00
DynamicModel : : compileDerivative ( ofstream & code_file , unsigned int & instruction_number , int eq , int symb_id , int lag , const temporary_terms_t & temporary_terms , const temporary_terms_idxs_t & temporary_terms_idxs , const deriv_node_temp_terms_t & tef_terms ) const
2009-12-16 18:13:23 +01:00
{
2019-10-28 11:09:36 +01:00
if ( auto it = derivatives [ 1 ] . find ( { eq , getDerivID ( symbol_table . getID ( SymbolType : : endogenous , symb_id ) , lag ) } ) ;
it ! = derivatives [ 1 ] . end ( ) )
2022-05-20 11:43:02 +02:00
it - > second - > compile ( code_file , instruction_number , false , temporary_terms , temporary_terms_idxs , true , false , tef_terms ) ;
2009-12-16 18:13:23 +01:00
else
{
FLDZ_ fldz ;
2010-07-23 11:20:24 +02:00
fldz . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
}
}
2009-07-21 17:50:12 +02:00
void
2022-05-20 11:43:02 +02:00
DynamicModel : : compileChainRuleDerivative ( ofstream & code_file , unsigned int & instruction_number , int blk , int eq , int var , int lag , const temporary_terms_t & temporary_terms , const temporary_terms_idxs_t & temporary_terms_idxs , const deriv_node_temp_terms_t & tef_terms ) const
2009-07-21 17:50:12 +02:00
{
2020-04-24 12:29:02 +02:00
if ( auto it = blocks_derivatives [ blk ] . find ( { eq , var , lag } ) ;
it ! = blocks_derivatives [ blk ] . end ( ) )
2022-05-20 11:43:02 +02:00
it - > second - > compile ( code_file , instruction_number , false , temporary_terms , temporary_terms_idxs , true , false , tef_terms ) ;
2009-07-21 17:50:12 +02:00
else
2009-10-16 18:34:27 +02:00
{
FLDZ_ fldz ;
2010-07-23 11:20:24 +02:00
fldz . write ( code_file , instruction_number ) ;
2009-10-16 18:34:27 +02:00
}
2009-07-21 17:50:12 +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
}
2020-06-22 12:46:33 +02:00
void
DynamicModel : : writeDynamicPerBlockHelper ( int blk , ostream & output , ExprNodeOutputType output_type , temporary_terms_t & temporary_terms , int nze_stochastic , int nze_deterministic , int nze_exo , int nze_exo_det , int nze_other_endo ) const
{
BlockSimulationType simulation_type = blocks [ blk ] . simulation_type ;
int block_size = blocks [ blk ] . size ;
int block_mfs_size = blocks [ blk ] . mfs_size ;
int block_recursive_size = blocks [ blk ] . getRecursiveSize ( ) ;
deriv_node_temp_terms_t tef_terms ;
auto write_eq_tt = [ & ] ( int eq )
{
for ( auto it : blocks_temporary_terms [ blk ] [ eq ] )
{
if ( dynamic_cast < AbstractExternalFunctionNode * > ( it ) )
it - > writeExternalFunctionOutput ( output , output_type , temporary_terms , blocks_temporary_terms_idxs , tef_terms ) ;
output < < " " ;
it - > writeOutput ( output , output_type , blocks_temporary_terms [ blk ] [ eq ] , blocks_temporary_terms_idxs , tef_terms ) ;
output < < ' = ' ;
it - > writeOutput ( output , output_type , temporary_terms , blocks_temporary_terms_idxs , tef_terms ) ;
temporary_terms . insert ( it ) ;
output < < ' ; ' < < endl ;
}
} ;
// The equations
for ( int eq = 0 ; eq < block_size ; eq + + )
{
write_eq_tt ( eq ) ;
EquationType equ_type = getBlockEquationType ( blk , eq ) ;
BinaryOpNode * e = getBlockEquationExpr ( blk , eq ) ;
expr_t lhs = e - > arg1 , rhs = e - > arg2 ;
switch ( simulation_type )
{
case BlockSimulationType : : evaluateBackward :
case BlockSimulationType : : evaluateForward :
evaluation :
if ( equ_type = = EquationType : : evaluateRenormalized )
{
e = getBlockEquationRenormalizedExpr ( blk , eq ) ;
lhs = e - > arg1 ;
rhs = e - > arg2 ;
}
else if ( equ_type ! = EquationType : : evaluate )
{
cerr < < " Type mismatch for equation " < < getBlockEquationID ( blk , eq ) + 1 < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " " ;
lhs - > writeOutput ( output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
output < < ' = ' ;
rhs - > writeOutput ( output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
output < < ' ; ' < < endl ;
break ;
case BlockSimulationType : : solveBackwardSimple :
case BlockSimulationType : : solveForwardSimple :
case BlockSimulationType : : solveBackwardComplete :
case BlockSimulationType : : solveForwardComplete :
case BlockSimulationType : : solveTwoBoundariesComplete :
case BlockSimulationType : : solveTwoBoundariesSimple :
if ( eq < block_recursive_size )
goto evaluation ;
output < < " residual " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < eq - block_recursive_size + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " =( " ;
goto end ;
default :
end :
lhs - > writeOutput ( output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
output < < " )-( " ;
rhs - > writeOutput ( output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
output < < " ); " < < endl ;
}
}
// The Jacobian if we have to solve the block
// Write temporary terms for derivatives
write_eq_tt ( blocks [ blk ] . size ) ;
2020-06-23 15:13:04 +02:00
if ( isCOutput ( output_type ) )
output < < " if (stochastic_mode) { " < < endl ;
else
output < < " if stochastic_mode " < < endl ;
2020-06-22 12:46:33 +02:00
ostringstream i_output , j_output , v_output ;
int line_counter = ARRAY_SUBSCRIPT_OFFSET ( output_type ) ;
for ( const auto & [ indices , d ] : blocks_derivatives [ blk ] )
{
auto [ eq , var , lag ] = indices ;
int jacob_col = blocks_jacob_cols_endo [ blk ] . at ( { var , lag } ) ;
i_output < < " g1_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < eq + 1 < < ' ; ' < < endl ;
j_output < < " g1_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < jacob_col + 1 < < ' ; ' < < endl ;
v_output < < " g1_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
2020-06-23 15:13:04 +02:00
assert ( line_counter = = nze_stochastic + ARRAY_SUBSCRIPT_OFFSET ( output_type ) ) ;
2020-06-22 12:46:33 +02:00
output < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
i_output . str ( " " ) ;
j_output . str ( " " ) ;
v_output . str ( " " ) ;
line_counter = ARRAY_SUBSCRIPT_OFFSET ( output_type ) ;
for ( const auto & [ indices , d ] : blocks_derivatives_exo [ blk ] )
{
auto [ eq , var , lag ] = indices ;
int jacob_col = blocks_jacob_cols_exo [ blk ] . at ( { var , lag } ) ;
i_output < < " g1_x_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < eq + 1 < < ' ; ' < < endl ;
j_output < < " g1_x_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < jacob_col + 1 < < ' ; ' < < endl ;
v_output < < " g1_x_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
2020-06-23 15:13:04 +02:00
assert ( line_counter = = nze_exo + ARRAY_SUBSCRIPT_OFFSET ( output_type ) ) ;
2020-06-22 12:46:33 +02:00
output < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
i_output . str ( " " ) ;
j_output . str ( " " ) ;
v_output . str ( " " ) ;
line_counter = ARRAY_SUBSCRIPT_OFFSET ( output_type ) ;
for ( const auto & [ indices , d ] : blocks_derivatives_exo_det [ blk ] )
{
auto [ eq , var , lag ] = indices ;
int jacob_col = blocks_jacob_cols_exo_det [ blk ] . at ( { var , lag } ) ;
i_output < < " g1_xd_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < eq + 1 < < ' ; ' < < endl ;
j_output < < " g1_xd_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < jacob_col + 1 < < ' ; ' < < endl ;
v_output < < " g1_xd_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
2020-06-23 15:13:04 +02:00
assert ( line_counter = = nze_exo_det + ARRAY_SUBSCRIPT_OFFSET ( output_type ) ) ;
2020-06-22 12:46:33 +02:00
output < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
i_output . str ( " " ) ;
j_output . str ( " " ) ;
v_output . str ( " " ) ;
line_counter = ARRAY_SUBSCRIPT_OFFSET ( output_type ) ;
for ( const auto & [ indices , d ] : blocks_derivatives_other_endo [ blk ] )
{
auto [ eq , var , lag ] = indices ;
int jacob_col = blocks_jacob_cols_other_endo [ blk ] . at ( { var , lag } ) ;
i_output < < " g1_o_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < eq + 1 < < ' ; ' < < endl ;
j_output < < " g1_o_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < jacob_col + 1 < < ' ; ' < < endl ;
v_output < < " g1_o_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
2020-06-23 15:13:04 +02:00
assert ( line_counter = = nze_other_endo + ARRAY_SUBSCRIPT_OFFSET ( output_type ) ) ;
2020-06-22 12:46:33 +02:00
output < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
// Deterministic mode
if ( simulation_type ! = BlockSimulationType : : evaluateForward
& & simulation_type ! = BlockSimulationType : : evaluateBackward )
{
2020-06-23 15:13:04 +02:00
if ( isCOutput ( output_type ) )
output < < " } else { " < < endl ;
else
output < < " else " < < endl ;
2020-06-22 12:46:33 +02:00
i_output . str ( " " ) ;
j_output . str ( " " ) ;
v_output . str ( " " ) ;
line_counter = ARRAY_SUBSCRIPT_OFFSET ( output_type ) ;
if ( simulation_type = = BlockSimulationType : : solveBackwardSimple
| | simulation_type = = BlockSimulationType : : solveForwardSimple
| | simulation_type = = BlockSimulationType : : solveBackwardComplete
| | simulation_type = = BlockSimulationType : : solveForwardComplete )
for ( const auto & [ indices , d ] : blocks_derivatives [ blk ] )
{
auto [ eq , var , lag ] = indices ;
2020-10-07 18:52:34 +02:00
if ( lag = = 0 & & eq > = block_recursive_size & & var > = block_recursive_size )
2020-06-22 12:46:33 +02:00
{
i_output < < " g1_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
2020-10-07 18:52:34 +02:00
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = '
< < eq + 1 - block_recursive_size < < ' ; ' < < endl ;
2020-06-22 12:46:33 +02:00
j_output < < " g1_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = '
< < var + 1 - block_recursive_size < < ' ; ' < < endl ;
v_output < < " g1_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
}
else // solveTwoBoundariesSimple || solveTwoBoundariesComplete
for ( const auto & [ indices , d ] : blocks_derivatives [ blk ] )
{
auto [ eq , var , lag ] = indices ;
assert ( lag > = - 1 & & lag < = 1 ) ;
if ( eq > = block_recursive_size & & var > = block_recursive_size )
{
i_output < < " g1_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = '
< < eq + 1 - block_recursive_size < < ' ; ' < < endl ;
j_output < < " g1_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = '
< < var + 1 - block_recursive_size + block_mfs_size * ( lag + 1 ) < < ' ; ' < < endl ;
v_output < < " g1_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
}
2020-06-23 15:13:04 +02:00
assert ( line_counter = = nze_deterministic + ARRAY_SUBSCRIPT_OFFSET ( output_type ) ) ;
2020-06-22 12:46:33 +02:00
output < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
}
2020-06-23 15:13:04 +02:00
if ( isCOutput ( output_type ) )
output < < " } " < < endl ;
else
output < < " end " < < endl ;
}
int
DynamicModel : : nzeDeterministicJacobianForBlock ( int blk ) const
{
BlockSimulationType simulation_type = blocks [ blk ] . simulation_type ;
int block_recursive_size = blocks [ blk ] . getRecursiveSize ( ) ;
int nze_deterministic = 0 ;
if ( simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete
| | simulation_type = = BlockSimulationType : : solveTwoBoundariesSimple )
nze_deterministic = count_if ( blocks_derivatives [ blk ] . begin ( ) , blocks_derivatives [ blk ] . end ( ) ,
[ = ] ( const auto & kv ) {
auto [ eq , var , lag ] = kv . first ;
return eq > = block_recursive_size & & var > = block_recursive_size ;
} ) ;
else if ( simulation_type = = BlockSimulationType : : solveBackwardSimple
| | simulation_type = = BlockSimulationType : : solveForwardSimple
| | simulation_type = = BlockSimulationType : : solveBackwardComplete
| | simulation_type = = BlockSimulationType : : solveForwardComplete )
nze_deterministic = count_if ( blocks_derivatives [ blk ] . begin ( ) , blocks_derivatives [ blk ] . end ( ) ,
2020-10-07 18:52:34 +02:00
[ = ] ( const auto & kv ) {
2020-06-23 15:13:04 +02:00
auto [ eq , var , lag ] = kv . first ;
2020-10-07 18:52:34 +02:00
return lag = = 0 & & eq > = block_recursive_size & & var > = block_recursive_size ;
2020-06-23 15:13:04 +02:00
} ) ;
return nze_deterministic ;
2020-06-22 12:46:33 +02:00
}
2009-04-14 16:39:53 +02:00
void
2020-05-19 16:56:53 +02:00
DynamicModel : : writeDynamicPerBlockMFiles ( const string & basename ) const
2009-12-16 18:13:23 +01:00
{
2020-05-06 17:13:47 +02:00
temporary_terms_t temporary_terms ; // Temp terms written so far
2009-12-16 18:13:23 +01:00
2020-05-19 16:56:53 +02:00
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
2009-12-16 18:13:23 +01:00
{
2020-05-19 16:56:53 +02:00
BlockSimulationType simulation_type = blocks [ blk ] . simulation_type ;
int block_size = blocks [ blk ] . size ;
int block_mfs_size = blocks [ blk ] . mfs_size ;
2020-06-19 15:15:15 +02:00
// Number of nonzero derivatives for the various Jacobians
int nze_stochastic = blocks_derivatives [ blk ] . size ( ) ;
2020-06-23 15:13:04 +02:00
int nze_deterministic = nzeDeterministicJacobianForBlock ( blk ) ;
2020-06-19 15:15:15 +02:00
int nze_other_endo = blocks_derivatives_other_endo [ blk ] . size ( ) ;
int nze_exo = blocks_derivatives_exo [ blk ] . size ( ) ;
int nze_exo_det = blocks_derivatives_exo_det [ blk ] . size ( ) ;
2020-05-19 16:56:53 +02:00
string filename = packageDir ( basename + " .block " ) + " /dynamic_ " + to_string ( blk + 1 ) + " .m " ;
ofstream output ;
output . open ( filename , ios : : out | ios : : binary ) ;
2020-06-23 15:13:04 +02:00
if ( ! output . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2009-12-16 18:13:23 +01:00
2018-11-23 17:19:59 +01:00
output < < " % " < < endl
2020-05-19 16:56:53 +02:00
< < " % " < < filename < < " : Computes dynamic version of one block " < < endl
2018-11-23 17:19:59 +01:00
< < " % " < < endl
< < " % Warning : this file is generated automatically by Dynare " < < endl
< < " % from model file (.mod) " < < endl < < endl
2020-05-19 16:56:53 +02:00
< < " % " < < endl ;
2020-03-20 17:31:14 +01:00
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
2020-06-16 15:54:51 +02:00
output < < " function [y, T, g1, varargout] = dynamic_ " < < blk + 1 < < " (y, x, params, steady_state, T, it_, stochastic_mode) " < < endl ;
2009-12-16 18:13:23 +01:00
else
2020-10-06 17:16:50 +02:00
output < < " function [residual, y, T, g1, varargout] = dynamic_ " < < blk + 1 < < " (y, x, params, steady_state, T, it_, stochastic_mode) " < < endl ;
2020-04-30 12:48:16 +02:00
2009-12-16 18:13:23 +01:00
output < < " % //////////////////////////////////////////////////////////////////////// " < < endl
2020-05-19 16:56:53 +02:00
< < " % // " < < string ( " Block " ) . substr ( static_cast < int > ( log10 ( blk + 1 ) ) ) < < blk + 1
2020-04-30 12:48:16 +02:00
< < " // " < < endl
2009-12-16 18:13:23 +01:00
< < " % // Simulation type "
< < BlockSim ( simulation_type ) < < " // " < < endl
2020-06-19 16:09:38 +02:00
< < " % //////////////////////////////////////////////////////////////////////// " < < endl ;
2009-12-16 14:21:31 +01:00
2020-06-22 12:46:33 +02:00
if ( simulation_type ! = BlockSimulationType : : evaluateForward
& & simulation_type ! = BlockSimulationType : : evaluateBackward )
2020-06-16 15:34:45 +02:00
output < < " residual=zeros( " < < block_mfs_size < < " ,1); " < < endl ;
2020-05-06 17:13:47 +02:00
2020-06-22 12:46:33 +02:00
output < < " if stochastic_mode " < < endl
< < " g1_i=zeros( " < < nze_stochastic < < " ,1); " < < endl
< < " g1_j=zeros( " < < nze_stochastic < < " ,1); " < < endl
< < " g1_v=zeros( " < < nze_stochastic < < " ,1); " < < endl
< < " g1_x_i=zeros( " < < nze_exo < < " ,1); " < < endl
< < " g1_x_j=zeros( " < < nze_exo < < " ,1); " < < endl
< < " g1_x_v=zeros( " < < nze_exo < < " ,1); " < < endl
< < " g1_xd_i=zeros( " < < nze_exo_det < < " ,1); " < < endl
< < " g1_xd_j=zeros( " < < nze_exo_det < < " ,1); " < < endl
< < " g1_xd_v=zeros( " < < nze_exo_det < < " ,1); " < < endl
< < " g1_o_i=zeros( " < < nze_other_endo < < " ,1); " < < endl
< < " g1_o_j=zeros( " < < nze_other_endo < < " ,1); " < < endl
< < " g1_o_v=zeros( " < < nze_other_endo < < " ,1); " < < endl ;
if ( simulation_type ! = BlockSimulationType : : evaluateForward
& & simulation_type ! = BlockSimulationType : : evaluateBackward )
output < < " else " < < endl
< < " g1_i=zeros( " < < nze_deterministic < < " ,1); " < < endl
< < " g1_j=zeros( " < < nze_deterministic < < " ,1); " < < endl
< < " g1_v=zeros( " < < nze_deterministic < < " ,1); " < < endl ;
output < < " end " < < endl
< < endl ;
2020-05-13 16:58:19 +02:00
2020-06-22 12:46:33 +02:00
writeDynamicPerBlockHelper ( blk , output , ExprNodeOutputType : : matlabDynamicModel , temporary_terms ,
nze_stochastic , nze_deterministic , nze_exo , nze_exo_det , nze_other_endo ) ;
2020-05-13 16:58:19 +02:00
2020-06-22 12:46:33 +02:00
output < < endl
2020-06-19 16:09:38 +02:00
< < " if stochastic_mode " < < endl
2020-06-22 12:46:33 +02:00
< < " g1=sparse(g1_i, g1_j, g1_v, " < < block_size < < " , " < < blocks_jacob_cols_endo [ blk ] . size ( ) < < " ); " < < endl
2020-06-19 16:09:38 +02:00
< < " varargout{1}=sparse(g1_x_i, g1_x_j, g1_x_v, " < < block_size < < " , " < < blocks_jacob_cols_exo [ blk ] . size ( ) < < " ); " < < endl
< < " varargout{2}=sparse(g1_xd_i, g1_xd_j, g1_xd_v, " < < block_size < < " , " < < blocks_jacob_cols_exo_det [ blk ] . size ( ) < < " ); " < < endl
2020-06-19 18:33:53 +02:00
< < " varargout{3}=sparse(g1_o_i, g1_o_j, g1_o_v, " < < block_size < < " , " < < blocks_jacob_cols_other_endo [ blk ] . size ( ) < < " ); " < < endl
< < " else " < < endl ;
2010-11-20 15:52:51 +01:00
switch ( simulation_type )
{
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : evaluateForward :
case BlockSimulationType : : evaluateBackward :
2020-06-22 12:46:33 +02:00
output < < " g1=[]; " < < endl ;
2009-12-16 18:13:23 +01:00
break ;
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : solveBackwardSimple :
case BlockSimulationType : : solveForwardSimple :
case BlockSimulationType : : solveBackwardComplete :
case BlockSimulationType : : solveForwardComplete :
2020-06-22 12:46:33 +02:00
output < < " g1=sparse(g1_i, g1_j, g1_v, " < < block_mfs_size
2020-06-19 18:33:53 +02:00
< < " , " < < block_mfs_size < < " ); " < < endl ;
2009-12-16 18:13:23 +01:00
break ;
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : solveTwoBoundariesSimple :
case BlockSimulationType : : solveTwoBoundariesComplete :
2020-06-22 12:46:33 +02:00
output < < " g1=sparse(g1_i, g1_j, g1_v, " < < block_mfs_size
2020-06-19 18:33:53 +02:00
< < " , " < < 3 * block_mfs_size < < " ); " < < endl ;
2009-12-16 18:13:23 +01:00
break ;
default :
break ;
}
2020-06-19 18:33:53 +02:00
output < < " end " < < endl
< < " end " < < endl ;
2009-12-16 18:13:23 +01:00
output . close ( ) ;
}
}
2009-04-14 16:39:53 +02:00
2020-06-23 15:13:04 +02:00
void
DynamicModel : : writeDynamicPerBlockCFiles ( const string & basename ) const
{
temporary_terms_t temporary_terms ; // Temp terms written so far
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
{
BlockSimulationType simulation_type = blocks [ blk ] . simulation_type ;
int block_size = blocks [ blk ] . size ;
int block_mfs_size = blocks [ blk ] . mfs_size ;
// Number of nonzero derivatives for the various Jacobians
int nze_stochastic = blocks_derivatives [ blk ] . size ( ) ;
int nze_deterministic = nzeDeterministicJacobianForBlock ( blk ) ;
int nze_other_endo = blocks_derivatives_other_endo [ blk ] . size ( ) ;
int nze_exo = blocks_derivatives_exo [ blk ] . size ( ) ;
int nze_exo_det = blocks_derivatives_exo_det [ blk ] . size ( ) ;
string filename = basename + " /model/src/dynamic_ " + to_string ( blk + 1 ) + " .c " ;
ofstream output ;
output . open ( filename , ios : : out | ios : : binary ) ;
if ( ! output . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " /* Block " < < blk + 1 < < endl
< < " " < < BlockSim ( simulation_type ) < < " */ " < < endl
< < endl
< < " #include <math.h> " < < endl
< < " #include <stdlib.h> " < < endl
< < " #include <stdbool.h> " < < endl
< < R " (#include " mex . h " ) " < < endl
< < endl ;
// Write function definition if BinaryOpcode::powerDeriv is used
writePowerDerivHeader ( output ) ;
output < < endl ;
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
2020-09-03 17:52:12 +02:00
output < < " void dynamic_ " < < blk + 1 < < " (double *restrict y, const double *restrict x, int nb_row_x, const double *restrict params, const double *restrict steady_state, double *restrict T, int it_, bool stochastic_mode, double *restrict g1_i, double *restrict g1_j, double *restrict g1_v, double *restrict g1_x_i, double *restrict g1_x_j, double *restrict g1_x_v, double *restrict g1_xd_i, double *restrict g1_xd_j, double *restrict g1_xd_v, double *restrict g1_o_i, double *restrict g1_o_j, double *restrict g1_o_v) " < < endl ;
2020-06-23 15:13:04 +02:00
else
2020-10-06 17:16:50 +02:00
output < < " void dynamic_ " < < blk + 1 < < " (double *restrict y, const double *restrict x, int nb_row_x, const double *restrict params, const double *restrict steady_state, double *restrict T, int it_, bool stochastic_mode, double *restrict residual, double *restrict g1_i, double *restrict g1_j, double *restrict g1_v, double *restrict g1_x_i, double *restrict g1_x_j, double *restrict g1_x_v, double *restrict g1_xd_i, double *restrict g1_xd_j, double *restrict g1_xd_v, double *restrict g1_o_i, double *restrict g1_o_j, double *restrict g1_o_v) " < < endl ;
2020-06-23 15:13:04 +02:00
output < < ' { ' < < endl ;
writeDynamicPerBlockHelper ( blk , output , ExprNodeOutputType : : CDynamicModel , temporary_terms ,
nze_stochastic , nze_deterministic , nze_exo , nze_exo_det , nze_other_endo ) ;
output < < ' } ' < < endl
< < endl ;
ostringstream header ;
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
header < < " void dynamic_ " < < blk + 1 < < " _mx(mxArray *y, const mxArray *x, const mxArray *params, const mxArray *steady_state, mxArray *T, const mxArray *it_, const mxArray *stochastic_mode, mxArray **g1, mxArray **g1_x, mxArray **g1_xd, mxArray **g1_o) " ;
else
2020-10-06 17:16:50 +02:00
header < < " void dynamic_ " < < blk + 1 < < " _mx(mxArray *y, const mxArray *x, const mxArray *params, const mxArray *steady_state, mxArray *T, const mxArray *it_, const mxArray *stochastic_mode, mxArray **residual, mxArray **g1, mxArray **g1_x, mxArray **g1_xd, mxArray **g1_o) " ;
2020-06-23 15:13:04 +02:00
output < < header . str ( ) < < endl
< < ' { ' < < endl
< < " int nb_row_x = mxGetM(x); " < < endl ;
if ( simulation_type ! = BlockSimulationType : : evaluateForward
& & simulation_type ! = BlockSimulationType : : evaluateBackward )
output < < " *residual = mxCreateDoubleMatrix( " < < block_mfs_size < < " ,1,mxREAL); " < < endl ;
output < < " mxArray *g1_i = NULL, *g1_j = NULL, *g1_v = NULL; " < < endl
< < " mxArray *g1_x_i = NULL, *g1_x_j = NULL, *g1_x_v = NULL; " < < endl
< < " mxArray *g1_xd_i = NULL, *g1_xd_j = NULL, *g1_xd_v = NULL; " < < endl
< < " mxArray *g1_o_i = NULL, *g1_o_j = NULL, *g1_o_v = NULL; " < < endl
< < " if (mxGetScalar(stochastic_mode)) { " < < endl
< < " g1_i=mxCreateDoubleMatrix( " < < nze_stochastic < < " ,1,mxREAL); " < < endl
< < " g1_j=mxCreateDoubleMatrix( " < < nze_stochastic < < " ,1,mxREAL); " < < endl
< < " g1_v=mxCreateDoubleMatrix( " < < nze_stochastic < < " ,1,mxREAL); " < < endl
< < " g1_x_i=mxCreateDoubleMatrix( " < < nze_exo < < " ,1,mxREAL); " < < endl
< < " g1_x_j=mxCreateDoubleMatrix( " < < nze_exo < < " ,1,mxREAL); " < < endl
< < " g1_x_v=mxCreateDoubleMatrix( " < < nze_exo < < " ,1,mxREAL); " < < endl
< < " g1_xd_i=mxCreateDoubleMatrix( " < < nze_exo_det < < " ,1,mxREAL); " < < endl
< < " g1_xd_j=mxCreateDoubleMatrix( " < < nze_exo_det < < " ,1,mxREAL); " < < endl
< < " g1_xd_v=mxCreateDoubleMatrix( " < < nze_exo_det < < " ,1,mxREAL); " < < endl
< < " g1_o_i=mxCreateDoubleMatrix( " < < nze_other_endo < < " ,1,mxREAL); " < < endl
< < " g1_o_j=mxCreateDoubleMatrix( " < < nze_other_endo < < " ,1,mxREAL); " < < endl
< < " g1_o_v=mxCreateDoubleMatrix( " < < nze_other_endo < < " ,1,mxREAL); " < < endl ;
if ( simulation_type ! = BlockSimulationType : : evaluateForward
& & simulation_type ! = BlockSimulationType : : evaluateBackward )
output < < " } else { " < < endl
< < " g1_i=mxCreateDoubleMatrix( " < < nze_deterministic < < " ,1,mxREAL); " < < endl
< < " g1_j=mxCreateDoubleMatrix( " < < nze_deterministic < < " ,1,mxREAL); " < < endl
< < " g1_v=mxCreateDoubleMatrix( " < < nze_deterministic < < " ,1,mxREAL); " < < endl ;
output < < " } " < < endl
< < endl ;
2020-06-25 15:19:49 +02:00
// N.B.: In the following, it_ is decreased by 1, to follow C convention
2020-06-23 15:13:04 +02:00
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
2020-06-25 15:19:49 +02:00
output < < " dynamic_ " < < blk + 1 < < " (mxGetPr(y), mxGetPr(x), nb_row_x, mxGetPr(params), mxGetPr(steady_state), mxGetPr(T), mxGetScalar(it_)-1, mxGetScalar(stochastic_mode), g1_i ? mxGetPr(g1_i) : NULL, g1_j ? mxGetPr(g1_j) : NULL, g1_v ? mxGetPr(g1_v) : NULL, g1_x_i ? mxGetPr(g1_x_i) : NULL, g1_x_j ? mxGetPr(g1_x_j) : NULL, g1_x_v ? mxGetPr(g1_x_v) : NULL, g1_xd_i ? mxGetPr(g1_xd_i) : NULL, g1_xd_j ? mxGetPr(g1_xd_j) : NULL, g1_xd_v ? mxGetPr(g1_xd_v) : NULL, g1_o_i ? mxGetPr(g1_o_i) : NULL, g1_o_j ? mxGetPr(g1_o_j) : NULL, g1_o_v ? mxGetPr(g1_o_v) : NULL); " < < endl ;
2020-06-23 15:13:04 +02:00
else
2020-06-25 15:19:49 +02:00
output < < " dynamic_ " < < blk + 1 < < " (mxGetPr(y), mxGetPr(x), nb_row_x, mxGetPr(params), mxGetPr(steady_state), mxGetPr(T), mxGetScalar(it_)-1, mxGetScalar(stochastic_mode), mxGetPr(*residual), g1_i ? mxGetPr(g1_i) : NULL, g1_j ? mxGetPr(g1_j) : NULL, g1_v ? mxGetPr(g1_v) : NULL, g1_x_i ? mxGetPr(g1_x_i) : NULL, g1_x_j ? mxGetPr(g1_x_j) : NULL, g1_x_v ? mxGetPr(g1_x_v) : NULL, g1_xd_i ? mxGetPr(g1_xd_i) : NULL, g1_xd_j ? mxGetPr(g1_xd_j) : NULL, g1_xd_v ? mxGetPr(g1_xd_v) : NULL, g1_o_i ? mxGetPr(g1_o_i) : NULL, g1_o_j ? mxGetPr(g1_o_j) : NULL, g1_o_v ? mxGetPr(g1_o_v) : NULL); " < < endl ;
2020-06-23 15:13:04 +02:00
output < < endl
< < " if (mxGetScalar(stochastic_mode)) { " < < endl
< < " mxArray *m = mxCreateDoubleScalar( " < < block_size < < " ); " < < endl
< < " mxArray *n = mxCreateDoubleScalar( " < < blocks_jacob_cols_endo [ blk ] . size ( ) < < " ); " < < endl
< < " mxArray *plhs[1]; " < < endl
< < " mxArray *prhs[5] = { g1_i, g1_j, g1_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs, 5, prhs, " sparse " );) " < < endl
< < " *g1=plhs[0]; " < < endl
< < " mxDestroyArray(g1_i); " < < endl
< < " mxDestroyArray(g1_j); " < < endl
< < " mxDestroyArray(g1_v); " < < endl
< < " mxDestroyArray(n); " < < endl
< < " n = mxCreateDoubleScalar( " < < blocks_jacob_cols_exo [ blk ] . size ( ) < < " ); " < < endl
< < " mxArray *prhs_x[5] = { g1_x_i, g1_x_j, g1_x_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs, 5, prhs_x, " sparse " );) " < < endl
< < " *g1_x=plhs[0]; " < < endl
< < " mxDestroyArray(g1_x_i); " < < endl
< < " mxDestroyArray(g1_x_j); " < < endl
< < " mxDestroyArray(g1_x_v); " < < endl
< < " mxDestroyArray(n); " < < endl
< < " n = mxCreateDoubleScalar( " < < blocks_jacob_cols_exo_det [ blk ] . size ( ) < < " ); " < < endl
< < " mxArray *prhs_xd[5] = { g1_xd_i, g1_xd_j, g1_xd_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs, 5, prhs_xd, " sparse " );) " < < endl
< < " *g1_xd=plhs[0]; " < < endl
< < " mxDestroyArray(g1_xd_i); " < < endl
< < " mxDestroyArray(g1_xd_j); " < < endl
< < " mxDestroyArray(g1_xd_v); " < < endl
< < " mxDestroyArray(n); " < < endl
< < " n = mxCreateDoubleScalar( " < < blocks_jacob_cols_other_endo [ blk ] . size ( ) < < " ); " < < endl
< < " mxArray *prhs_o[5] = { g1_o_i, g1_o_j, g1_o_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs, 5, prhs_o, " sparse " );) " < < endl
< < " *g1_o=plhs[0]; " < < endl
< < " mxDestroyArray(g1_o_i); " < < endl
< < " mxDestroyArray(g1_o_j); " < < endl
< < " mxDestroyArray(g1_o_v); " < < endl
< < " mxDestroyArray(n); " < < endl
< < " mxDestroyArray(m); " < < endl
< < " } else { " < < endl ;
switch ( simulation_type )
{
case BlockSimulationType : : evaluateForward :
case BlockSimulationType : : evaluateBackward :
output < < " *g1=mxCreateDoubleMatrix(0,0,mxREAL); " < < endl ;
break ;
case BlockSimulationType : : solveBackwardSimple :
case BlockSimulationType : : solveForwardSimple :
case BlockSimulationType : : solveBackwardComplete :
case BlockSimulationType : : solveForwardComplete :
output < < " mxArray *m = mxCreateDoubleScalar( " < < block_mfs_size < < " ); " < < endl
< < " mxArray *n = mxCreateDoubleScalar( " < < block_mfs_size < < " ); " < < endl
< < " mxArray *plhs[1]; " < < endl
< < " mxArray *prhs[5] = { g1_i, g1_j, g1_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs, 5, prhs, " sparse " );) " < < endl
< < " *g1=plhs[0]; " < < endl
< < " mxDestroyArray(g1_i); " < < endl
< < " mxDestroyArray(g1_j); " < < endl
< < " mxDestroyArray(g1_v); " < < endl
< < " mxDestroyArray(n); " < < endl
< < " mxDestroyArray(m); " < < endl ;
break ;
case BlockSimulationType : : solveTwoBoundariesSimple :
case BlockSimulationType : : solveTwoBoundariesComplete :
output < < " mxArray *m = mxCreateDoubleScalar( " < < block_mfs_size < < " ); " < < endl
< < " mxArray *n = mxCreateDoubleScalar( " < < 3 * block_mfs_size < < " ); " < < endl
< < " mxArray *plhs[1]; " < < endl
< < " mxArray *prhs[5] = { g1_i, g1_j, g1_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs, 5, prhs, " sparse " );) " < < endl
< < " *g1=plhs[0]; " < < endl
< < " mxDestroyArray(g1_i); " < < endl
< < " mxDestroyArray(g1_j); " < < endl
< < " mxDestroyArray(g1_v); " < < endl
< < " mxDestroyArray(n); " < < endl
< < " mxDestroyArray(m); " < < endl ;
break ;
default :
break ;
}
output < < " *g1_x=mxCreateDoubleMatrix(0,0,mxREAL); " < < endl
< < " *g1_xd=mxCreateDoubleMatrix(0,0,mxREAL); " < < endl
< < " *g1_o=mxCreateDoubleMatrix(0,0,mxREAL); " < < endl
< < " } " < < endl
< < " } " < < endl ;
output . close ( ) ;
filename = basename + " /model/src/dynamic_ " + to_string ( blk + 1 ) + " .h " ;
ofstream header_output ;
header_output . open ( filename , ios : : out | ios : : binary ) ;
if ( ! header_output . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
header_output < < header . str ( ) < < ' ; ' < < endl ;
header_output . close ( ) ;
}
}
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
{
ostringstream tmp_output ;
ofstream code_file ;
2010-07-23 11:20:24 +02:00
unsigned int instruction_number = 0 ;
2010-01-22 11:03:29 +01:00
bool file_open = false ;
2018-06-27 15:01:31 +02:00
string main_name = basename + " /model/bytecode/dynamic.cod " ;
2018-06-27 15:12:12 +02:00
code_file . open ( main_name , ios : : out | ios : : binary | ios : : ate ) ;
2010-01-22 11:03:29 +01:00
if ( ! code_file . is_open ( ) )
{
2019-04-03 16:32:52 +02:00
cerr < < R " (Error : Can't open file " ) " << main_name << R " ( " for writing) " < < endl ;
2010-01-22 11:03:29 +01:00
exit ( EXIT_FAILURE ) ;
}
int count_u ;
int u_count_int = 0 ;
BlockSimulationType simulation_type ;
if ( ( max_endo_lag > 0 ) & & ( max_endo_lead > 0 ) )
2020-03-20 17:31:14 +01:00
simulation_type = BlockSimulationType : : solveTwoBoundariesComplete ;
2010-01-22 11:03:29 +01: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
2020-05-19 17:43:35 +02:00
writeBytecodeBinFile ( basename + " /model/bytecode/dynamic.bin " , u_count_int , file_open , simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete ) ;
2010-01-22 11:03:29 +01:00
file_open = true ;
//Temporary variables declaration
2020-05-13 15:16:38 +02:00
FDIMT_ fdimt ( temporary_terms_idxs . size ( ) ) ;
2010-07-23 11:20:24 +02:00
fdimt . write ( code_file , instruction_number ) ;
2020-05-06 14:02:58 +02:00
vector < int > exo , exo_det , other_endo ;
2010-01-22 11:03:29 +01:00
2011-02-04 16:25:38 +01:00
for ( int i = 0 ; i < symbol_table . exo_det_nbr ( ) ; i + + )
2010-07-23 11:20:24 +02:00
exo_det . push_back ( i ) ;
2011-02-04 16:25:38 +01:00
for ( int i = 0 ; i < symbol_table . exo_nbr ( ) ; i + + )
2010-07-23 11:20:24 +02:00
exo . push_back ( i ) ;
2010-10-27 15:34:48 +02:00
2018-11-23 17:19:59 +01:00
map < tuple < int , int , int > , expr_t > first_derivatives_reordered_endo ;
map < tuple < int , SymbolType , int , int > , expr_t > first_derivatives_reordered_exo ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d1 ] : derivatives [ 1 ] )
2010-10-27 15:34:48 +02:00
{
2019-12-16 19:42:59 +01:00
int deriv_id = indices [ 1 ] ;
2020-03-24 18:26:06 +01:00
int eq = indices [ 0 ] ;
2010-10-27 15:34:48 +02:00
int symb = getSymbIDByDerivID ( deriv_id ) ;
2020-03-24 18:26:06 +01:00
int var = symbol_table . getTypeSpecificID ( symb ) ;
2010-10-27 15:34:48 +02:00
int lag = getLagByDerivID ( deriv_id ) ;
2018-07-17 18:34:07 +02:00
if ( getTypeByDerivID ( deriv_id ) = = SymbolType : : endogenous )
2019-12-16 19:42:59 +01:00
first_derivatives_reordered_endo [ { lag , var , eq } ] = d1 ;
2018-07-17 18:34:07 +02:00
else if ( getTypeByDerivID ( deriv_id ) = = SymbolType : : exogenous | | getTypeByDerivID ( deriv_id ) = = SymbolType : : exogenousDet )
2019-12-16 19:42:59 +01:00
first_derivatives_reordered_exo [ { lag , getTypeByDerivID ( deriv_id ) , var , eq } ] = d1 ;
2010-10-27 15:34:48 +02:00
}
int prev_var = - 1 ;
int prev_lag = - 999999999 ;
int count_col_endo = 0 ;
2018-11-23 17:19:59 +01:00
for ( const auto & it : first_derivatives_reordered_endo )
2010-10-27 15:34:48 +02:00
{
2018-11-23 17:19:59 +01:00
int var , lag ;
tie ( lag , var , ignore ) = it . first ;
2011-02-04 16:25:38 +01:00
if ( prev_var ! = var | | prev_lag ! = lag )
2010-10-27 15:34:48 +02:00
{
prev_var = var ;
prev_lag = lag ;
count_col_endo + + ;
}
}
2010-11-20 15:52:51 +01:00
prev_var = - 1 ;
prev_lag = - 999999999 ;
2018-07-17 18:34:07 +02:00
SymbolType prev_type { SymbolType : : unusedEndogenous } ; // Any non-exogenous type would do here
2010-11-20 15:52:51 +01:00
int count_col_exo = 0 ;
2014-12-17 09:37:43 +01:00
int count_col_det_exo = 0 ;
2010-11-20 15:52:51 +01:00
2019-12-20 16:59:30 +01:00
for ( const auto & it : first_derivatives_reordered_exo )
2010-11-20 15:52:51 +01:00
{
2018-11-23 17:19:59 +01:00
int var , lag ;
SymbolType type ;
tie ( lag , type , var , ignore ) = it . first ;
2011-03-18 01:09:20 +01:00
if ( prev_var ! = var | | prev_lag ! = lag | | prev_type ! = type )
2010-11-20 15:52:51 +01:00
{
prev_var = var ;
prev_lag = lag ;
2011-03-18 01:09:20 +01:00
prev_type = type ;
2018-07-17 18:34:07 +02:00
if ( type = = SymbolType : : exogenous )
2014-12-17 09:37:43 +01:00
count_col_exo + + ;
2018-07-17 18:34:07 +02:00
else if ( type = = SymbolType : : exogenousDet )
2014-12-17 09:37:43 +01:00
count_col_det_exo + + ;
2010-11-20 15:52:51 +01:00
}
}
2017-06-01 19:58:32 +02:00
2010-01-22 11:03:29 +01:00
FBEGINBLOCK_ fbeginblock ( symbol_table . endo_nbr ( ) ,
simulation_type ,
0 ,
symbol_table . endo_nbr ( ) ,
2020-04-17 14:55:55 +02:00
endo_idx_block2orig ,
eq_idx_block2orig ,
2010-01-22 11:03:29 +01:00
false ,
symbol_table . endo_nbr ( ) ,
2014-12-17 09:37:43 +01:00
max_endo_lag ,
max_endo_lead ,
2010-07-23 11:20:24 +02:00
u_count_int ,
2010-10-27 15:34:48 +02:00
count_col_endo ,
2010-07-23 11:20:24 +02:00
symbol_table . exo_det_nbr ( ) ,
2014-12-17 09:37:43 +01:00
count_col_det_exo ,
symbol_table . exo_nbr ( ) ,
2010-11-20 15:52:51 +01:00
count_col_exo ,
2014-12-17 09:37:43 +01:00
0 ,
2010-07-23 11:20:24 +02:00
0 ,
exo_det ,
exo ,
2020-05-06 14:02:58 +02:00
other_endo ) ;
2010-07-23 11:20:24 +02:00
fbeginblock . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
2020-05-13 12:53:47 +02:00
temporary_terms_t temporary_terms_union ;
2022-05-20 11:43:02 +02:00
deriv_node_temp_terms_t tef_terms ;
compileTemporaryTerms ( code_file , instruction_number , true , false , temporary_terms_union , temporary_terms_idxs , tef_terms ) ;
2010-01-22 11:03:29 +01:00
2022-05-20 11:43:02 +02:00
compileModelEquations ( code_file , instruction_number , true , false , temporary_terms_union , temporary_terms_idxs , tef_terms ) ;
2010-01-22 11:03:29 +01:00
FENDEQU_ fendequ ;
2010-07-23 11:20:24 +02:00
fendequ . write ( code_file , instruction_number ) ;
2010-10-27 15:34:48 +02:00
// Get the current code_file position and jump if eval = true
streampos pos1 = code_file . tellp ( ) ;
FJMPIFEVAL_ fjmp_if_eval ( 0 ) ;
fjmp_if_eval . write ( code_file , instruction_number ) ;
int prev_instruction_number = instruction_number ;
2018-11-23 17:19:59 +01:00
vector < vector < tuple < int , int , int > > > my_derivatives ( symbol_table . endo_nbr ( ) ) ; ;
2010-01-22 11:03:29 +01:00
count_u = symbol_table . endo_nbr ( ) ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d1 ] : derivatives [ 1 ] )
2010-01-22 11:03:29 +01:00
{
2019-12-16 19:42:59 +01:00
int deriv_id = indices [ 1 ] ;
2018-07-17 18:34:07 +02:00
if ( getTypeByDerivID ( deriv_id ) = = SymbolType : : endogenous )
2010-01-22 11:03:29 +01:00
{
2020-03-24 18:26:06 +01:00
int eq = indices [ 0 ] ;
2010-01-22 11:03:29 +01:00
int symb = getSymbIDByDerivID ( deriv_id ) ;
2020-03-24 18:26:06 +01:00
int var = symbol_table . getTypeSpecificID ( symb ) ;
2010-01-22 11:03:29 +01:00
int lag = getLagByDerivID ( deriv_id ) ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstEndoDerivative , eq , var , lag ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2018-11-15 16:39:53 +01:00
if ( ! my_derivatives [ eq ] . size ( ) )
my_derivatives [ eq ] . clear ( ) ;
2018-11-23 17:19:59 +01:00
my_derivatives [ eq ] . emplace_back ( var , lag , count_u ) ;
2022-05-20 11:43:02 +02:00
d1 - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , true , false , tef_terms ) ;
2010-01-22 11:03:29 +01:00
FSTPU_ fstpu ( count_u ) ;
2010-07-23 11:20:24 +02:00
fstpu . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
count_u + + ;
}
}
for ( int i = 0 ; i < symbol_table . endo_nbr ( ) ; i + + )
{
FLDR_ fldr ( i ) ;
2010-07-23 11:20:24 +02:00
fldr . write ( code_file , instruction_number ) ;
2018-11-15 16:39:53 +01:00
if ( my_derivatives [ i ] . size ( ) )
2010-01-22 11:03:29 +01:00
{
2019-12-16 19:42:59 +01:00
for ( auto it = my_derivatives [ i ] . begin ( ) ; it ! = my_derivatives [ i ] . end ( ) ; + + it )
2010-01-22 11:03:29 +01:00
{
2018-11-23 17:19:59 +01:00
FLDU_ fldu ( get < 2 > ( * it ) ) ;
2010-11-20 15:52:51 +01:00
fldu . write ( code_file , instruction_number ) ;
2018-11-23 17:19:59 +01:00
FLDV_ fldv { static_cast < int > ( SymbolType : : endogenous ) , static_cast < unsigned int > ( get < 0 > ( * it ) ) , get < 1 > ( * it ) } ;
2010-11-20 15:52:51 +01:00
fldv . write ( code_file , instruction_number ) ;
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : times ) } ;
2010-07-23 11:20:24 +02:00
fbinary . write ( code_file , instruction_number ) ;
2018-11-15 16:39:53 +01:00
if ( it ! = my_derivatives [ i ] . begin ( ) )
2010-11-20 15:52:51 +01:00
{
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : plus ) } ;
2010-11-20 15:52:51 +01:00
fbinary . write ( code_file , instruction_number ) ;
}
2010-01-22 11:03:29 +01:00
}
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : minus ) } ;
2010-11-20 15:52:51 +01:00
fbinary . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
}
FSTPU_ fstpu ( i ) ;
2010-07-23 11:20:24 +02:00
fstpu . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
}
2010-10-27 15:34:48 +02:00
// Get the current code_file position and jump = true
streampos pos2 = code_file . tellp ( ) ;
FJMP_ fjmp ( 0 ) ;
fjmp . write ( code_file , instruction_number ) ;
// Set code_file position to previous JMPIFEVAL_ and set the number of instructions to jump
streampos pos3 = code_file . tellp ( ) ;
code_file . seekp ( pos1 ) ;
FJMPIFEVAL_ fjmp_if_eval1 ( instruction_number - prev_instruction_number ) ;
fjmp_if_eval1 . write ( code_file , instruction_number ) ;
code_file . seekp ( pos3 ) ;
2011-02-04 16:25:38 +01:00
prev_instruction_number = instruction_number ;
2010-10-27 15:34:48 +02:00
// The Jacobian
prev_var = - 1 ;
prev_lag = - 999999999 ;
count_col_endo = 0 ;
2018-11-23 17:19:59 +01:00
for ( const auto & it : first_derivatives_reordered_endo )
2010-10-27 15:34:48 +02:00
{
2020-03-24 18:26:06 +01:00
auto [ lag , var , eq ] = it . first ;
2018-11-23 17:19:59 +01:00
expr_t d1 = it . second ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstEndoDerivative , eq , var , lag ) ;
2010-10-27 15:34:48 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2011-02-04 16:25:38 +01:00
if ( prev_var ! = var | | prev_lag ! = lag )
2010-10-27 15:34:48 +02:00
{
prev_var = var ;
prev_lag = lag ;
count_col_endo + + ;
}
2022-05-20 11:43:02 +02:00
d1 - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , true , false , tef_terms ) ;
2010-10-27 15:34:48 +02:00
FSTPG3_ fstpg3 ( eq , var , lag , count_col_endo - 1 ) ;
fstpg3 . write ( code_file , instruction_number ) ;
}
prev_var = - 1 ;
prev_lag = - 999999999 ;
2010-11-20 15:52:51 +01:00
count_col_exo = 0 ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : first_derivatives_reordered_exo )
2010-10-27 15:34:48 +02:00
{
2020-03-24 18:26:06 +01:00
auto [ lag , ignore , var , eq ] = it . first ;
2018-11-23 17:19:59 +01:00
expr_t d1 = it . second ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstExoDerivative , eq , var , lag ) ;
2010-10-27 15:34:48 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2011-02-04 16:25:38 +01:00
if ( prev_var ! = var | | prev_lag ! = lag )
2010-10-27 15:34:48 +02:00
{
prev_var = var ;
prev_lag = lag ;
count_col_exo + + ;
}
2022-05-20 11:43:02 +02:00
d1 - > compile ( code_file , instruction_number , false , temporary_terms_union , temporary_terms_idxs , true , false , tef_terms ) ;
2010-10-27 15:34:48 +02:00
FSTPG3_ fstpg3 ( eq , var , lag , count_col_exo - 1 ) ;
fstpg3 . write ( code_file , instruction_number ) ;
}
// Set codefile position to previous JMP_ and set the number of instructions to jump
pos1 = code_file . tellp ( ) ;
code_file . seekp ( pos2 ) ;
FJMP_ fjmp1 ( instruction_number - prev_instruction_number ) ;
fjmp1 . write ( code_file , instruction_number ) ;
code_file . seekp ( pos1 ) ;
2010-01-22 11:03:29 +01:00
FENDBLOCK_ fendblock ;
2010-07-23 11:20:24 +02:00
fendblock . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
FEND_ fend ;
2010-07-23 11:20:24 +02:00
fend . write ( code_file , instruction_number ) ;
2010-01-22 11:03:29 +01:00
code_file . close ( ) ;
}
void
2021-01-25 18:03:37 +01:00
DynamicModel : : writeDynamicBlockBytecode ( const string & basename ) const
2009-12-16 18:13:23 +01:00
{
struct Uff_l
2009-04-14 16:39:53 +02:00
{
2009-12-16 18:13:23 +01:00
int u , var , lag ;
Uff_l * pNext ;
} ;
struct Uff
{
Uff_l * Ufl , * Ufl_First ;
} ;
int i , v ;
string tmp_s ;
ostringstream tmp_output ;
ofstream code_file ;
2010-07-23 11:20:24 +02:00
unsigned int instruction_number = 0 ;
2018-06-04 12:52:14 +02:00
expr_t lhs = nullptr , rhs = nullptr ;
2009-12-16 18:13:23 +01:00
BinaryOpNode * eq_node ;
Uff Uf [ symbol_table . endo_nbr ( ) ] ;
2010-09-16 19:18:45 +02:00
map < expr_t , int > reference_count ;
2009-12-16 18:13:23 +01:00
vector < int > feedback_variables ;
bool file_open = false ;
2021-01-25 18:03:37 +01:00
string main_name = basename + " /model/bytecode/dynamic.cod " ;
2018-06-27 15:12:12 +02:00
code_file . open ( main_name , ios : : out | ios : : binary | ios : : ate ) ;
2009-12-16 18:13:23 +01:00
if ( ! code_file . is_open ( ) )
{
2019-04-03 16:32:52 +02:00
cerr < < R " (Error : Can't open file " ) " << main_name << R " ( " for writing) " < < endl ;
2009-12-16 18:13:23 +01:00
exit ( EXIT_FAILURE ) ;
}
//Temporary variables declaration
2020-05-06 17:13:47 +02:00
FDIMT_ fdimt ( blocks_temporary_terms_idxs . size ( ) ) ;
2010-07-23 11:20:24 +02:00
fdimt . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
2020-04-23 16:04:02 +02:00
for ( int block = 0 ; block < static_cast < int > ( blocks . size ( ) ) ; block + + )
2009-12-16 18:13:23 +01:00
{
feedback_variables . clear ( ) ;
if ( block > 0 )
{
FENDBLOCK_ fendblock ;
2010-07-23 11:20:24 +02:00
fendblock . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
}
int count_u ;
int u_count_int = 0 ;
2020-04-23 16:04:02 +02:00
BlockSimulationType simulation_type = blocks [ block ] . simulation_type ;
int block_size = blocks [ block ] . size ;
int block_mfs = blocks [ block ] . mfs_size ;
int block_recursive = blocks [ block ] . getRecursiveSize ( ) ;
2020-04-30 11:15:55 +02:00
int block_max_lag = blocks [ block ] . max_lag ;
int block_max_lead = blocks [ block ] . max_lead ;
2009-12-16 18:13:23 +01:00
2020-03-20 17:31:14 +01:00
if ( simulation_type = = BlockSimulationType : : solveTwoBoundariesSimple
| | simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete
| | simulation_type = = BlockSimulationType : : solveBackwardComplete
| | simulation_type = = BlockSimulationType : : solveForwardComplete )
2009-12-16 18:13:23 +01:00
{
2020-05-19 17:43:35 +02:00
writeBlockBytecodeBinFile ( basename , block , u_count_int , file_open ,
2021-01-25 18:03:37 +01:00
simulation_type = = BlockSimulationType : : solveTwoBoundariesComplete | | simulation_type = = BlockSimulationType : : solveTwoBoundariesSimple ) ;
2009-12-16 18:13:23 +01:00
file_open = true ;
}
2017-06-01 19:58:32 +02:00
2009-12-16 18:13:23 +01:00
FBEGINBLOCK_ fbeginblock ( block_mfs ,
simulation_type ,
2020-04-23 16:04:02 +02:00
blocks [ block ] . first_equation ,
2009-12-16 18:13:23 +01:00
block_size ,
2020-04-17 14:55:55 +02:00
endo_idx_block2orig ,
eq_idx_block2orig ,
2020-04-21 18:10:46 +02:00
blocks [ block ] . linear ,
2009-12-16 18:13:23 +01:00
symbol_table . endo_nbr ( ) ,
block_max_lag ,
2014-12-17 09:37:43 +01:00
block_max_lead ,
2010-07-23 11:20:24 +02:00
u_count_int ,
2020-05-06 14:02:58 +02:00
blocks_jacob_cols_endo [ block ] . size ( ) ,
blocks_exo_det [ block ] . size ( ) ,
blocks_jacob_cols_exo_det [ block ] . size ( ) ,
blocks_exo [ block ] . size ( ) ,
blocks_jacob_cols_exo [ block ] . size ( ) ,
blocks_other_endo [ block ] . size ( ) ,
blocks_jacob_cols_other_endo [ block ] . size ( ) ,
vector < int > ( blocks_exo_det [ block ] . begin ( ) , blocks_exo_det [ block ] . end ( ) ) ,
vector < int > ( blocks_exo [ block ] . begin ( ) , blocks_exo [ block ] . end ( ) ) ,
vector < int > ( blocks_other_endo [ block ] . begin ( ) , blocks_other_endo [ block ] . end ( ) ) ) ;
2010-07-23 11:20:24 +02:00
fbeginblock . write ( code_file , instruction_number ) ;
2017-06-01 19:58:32 +02:00
2020-05-13 12:53:47 +02:00
temporary_terms_t temporary_terms_union ;
2009-04-14 16:39:53 +02:00
2020-05-06 17:13:47 +02:00
//The Temporary terms
deriv_node_temp_terms_t tef_terms ;
2020-05-13 16:58:19 +02:00
auto write_eq_tt = [ & ] ( int eq )
{
for ( auto it : blocks_temporary_terms [ block ] [ eq ] )
{
if ( dynamic_cast < AbstractExternalFunctionNode * > ( it ) )
it - > compileExternalFunctionOutput ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : TemporaryTerm , static_cast < int > ( blocks_temporary_terms_idxs . at ( it ) ) ) ;
2020-05-13 16:58:19 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
it - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
FSTPT_ fstpt ( static_cast < int > ( blocks_temporary_terms_idxs . at ( it ) ) ) ;
fstpt . write ( code_file , instruction_number ) ;
temporary_terms_union . insert ( it ) ;
2009-04-14 16:39:53 +02:00
# ifdef DEBUGC
2020-05-13 16:58:19 +02:00
cout < < " FSTPT " < < v < < endl ;
instruction_number + + ;
code_file . write ( & FOK , sizeof ( FOK ) ) ;
code_file . write ( reinterpret_cast < char * > ( & k ) , sizeof ( k ) ) ;
ki + + ;
2009-12-16 14:21:31 +01:00
# endif
2020-05-13 16:58:19 +02:00
}
} ;
2009-12-16 14:21:31 +01:00
2020-05-06 17:13:47 +02:00
// The equations
for ( i = 0 ; i < block_size ; i + + )
{
2021-01-25 18:03:37 +01:00
write_eq_tt ( i ) ;
2020-05-13 16:58:19 +02:00
2009-12-16 18:13:23 +01:00
int variable_ID , equation_ID ;
EquationType equ_type ;
2009-12-16 14:21:31 +01:00
2009-12-16 18:13:23 +01:00
switch ( simulation_type )
{
evaluation :
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : evaluateBackward :
case BlockSimulationType : : evaluateForward :
2009-12-16 18:13:23 +01:00
equ_type = getBlockEquationType ( block , i ) ;
2010-01-22 17:42:08 +01:00
{
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : ModelEquation , getBlockEquationID ( block , i ) ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2010-01-22 17:42:08 +01:00
}
2020-03-20 18:00:56 +01:00
if ( equ_type = = EquationType : : evaluate )
2009-12-16 18:13:23 +01:00
{
2020-05-07 15:20:11 +02:00
eq_node = getBlockEquationExpr ( block , i ) ;
2018-11-28 14:32:26 +01:00
lhs = eq_node - > arg1 ;
rhs = eq_node - > arg2 ;
2022-05-20 11:43:02 +02:00
rhs - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
lhs - > compile ( code_file , instruction_number , true , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2009-12-16 18:13:23 +01:00
}
2020-05-20 11:49:32 +02:00
else if ( equ_type = = EquationType : : evaluateRenormalized )
2009-12-16 18:13:23 +01:00
{
2020-05-07 15:20:11 +02:00
eq_node = getBlockEquationRenormalizedExpr ( block , i ) ;
2018-11-28 14:32:26 +01:00
lhs = eq_node - > arg1 ;
rhs = eq_node - > arg2 ;
2022-05-20 11:43:02 +02:00
rhs - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
lhs - > compile ( code_file , instruction_number , true , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2009-12-16 18:13:23 +01:00
}
break ;
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : solveBackwardComplete :
case BlockSimulationType : : solveForwardComplete :
case BlockSimulationType : : solveTwoBoundariesComplete :
case BlockSimulationType : : solveTwoBoundariesSimple :
2020-03-24 18:26:06 +01:00
if ( i < block_recursive )
2009-12-16 18:13:23 +01:00
goto evaluation ;
variable_ID = getBlockVariableID ( block , i ) ;
equation_ID = getBlockEquationID ( block , i ) ;
feedback_variables . push_back ( variable_ID ) ;
2018-06-04 12:52:14 +02:00
Uf [ equation_ID ] . Ufl = nullptr ;
2009-12-16 18:13:23 +01:00
goto end ;
default :
end :
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : ModelEquation , getBlockEquationID ( block , i ) ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2020-05-07 15:20:11 +02:00
eq_node = getBlockEquationExpr ( block , i ) ;
2018-11-28 14:32:26 +01:00
lhs = eq_node - > arg1 ;
rhs = eq_node - > arg2 ;
2022-05-20 11:43:02 +02:00
lhs - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
rhs - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2009-12-16 18:13:23 +01:00
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : minus ) } ;
2010-07-23 11:20:24 +02:00
fbinary . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
FSTPR_ fstpr ( i - block_recursive ) ;
2010-07-23 11:20:24 +02:00
fstpr . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
}
}
FENDEQU_ fendequ ;
2010-07-23 11:20:24 +02:00
fendequ . write ( code_file , instruction_number ) ;
2022-02-18 12:37:37 +01:00
/* If the block is not of type “evaluate backward/forward”, then we write
the temporary terms for derivatives at this point , i . e . before the
JMPIFEVAL , because they will be needed in both “ simulate ” and
“ evaluate ” modes . */
if ( simulation_type ! = BlockSimulationType : : evaluateBackward
& & simulation_type ! = BlockSimulationType : : evaluateForward )
write_eq_tt ( blocks [ block ] . size ) ;
2010-07-23 11:20:24 +02:00
// Get the current code_file position and jump if eval = true
streampos pos1 = code_file . tellp ( ) ;
FJMPIFEVAL_ fjmp_if_eval ( 0 ) ;
fjmp_if_eval . write ( code_file , instruction_number ) ;
int prev_instruction_number = instruction_number ;
2022-02-18 12:37:37 +01:00
/* Write the derivatives for the “simulate” mode (not needed if the block
is of type “ evaluate backward / forward ” ) */
2020-03-20 17:31:14 +01:00
if ( simulation_type ! = BlockSimulationType : : evaluateBackward
& & simulation_type ! = BlockSimulationType : : evaluateForward )
2009-12-16 18:13:23 +01:00
{
switch ( simulation_type )
{
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : solveBackwardSimple :
case BlockSimulationType : : solveForwardSimple :
2010-01-22 17:42:08 +01:00
{
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstEndoDerivative , getBlockEquationID ( block , 0 ) , getBlockVariableID ( block , 0 ) , 0 ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2010-01-22 17:42:08 +01:00
}
2022-05-20 11:43:02 +02:00
compileDerivative ( code_file , instruction_number , getBlockEquationID ( block , 0 ) , getBlockVariableID ( block , 0 ) , 0 , temporary_terms_union , blocks_temporary_terms_idxs , tef_terms ) ;
2009-06-05 16:45:23 +02:00
{
2009-12-16 18:13:23 +01:00
FSTPG_ fstpg ( 0 ) ;
2010-07-23 11:20:24 +02:00
fstpg . write ( code_file , instruction_number ) ;
2009-06-05 16:45:23 +02:00
}
2009-12-16 18:13:23 +01:00
break ;
2020-03-20 17:31:14 +01:00
case BlockSimulationType : : solveBackwardComplete :
case BlockSimulationType : : solveForwardComplete :
case BlockSimulationType : : solveTwoBoundariesComplete :
case BlockSimulationType : : solveTwoBoundariesSimple :
2009-12-16 18:13:23 +01:00
count_u = feedback_variables . size ( ) ;
2020-04-24 12:29:02 +02:00
for ( const auto & [ indices , ignore ] : blocks_derivatives [ block ] )
2009-12-16 18:13:23 +01:00
{
2020-04-24 12:29:02 +02:00
auto [ eq , var , lag ] = indices ;
2020-03-24 18:26:06 +01:00
int eqr = getBlockEquationID ( block , eq ) ;
int varr = getBlockVariableID ( block , var ) ;
2010-07-23 11:20:24 +02:00
if ( eq > = block_recursive and var > = block_recursive )
2009-12-16 18:13:23 +01:00
{
2020-03-20 17:31:14 +01:00
if ( lag ! = 0
& & ( simulation_type = = BlockSimulationType : : solveForwardComplete
| | simulation_type = = BlockSimulationType : : solveBackwardComplete ) )
2010-08-18 13:45:07 +02:00
continue ;
2009-12-16 18:13:23 +01:00
if ( ! Uf [ eqr ] . Ufl )
{
2019-04-23 11:07:32 +02:00
Uf [ eqr ] . Ufl = static_cast < Uff_l * > ( malloc ( sizeof ( Uff_l ) ) ) ;
2009-12-16 18:13:23 +01:00
Uf [ eqr ] . Ufl_First = Uf [ eqr ] . Ufl ;
}
else
{
2019-04-23 11:07:32 +02:00
Uf [ eqr ] . Ufl - > pNext = static_cast < Uff_l * > ( malloc ( sizeof ( Uff_l ) ) ) ;
2009-12-16 18:13:23 +01:00
Uf [ eqr ] . Ufl = Uf [ eqr ] . Ufl - > pNext ;
}
2018-06-04 12:52:14 +02:00
Uf [ eqr ] . Ufl - > pNext = nullptr ;
2009-12-16 18:13:23 +01:00
Uf [ eqr ] . Ufl - > u = count_u ;
Uf [ eqr ] . Ufl - > var = varr ;
Uf [ eqr ] . Ufl - > lag = lag ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstEndoDerivative , eqr , varr , lag ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2022-05-20 11:43:02 +02:00
compileChainRuleDerivative ( code_file , instruction_number , block , eq , var , lag , temporary_terms_union , blocks_temporary_terms_idxs , tef_terms ) ;
2009-12-16 18:13:23 +01:00
FSTPU_ fstpu ( count_u ) ;
2010-07-23 11:20:24 +02:00
fstpu . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
count_u + + ;
}
}
2020-03-24 18:26:06 +01:00
for ( i = 0 ; i < block_size ; i + + )
2009-12-16 18:13:23 +01:00
{
2020-03-24 18:26:06 +01:00
if ( i > = block_recursive )
2009-12-16 18:13:23 +01:00
{
FLDR_ fldr ( i - block_recursive ) ;
2010-07-23 11:20:24 +02:00
fldr . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
FLDZ_ fldz ;
2010-07-23 11:20:24 +02:00
fldz . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
v = getBlockEquationID ( block , i ) ;
for ( Uf [ v ] . Ufl = Uf [ v ] . Ufl_First ; Uf [ v ] . Ufl ; Uf [ v ] . Ufl = Uf [ v ] . Ufl - > pNext )
{
FLDU_ fldu ( Uf [ v ] . Ufl - > u ) ;
2010-07-23 11:20:24 +02:00
fldu . write ( code_file , instruction_number ) ;
2018-07-17 18:34:07 +02:00
FLDV_ fldv { static_cast < int > ( SymbolType : : endogenous ) , static_cast < unsigned int > ( Uf [ v ] . Ufl - > var ) , Uf [ v ] . Ufl - > lag } ;
2010-07-23 11:20:24 +02:00
fldv . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : times ) } ;
2010-07-23 11:20:24 +02:00
fbinary . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
FCUML_ fcuml ;
2010-07-23 11:20:24 +02:00
fcuml . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
}
Uf [ v ] . Ufl = Uf [ v ] . Ufl_First ;
while ( Uf [ v ] . Ufl )
{
Uf [ v ] . Ufl_First = Uf [ v ] . Ufl - > pNext ;
free ( Uf [ v ] . Ufl ) ;
Uf [ v ] . Ufl = Uf [ v ] . Ufl_First ;
}
2018-07-18 16:18:26 +02:00
FBINARY_ fbinary { static_cast < int > ( BinaryOpcode : : minus ) } ;
2010-07-23 11:20:24 +02:00
fbinary . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
FSTPU_ fstpu ( i - block_recursive ) ;
2010-07-23 11:20:24 +02:00
fstpu . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
}
}
break ;
default :
break ;
}
}
2022-02-18 12:37:37 +01:00
2010-07-23 11:20:24 +02:00
// Get the current code_file position and jump = true
streampos pos2 = code_file . tellp ( ) ;
FJMP_ fjmp ( 0 ) ;
fjmp . write ( code_file , instruction_number ) ;
// Set code_file position to previous JMPIFEVAL_ and set the number of instructions to jump
streampos pos3 = code_file . tellp ( ) ;
code_file . seekp ( pos1 ) ;
FJMPIFEVAL_ fjmp_if_eval1 ( instruction_number - prev_instruction_number ) ;
fjmp_if_eval1 . write ( code_file , instruction_number ) ;
code_file . seekp ( pos3 ) ;
2011-02-04 16:25:38 +01:00
prev_instruction_number = instruction_number ;
2010-07-23 11:20:24 +02:00
2022-02-18 12:37:37 +01:00
/* If the block is of type “evaluate backward/forward”, then write the
temporary terms for derivatives at this point , because they have not
been written before the JMPIFEVAL . */
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
write_eq_tt ( blocks [ block ] . size ) ;
// Write the derivatives for the “evaluate” mode
2020-05-06 14:02:58 +02:00
for ( const auto & [ indices , d ] : blocks_derivatives [ block ] )
2010-07-23 11:20:24 +02:00
{
2020-05-06 14:02:58 +02:00
auto [ eq , var , lag ] = indices ;
2020-03-24 18:26:06 +01:00
int eqr = getBlockEquationID ( block , eq ) ;
int varr = getBlockVariableID ( block , var ) ;
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstEndoDerivative , eqr , varr , lag ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2022-05-20 11:43:02 +02:00
compileDerivative ( code_file , instruction_number , eqr , varr , lag , temporary_terms_union , blocks_temporary_terms_idxs , tef_terms ) ;
2020-05-06 14:02:58 +02:00
FSTPG3_ fstpg3 ( eq , var , lag , blocks_jacob_cols_endo [ block ] . at ( { var , lag } ) ) ;
2010-07-23 11:20:24 +02:00
fstpg3 . write ( code_file , instruction_number ) ;
}
2020-05-06 14:02:58 +02:00
for ( const auto & [ indices , d ] : blocks_derivatives_exo [ block ] )
2010-07-23 11:20:24 +02:00
{
2020-05-06 14:02:58 +02:00
auto [ eqr , var , lag ] = indices ;
2020-04-30 16:00:16 +02:00
int eq = getBlockEquationID ( block , eqr ) ;
2020-05-05 17:15:08 +02:00
int varr = 0 ; // Dummy value, actually unused by the bytecode MEX
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstExoDerivative , eqr , varr , lag ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2022-05-20 11:43:02 +02:00
d - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2020-05-06 14:02:58 +02:00
FSTPG3_ fstpg3 ( eq , var , lag , blocks_jacob_cols_exo [ block ] . at ( { var , lag } ) ) ;
2010-07-23 11:20:24 +02:00
fstpg3 . write ( code_file , instruction_number ) ;
}
2020-05-06 14:02:58 +02:00
for ( const auto & [ indices , d ] : blocks_derivatives_exo_det [ block ] )
2010-07-23 11:20:24 +02:00
{
2020-05-06 14:02:58 +02:00
auto [ eqr , var , lag ] = indices ;
2020-04-30 16:00:16 +02:00
int eq = getBlockEquationID ( block , eqr ) ;
2020-05-05 17:15:08 +02:00
int varr = 0 ; // Dummy value, actually unused by the bytecode MEX
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstExodetDerivative , eqr , varr , lag ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2022-05-20 11:43:02 +02:00
d - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2020-05-06 14:02:58 +02:00
FSTPG3_ fstpg3 ( eq , var , lag , blocks_jacob_cols_exo_det [ block ] . at ( { var , lag } ) ) ;
2010-07-23 11:20:24 +02:00
fstpg3 . write ( code_file , instruction_number ) ;
}
2020-05-06 14:02:58 +02:00
for ( const auto & [ indices , d ] : blocks_derivatives_other_endo [ block ] )
2010-07-23 11:20:24 +02:00
{
2020-05-06 14:02:58 +02:00
auto [ eqr , var , lag ] = indices ;
2020-04-30 16:00:16 +02:00
int eq = getBlockEquationID ( block , eqr ) ;
2020-05-05 17:15:08 +02:00
int varr = 0 ; // Dummy value, actually unused by the bytecode MEX
2021-02-01 11:10:59 +01:00
FNUMEXPR_ fnumexpr ( ExpressionType : : FirstOtherEndoDerivative , eqr , varr , lag ) ;
2010-07-23 11:20:24 +02:00
fnumexpr . write ( code_file , instruction_number ) ;
2022-05-20 11:43:02 +02:00
d - > compile ( code_file , instruction_number , false , temporary_terms_union , blocks_temporary_terms_idxs , true , false , tef_terms ) ;
2020-05-06 14:02:58 +02:00
FSTPG3_ fstpg3 ( eq , var , lag , blocks_jacob_cols_other_endo [ block ] . at ( { var , lag } ) ) ;
2010-07-23 11:20:24 +02:00
fstpg3 . write ( code_file , instruction_number ) ;
}
// Set codefile position to previous JMP_ and set the number of instructions to jump
pos1 = code_file . tellp ( ) ;
code_file . seekp ( pos2 ) ;
FJMP_ fjmp1 ( instruction_number - prev_instruction_number ) ;
fjmp1 . write ( code_file , instruction_number ) ;
code_file . seekp ( pos1 ) ;
2009-12-16 18:13:23 +01:00
}
FENDBLOCK_ fendblock ;
2010-07-23 11:20:24 +02:00
fendblock . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
FEND_ fend ;
2010-07-23 11:20:24 +02:00
fend . write ( code_file , instruction_number ) ;
2009-12-16 18:13:23 +01:00
code_file . close ( ) ;
}
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
{
2018-06-27 15:01:31 +02:00
writeDynamicModel ( basename , false , false ) ;
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
2015-07-27 17:02:51 +02:00
void
DynamicModel : : writeDynamicJuliaFile ( const string & basename ) const
{
2018-03-27 17:14:30 +02:00
writeDynamicModel ( basename , false , true ) ;
2015-07-27 17:02:51 +02:00
}
2009-04-14 16:39:53 +02:00
void
2020-01-20 17:22:32 +01:00
DynamicModel : : writeDynamicCFile ( const string & basename ) const
2009-12-16 18:13:23 +01:00
{
2018-06-27 15:01:31 +02:00
string filename = basename + " /model/src/dynamic.c " ;
2009-12-16 18:13:23 +01:00
2018-11-15 16:39:53 +01:00
int ntt = temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) + temporary_terms_derivatives [ 2 ] . size ( ) + temporary_terms_derivatives [ 3 ] . size ( ) ;
2018-09-25 19:15:22 +02:00
2020-05-29 16:12:01 +02:00
ofstream output ;
output . open ( filename , ios : : out | ios : : binary ) ;
if ( ! output . is_open ( ) )
2009-12-16 18:13:23 +01:00
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2020-05-29 16:12:01 +02:00
output < < " /* " < < endl
< < " * " < < filename < < " : Computes dynamic model for Dynare " < < endl
< < " * " < < endl
< < " * Warning : this file is generated automatically by Dynare " < < endl
< < " * from model file (.mod) " < < endl
< < " */ " < < endl
< < endl
< < " #include <math.h> " < < endl
< < " #include <stdlib.h> " < < endl
< < R " (#include " mex . h " ) " < < endl
< < endl ;
2009-12-16 18:13:23 +01:00
2018-07-18 16:18:26 +02:00
// Write function definition if BinaryOpcode::powerDeriv is used
2020-05-29 16:12:01 +02:00
writePowerDeriv ( output ) ;
2018-09-25 19:15:22 +02:00
2020-05-29 16:12:01 +02:00
output < < endl ;
2009-12-16 18:13:23 +01:00
2020-05-29 16:12:01 +02:00
writeDynamicModel ( output , true , false ) ;
2018-09-25 19:15:22 +02:00
2020-05-29 16:12:01 +02:00
output < < " void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) " < < endl
< < " { " < < endl
2020-06-23 16:30:21 +02:00
< < " if (nlhs > " < < min ( computed_derivs_order + 1 , 4 ) < < " ) " < < endl
2020-05-29 16:12:01 +02:00
< < R " ( mexErrMsgTxt( " Derivatives of higher order than computed have been requested " );) " < < endl
2020-06-23 16:30:21 +02:00
< < " if (nrhs != 5) " < < endl
< < R " ( mexErrMsgTxt( " Requires exactly 5 input arguments " );) " < < endl
2020-05-29 16:12:01 +02:00
< < endl
< < " double *y = mxGetPr(prhs[0]); " < < endl
< < " double *x = mxGetPr(prhs[1]); " < < endl
< < " double *params = mxGetPr(prhs[2]); " < < endl
< < " double *steady_state = mxGetPr(prhs[3]); " < < endl
< < " int it_ = (int) mxGetScalar(prhs[4]) - 1; " < < endl
< < " int nb_row_x = mxGetM(prhs[1]); " < < endl
< < endl
< < " double *T = (double *) malloc(sizeof(double)* " < < ntt < < " ); " < < endl
< < endl
< < " if (nlhs >= 1) " < < endl
< < " { " < < endl
< < " plhs[0] = mxCreateDoubleMatrix( " < < equations . size ( ) < < " ,1, mxREAL); " < < endl
< < " double *residual = mxGetPr(plhs[0]); " < < endl
< < " dynamic_resid_tt(y, x, nb_row_x, params, steady_state, it_, T); " < < endl
< < " dynamic_resid(y, x, nb_row_x, params, steady_state, it_, T, residual); " < < endl
< < " } " < < endl
< < endl
< < " if (nlhs >= 2) " < < endl
< < " { " < < endl
< < " plhs[1] = mxCreateDoubleMatrix( " < < equations . size ( ) < < " , " < < dynJacobianColsNbr < < " , mxREAL); " < < endl
< < " double *g1 = mxGetPr(plhs[1]); " < < endl
< < " dynamic_g1_tt(y, x, nb_row_x, params, steady_state, it_, T); " < < endl
< < " dynamic_g1(y, x, nb_row_x, params, steady_state, it_, T, g1); " < < endl
< < " } " < < endl
< < endl
< < " if (nlhs >= 3) " < < endl
< < " { " < < endl
2020-06-23 17:50:50 +02:00
< < " mxArray *g2_i = mxCreateDoubleMatrix( " < < NNZDerivatives [ 2 ] < < " , " < < 1 < < " , mxREAL); " < < endl
< < " mxArray *g2_j = mxCreateDoubleMatrix( " < < NNZDerivatives [ 2 ] < < " , " < < 1 < < " , mxREAL); " < < endl
< < " mxArray *g2_v = mxCreateDoubleMatrix( " < < NNZDerivatives [ 2 ] < < " , " < < 1 < < " , mxREAL); " < < endl
2020-05-29 16:12:01 +02:00
< < " dynamic_g2_tt(y, x, nb_row_x, params, steady_state, it_, T); " < < endl
2020-06-23 17:50:50 +02:00
< < " dynamic_g2(y, x, nb_row_x, params, steady_state, it_, T, mxGetPr(g2_i), mxGetPr(g2_j), mxGetPr(g2_v)); " < < endl
< < " mxArray *m = mxCreateDoubleScalar( " < < equations . size ( ) < < " ); " < < endl
< < " mxArray *n = mxCreateDoubleScalar( " < < dynJacobianColsNbr * dynJacobianColsNbr < < " ); " < < endl
< < " mxArray *plhs_sparse[1], *prhs_sparse[5] = { g2_i, g2_j, g2_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs_sparse, 5, prhs_sparse, " sparse " );) " < < endl
< < " plhs[2] = plhs_sparse[0]; " < < endl
< < " mxDestroyArray(g2_i); " < < endl
< < " mxDestroyArray(g2_j); " < < endl
< < " mxDestroyArray(g2_v); " < < endl
< < " mxDestroyArray(m); " < < endl
< < " mxDestroyArray(n); " < < endl
2020-05-29 16:12:01 +02:00
< < " } " < < endl
< < endl
< < " if (nlhs >= 4) " < < endl
< < " { " < < endl
2020-06-23 17:50:50 +02:00
< < " mxArray *g3_i = mxCreateDoubleMatrix( " < < NNZDerivatives [ 3 ] < < " , " < < 1 < < " , mxREAL); " < < endl
< < " mxArray *g3_j = mxCreateDoubleMatrix( " < < NNZDerivatives [ 3 ] < < " , " < < 1 < < " , mxREAL); " < < endl
< < " mxArray *g3_v = mxCreateDoubleMatrix( " < < NNZDerivatives [ 3 ] < < " , " < < 1 < < " , mxREAL); " < < endl
2020-05-29 16:12:01 +02:00
< < " dynamic_g3_tt(y, x, nb_row_x, params, steady_state, it_, T); " < < endl
2020-06-23 17:50:50 +02:00
< < " dynamic_g3(y, x, nb_row_x, params, steady_state, it_, T, mxGetPr(g3_i), mxGetPr(g3_j), mxGetPr(g3_v)); " < < endl
< < " mxArray *m = mxCreateDoubleScalar( " < < equations . size ( ) < < " ); " < < endl
< < " mxArray *n = mxCreateDoubleScalar( " < < dynJacobianColsNbr * dynJacobianColsNbr * dynJacobianColsNbr < < " ); " < < endl
< < " mxArray *plhs_sparse[1], *prhs_sparse[5] = { g3_i, g3_j, g3_v, m, n }; " < < endl
< < R " ( mexCallMATLAB(1, plhs_sparse, 5, prhs_sparse, " sparse " );) " < < endl
< < " plhs[3] = plhs_sparse[0]; " < < endl
< < " mxDestroyArray(g3_i); " < < endl
< < " mxDestroyArray(g3_j); " < < endl
< < " mxDestroyArray(g3_v); " < < endl
< < " mxDestroyArray(m); " < < endl
< < " mxDestroyArray(n); " < < endl
2020-05-29 16:12:01 +02:00
< < " } " < < endl
< < endl
2020-06-23 16:30:21 +02:00
< < " free(T); " < < endl
2020-05-29 16:12:01 +02:00
< < " } " < < endl ;
2011-12-22 14:55:57 +01:00
2020-05-29 16:12:01 +02:00
output . close ( ) ;
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 < < " [ " ;
2018-06-04 15:03:26 +02:00
for ( auto it = nonzero_hessian_eqs . begin ( ) ;
2019-12-16 19:42:59 +01:00
it ! = nonzero_hessian_eqs . end ( ) ; + + it )
2018-01-11 12:55:36 +01:00
{
if ( it ! = nonzero_hessian_eqs . begin ( ) )
output < < " " ;
2019-12-13 22:31:49 +01:00
output < < * it + 1 ;
2018-01-11 12:55:36 +01:00
}
if ( nonzero_hessian_eqs . size ( ) ! = 1 )
output < < " ] " ;
}
2009-04-14 16:39:53 +02:00
void
2020-05-19 17:43:35 +02:00
DynamicModel : : writeBlockBytecodeBinFile ( const string & basename , int num , int & u_count_int ,
2021-01-25 18:03:37 +01:00
bool & file_open , bool is_two_boundaries ) const
2009-12-16 18:13:23 +01:00
{
int j ;
std : : ofstream SaveCode ;
2021-01-25 18:03:37 +01:00
string filename = basename + " /model/bytecode/dynamic.bin " ;
2018-09-21 17:13:19 +02:00
2009-12-16 18:13:23 +01:00
if ( file_open )
2018-06-27 15:01:31 +02:00
SaveCode . open ( filename , ios : : out | ios : : in | ios : : binary | ios : : ate ) ;
2009-12-16 18:13:23 +01:00
else
2018-06-27 15:01:31 +02:00
SaveCode . open ( filename , ios : : out | ios : : binary ) ;
2009-12-16 18:13:23 +01:00
if ( ! SaveCode . is_open ( ) )
{
2019-04-03 16:32:52 +02:00
cerr < < R " (Error : Can't open file " ) " << filename << R " ( " for writing) " < < endl ;
2009-12-16 18:13:23 +01:00
exit ( EXIT_FAILURE ) ;
}
u_count_int = 0 ;
2020-04-23 16:04:02 +02:00
int block_size = blocks [ num ] . size ;
int block_mfs = blocks [ num ] . mfs_size ;
int block_recursive = blocks [ num ] . getRecursiveSize ( ) ;
2020-04-24 12:29:02 +02:00
for ( const auto & [ indices , ignore ] : blocks_derivatives [ num ] )
2009-12-16 18:13:23 +01:00
{
2020-04-24 12:29:02 +02:00
auto [ eq , var , lag ] = indices ;
2010-08-18 13:45:07 +02:00
if ( lag ! = 0 & & ! is_two_boundaries )
continue ;
2010-04-28 16:03:32 +02:00
if ( eq > = block_recursive & & var > = block_recursive )
2009-12-16 18:13:23 +01:00
{
int v = eq - block_recursive ;
SaveCode . write ( reinterpret_cast < char * > ( & v ) , sizeof ( v ) ) ;
int varr = var - block_recursive + lag * block_mfs ;
SaveCode . write ( reinterpret_cast < char * > ( & varr ) , sizeof ( varr ) ) ;
2020-03-24 18:26:06 +01:00
SaveCode . write ( reinterpret_cast < const char * > ( & lag ) , sizeof ( lag ) ) ;
2009-12-16 18:13:23 +01:00
int u = u_count_int + block_mfs ;
SaveCode . write ( reinterpret_cast < char * > ( & u ) , sizeof ( u ) ) ;
u_count_int + + ;
}
}
if ( is_two_boundaries )
u_count_int + = block_mfs ;
2020-03-24 18:26:06 +01:00
for ( j = block_recursive ; j < block_size ; j + + )
2009-12-16 18:13:23 +01:00
{
2020-03-24 18:26:06 +01:00
int varr = getBlockVariableID ( num , j ) ;
2009-12-16 18:13:23 +01:00
SaveCode . write ( reinterpret_cast < char * > ( & varr ) , sizeof ( varr ) ) ;
}
2020-03-24 18:26:06 +01:00
for ( j = block_recursive ; j < block_size ; j + + )
2009-12-16 18:13:23 +01:00
{
2020-03-24 18:26:06 +01:00
int eqr = getBlockEquationID ( num , j ) ;
2009-12-16 18:13:23 +01:00
SaveCode . write ( reinterpret_cast < char * > ( & eqr ) , sizeof ( eqr ) ) ;
}
SaveCode . close ( ) ;
}
2009-04-14 16:39:53 +02:00
void
2020-05-19 16:56:53 +02:00
DynamicModel : : writeDynamicBlockMFile ( const string & basename ) const
2009-12-16 18:13:23 +01:00
{
2020-06-19 18:33:53 +02:00
ofstream output ;
2018-06-27 15:01:31 +02:00
string filename = packageDir ( basename ) + " /dynamic.m " ;
2020-06-19 18:33:53 +02:00
output . open ( filename , ios : : out | ios : : binary ) ;
if ( ! output . is_open ( ) )
2009-12-16 18:13:23 +01:00
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2020-06-19 18:33:53 +02:00
output < < " function [residual, y, T, g1, varargout] = dynamic(nblock, y, x, params, steady_state, T, it_, stochastic_mode) " < < endl
< < " switch nblock " < < endl ;
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
{
output < < " case " < < blk + 1 < < endl ;
BlockSimulationType simulation_type = blocks [ blk ] . simulation_type ;
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
output < < " [y, T, g1, varargout{1:nargout-4}] = " < < basename < < " .block.dynamic_ " < < blk + 1 < < " (y, x, params, steady_state, T, it_, stochastic_mode); " < < endl
< < " residual = []; " < < endl ;
else
2020-10-06 17:16:50 +02:00
output < < " [residual, y, T, g1, varargout{1:nargout-4}] = " < < basename < < " .block.dynamic_ " < < blk + 1 < < " (y, x, params, steady_state, T, it_, stochastic_mode); " < < endl ;
2020-06-19 18:33:53 +02:00
}
output < < " end " < < endl
< < " end " < < endl ;
output . close ( ) ;
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
2020-06-23 15:13:04 +02:00
void
DynamicModel : : writeDynamicBlockCFile ( const string & basename ) const
{
string filename = basename + " /model/src/dynamic.c " ;
ofstream output ;
output . open ( filename , ios : : out | ios : : binary ) ;
if ( ! output . is_open ( ) )
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " #include <math.h> " < < endl
< < R " (#include " mex . h " ) " < < endl ;
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
output < < R " (#include " dynamic_ ) " << blk+1 << R " ( . h " ) " < < endl ;
output < < endl ;
writePowerDeriv ( output ) ;
output < < endl
< < " void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) " < < endl
< < " { " < < endl
< < " if (nrhs != 8) " < < endl
< < R " ( mexErrMsgTxt( " Requires exactly 8 input arguments " );) " < < endl
< < " if (nlhs > 7) " < < endl
< < R " ( mexErrMsgTxt( " Accepts at most 7 output arguments " );) " < < endl
< < " int nblock = (int) mxGetScalar(prhs[0]); " < < endl
< < " const mxArray *y = prhs[1], *x = prhs[2], *params = prhs[3], *steady_state = prhs[4], *T = prhs[5], *it_ = prhs[6], *stochastic_mode = prhs[7]; " < < endl
< < " mxArray *T_new = mxDuplicateArray(T); " < < endl
< < " mxArray *y_new = mxDuplicateArray(y); " < < endl
< < " mxArray *residual, *g1, *g1_x, *g1_xd, *g1_o; " < < endl
< < " switch (nblock) " < < endl
< < " { " < < endl ;
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
{
output < < " case " < < blk + 1 < < ' : ' < < endl ;
BlockSimulationType simulation_type = blocks [ blk ] . simulation_type ;
if ( simulation_type = = BlockSimulationType : : evaluateBackward
| | simulation_type = = BlockSimulationType : : evaluateForward )
output < < " dynamic_ " < < blk + 1 < < " _mx(y_new, x, params, steady_state, T_new, it_, stochastic_mode, &g1, &g1_x, &g1_xd, &g1_o); " < < endl
< < " residual = mxCreateDoubleMatrix(0,0,mxREAL); " < < endl ;
else
2020-10-06 17:16:50 +02:00
output < < " dynamic_ " < < blk + 1 < < " _mx(y_new, x, params, steady_state, T_new, it_, stochastic_mode, &residual, &g1, &g1_x, &g1_xd, &g1_o); " < < endl ;
2020-06-23 15:13:04 +02:00
output < < " break; " < < endl ;
}
output < < " } " < < endl
< < endl
< < " if (nlhs >= 1) " < < endl
< < " plhs[0] = residual; " < < endl
< < " else " < < endl
< < " mxDestroyArray(residual); " < < endl
< < " if (nlhs >= 2) " < < endl
< < " plhs[1] = y_new; " < < endl
< < " else " < < endl
< < " mxDestroyArray(y_new); " < < endl
< < " if (nlhs >= 3) " < < endl
< < " plhs[2] = T_new; " < < endl
< < " else " < < endl
< < " mxDestroyArray(T_new); " < < endl
< < " if (nlhs >= 4) " < < endl
< < " plhs[3] = g1; " < < endl
< < " else " < < endl
< < " mxDestroyArray(g1); " < < endl
< < " if (nlhs >= 5) " < < endl
< < " plhs[4] = g1_x; " < < endl
< < " else " < < endl
< < " mxDestroyArray(g1_x); " < < endl
< < " if (nlhs >= 6) " < < endl
< < " plhs[5] = g1_xd; " < < endl
< < " else " < < endl
< < " mxDestroyArray(g1_xd); " < < endl
< < " if (nlhs >= 7) " < < endl
< < " plhs[6] = g1_o; " < < endl
< < " else " < < endl
< < " mxDestroyArray(g1_o); " < < endl
< < " } " < < endl ;
output . close ( ) ;
}
2018-03-27 17:14:30 +02:00
void
DynamicModel : : writeWrapperFunctions ( const string & basename , const string & ending ) const
{
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
2018-06-27 15:01:31 +02:00
string filename = packageDir ( basename ) + " / " + name + " .m " ;
2018-03-27 17:14:30 +02:00
ofstream output ;
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 ( ) )
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
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
2018-06-27 15:01:31 +02:00
DynamicModel : : writeDynamicModelHelper ( const string & basename ,
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 ,
const ostringstream & init_s ,
const ostringstream & end_s ,
const ostringstream & s , const ostringstream & s_tt ) const
{
2018-06-27 15:01:31 +02:00
string filename = packageDir ( basename ) + " / " + name_tt + " .m " ;
2018-03-27 17:14:30 +02:00
ofstream output ;
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 ( ) )
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
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 ( ) ;
2018-06-27 15:01:31 +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 ( ) )
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
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
2018-06-27 15:01:31 +02:00
DynamicModel : : writeDynamicMatlabCompatLayer ( const string & basename ) const
2018-05-23 16:10:26 +02:00
{
2018-06-27 15:01:31 +02:00
string filename = packageDir ( basename ) + " /dynamic.m " ;
2018-05-23 16:10:26 +02:00
ofstream output ;
2018-06-27 15:12:12 +02:00
output . open ( filename , ios : : out | ios : : binary ) ;
2018-05-23 16:10:26 +02:00
if ( ! output . is_open ( ) )
{
cerr < < " Error: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2018-11-15 16:39:53 +01:00
int ntt = temporary_terms_mlv . size ( ) + 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 ( ) ;
}
2009-04-14 16:39:53 +02:00
void
2015-07-27 17:02:51 +02:00
DynamicModel : : writeDynamicModel ( ostream & DynamicOutput , bool use_dll , bool julia ) const
2009-12-16 18:13:23 +01:00
{
2018-03-27 17:14:30 +02:00
writeDynamicModel ( " " , DynamicOutput , use_dll , julia ) ;
}
void
2018-06-27 15:01:31 +02:00
DynamicModel : : writeDynamicModel ( const string & basename , bool use_dll , bool julia ) const
2018-03-27 17:14:30 +02:00
{
ofstream DynamicOutput ;
2018-06-27 15:01:31 +02:00
writeDynamicModel ( basename , DynamicOutput , use_dll , julia ) ;
2018-03-27 17:14:30 +02:00
}
void
2018-06-27 15:01:31 +02:00
DynamicModel : : writeDynamicModel ( const string & basename , ostream & DynamicOutput , bool use_dll , bool julia ) const
2018-03-27 17:14:30 +02:00
{
2019-12-20 16:59:30 +01:00
vector < ostringstream > d_output ( derivatives . size ( ) ) ; // Derivatives output (at all orders, including 0=residual)
2019-04-12 15:41:52 +02:00
vector < ostringstream > tt_output ( derivatives . size ( ) ) ; // Temp terms output (at all orders)
2009-12-16 18:13:23 +01:00
2018-09-05 18:27:13 +02:00
ExprNodeOutputType output_type = ( use_dll ? ExprNodeOutputType : : CDynamicModel :
julia ? ExprNodeOutputType : : juliaDynamicModel : ExprNodeOutputType : : matlabDynamicModel ) ;
2009-12-16 18:13:23 +01:00
2011-04-12 16:41:29 +02:00
deriv_node_temp_terms_t tef_terms ;
2018-03-27 17:14:30 +02:00
temporary_terms_t temp_term_union ;
2013-10-22 18:31:59 +02:00
2018-11-16 18:13:34 +01:00
writeModelLocalVariableTemporaryTerms ( temp_term_union , temporary_terms_idxs ,
2019-04-12 15:41:52 +02:00
tt_output [ 0 ] , output_type , tef_terms ) ;
2009-06-05 16:45:23 +02:00
2018-11-15 16:39:53 +01:00
writeTemporaryTerms ( temporary_terms_derivatives [ 0 ] ,
2018-05-24 19:29:53 +02:00
temp_term_union ,
2018-05-28 15:23:15 +02:00
temporary_terms_idxs ,
2019-04-12 15:41:52 +02:00
tt_output [ 0 ] , output_type , tef_terms ) ;
2009-06-05 16:45:23 +02:00
2019-04-12 15:41:52 +02:00
writeModelEquations ( d_output [ 0 ] , output_type , temp_term_union ) ;
2009-06-05 16:45:23 +02:00
2009-12-16 18:13:23 +01:00
int nrows = equations . size ( ) ;
int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr ;
2009-06-05 16:45:23 +02:00
2009-12-16 18:13:23 +01:00
// Writing Jacobian
2018-11-15 16:39:53 +01:00
if ( ! derivatives [ 1 ] . empty ( ) )
2009-12-16 18:13:23 +01:00
{
2018-11-15 16:39:53 +01:00
writeTemporaryTerms ( temporary_terms_derivatives [ 1 ] ,
2018-05-24 19:29:53 +02:00
temp_term_union ,
2018-05-28 15:23:15 +02:00
temporary_terms_idxs ,
2019-04-12 15:41:52 +02:00
tt_output [ 1 ] , output_type , tef_terms ) ;
2009-12-16 18:13:23 +01:00
2019-12-20 16:59:30 +01:00
for ( const auto & first_derivative : derivatives [ 1 ] )
2018-03-27 17:14:30 +02:00
{
2019-09-11 15:59:23 +02:00
auto [ eq , var ] = vectorToTuple < 2 > ( first_derivative . first ) ;
2018-06-04 12:26:16 +02:00
expr_t d1 = first_derivative . second ;
2018-03-27 17:14:30 +02:00
2019-04-12 15:41:52 +02:00
jacobianHelper ( d_output [ 1 ] , eq , getDynJacobianCol ( var ) , output_type ) ;
d_output [ 1 ] < < " = " ;
d1 - > writeOutput ( d_output [ 1 ] , output_type ,
2018-05-24 19:29:53 +02:00
temp_term_union , temporary_terms_idxs , tef_terms ) ;
2019-04-12 15:41:52 +02:00
d_output [ 1 ] < < " ; " < < endl ;
2018-03-27 17:14:30 +02:00
}
2009-12-16 18:13:23 +01:00
}
2009-06-05 16:45:23 +02:00
2019-04-12 15:41:52 +02:00
// Write derivatives for order ≥ 2
for ( size_t i = 2 ; i < derivatives . size ( ) ; i + + )
if ( ! derivatives [ i ] . empty ( ) )
{
writeTemporaryTerms ( temporary_terms_derivatives [ i ] ,
temp_term_union ,
temporary_terms_idxs ,
tt_output [ i ] , output_type , tef_terms ) ;
/* When creating the sparse matrix (in MATLAB or C mode), since storage
is in column - major order , output the first column , then the second ,
then the third . This gives a significant performance boost in use_dll
mode ( at both compilation and runtime ) , because it facilitates memory
accesses and expression reusage . */
2020-06-23 17:50:50 +02:00
ostringstream i_output , j_output , v_output ;
2019-04-12 15:41:52 +02:00
int k = 0 ; // Current line index in the 3-column matrix
2019-12-16 19:42:59 +01:00
for ( const auto & [ vidx , d ] : derivatives [ i ] )
2019-04-12 15:41:52 +02:00
{
int eq = vidx [ 0 ] ;
2015-08-20 12:18:19 +02:00
2019-04-12 15:41:52 +02:00
int col_idx = 0 ;
for ( size_t j = 1 ; j < vidx . size ( ) ; j + + )
{
col_idx * = dynJacobianColsNbr ;
col_idx + = getDynJacobianCol ( vidx [ j ] ) ;
}
2015-08-20 12:18:19 +02:00
2018-09-05 18:27:13 +02:00
if ( output_type = = ExprNodeOutputType : : juliaDynamicModel )
2019-04-12 15:41:52 +02:00
{
d_output [ i ] < < " @inbounds " < < " g " < < i < < " [ " < < eq + 1 < < " , " < < col_idx + 1 < < " ] = " ;
d - > writeOutput ( d_output [ i ] , output_type , temp_term_union , temporary_terms_idxs , tef_terms ) ;
d_output [ i ] < < endl ;
}
2018-03-27 17:14:30 +02:00
else
{
2020-06-23 17:50:50 +02:00
i_output < < " g " < < i < < " _i " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = " < < eq + 1 < < " ; " < < endl ;
j_output < < " g " < < i < < " _j " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = " < < col_idx + 1 < < " ; " < < endl ;
v_output < < " g " < < i < < " _v " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d - > writeOutput ( v_output , output_type , temp_term_union , temporary_terms_idxs , tef_terms ) ;
v_output < < " ; " < < endl ;
2015-08-20 12:18:19 +02:00
2018-03-27 17:14:30 +02:00
k + + ;
}
2009-06-25 11:56:41 +02:00
2019-06-17 15:28:33 +02:00
// Output symetric elements at order 2
2019-04-12 15:41:52 +02:00
if ( i = = 2 & & vidx [ 1 ] ! = vidx [ 2 ] )
{
int col_idx_sym = getDynJacobianCol ( vidx [ 2 ] ) * dynJacobianColsNbr + getDynJacobianCol ( vidx [ 1 ] ) ;
if ( output_type = = ExprNodeOutputType : : juliaDynamicModel )
d_output [ 2 ] < < " @inbounds g2[ " < < eq + 1 < < " , " < < col_idx_sym + 1 < < " ] = "
< < " g2[ " < < eq + 1 < < " , " < < col_idx + 1 < < " ] " < < endl ;
else
{
2020-06-23 17:50:50 +02:00
i_output < < " g " < < i < < " _i " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = " < < eq + 1 < < " ; " < < endl ;
j_output < < " g " < < i < < " _j " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " = " < < col_idx_sym + 1 < < " ; " < < endl ;
v_output < < " g " < < i < < " _v " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = "
< < " g " < < i < < " _v " < < LEFT_ARRAY_SUBSCRIPT ( output_type )
< < k - 1 + ARRAY_SUBSCRIPT_OFFSET ( output_type )
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " ; " < < endl ;
2019-04-12 15:41:52 +02:00
k + + ;
}
}
}
if ( output_type ! = ExprNodeOutputType : : juliaDynamicModel )
2020-06-23 17:50:50 +02:00
d_output [ i ] < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
2019-04-12 15:41:52 +02:00
}
2009-10-12 18:09:16 +02:00
2018-09-05 18:27:13 +02:00
if ( output_type = = ExprNodeOutputType : : matlabDynamicModel )
2009-12-16 18:13:23 +01:00
{
2016-12-28 14:02:50 +01:00
// Check that we don't have more than 32 nested parenthesis because Matlab does not suppor this. See Issue #1201
2016-12-30 11:26:56 +01:00
map < string , string > tmp_paren_vars ;
2017-01-05 15:19:13 +01:00
bool message_printed = false ;
2019-04-12 15:41:52 +02:00
for ( auto & it : tt_output )
fixNestedParenthesis ( it , tmp_paren_vars , message_printed ) ;
for ( auto & it : d_output )
fixNestedParenthesis ( it , tmp_paren_vars , message_printed ) ;
2018-03-27 17:14:30 +02:00
ostringstream init_output , end_output ;
init_output < < " residual = zeros( " < < nrows < < " , 1); " ;
2018-06-27 15:01:31 +02:00
writeDynamicModelHelper ( basename , " dynamic_resid " , " residual " ,
" dynamic_resid_tt " ,
2018-11-15 16:39:53 +01:00
temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) ,
2018-03-27 17:14:30 +02:00
" " , init_output , end_output ,
2019-04-12 15:41:52 +02:00
d_output [ 0 ] , tt_output [ 0 ] ) ;
2018-03-27 17:14:30 +02:00
2019-04-12 15:41:52 +02:00
init_output . str ( " " ) ;
2018-03-27 17:14:30 +02:00
init_output < < " g1 = zeros( " < < nrows < < " , " < < dynJacobianColsNbr < < " ); " ;
2018-06-27 15:01:31 +02:00
writeDynamicModelHelper ( basename , " dynamic_g1 " , " g1 " ,
" dynamic_g1_tt " ,
2018-11-15 16:39:53 +01:00
temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) ,
2018-06-27 15:01:31 +02:00
" dynamic_resid_tt " ,
2018-03-27 17:14:30 +02:00
init_output , end_output ,
2019-04-12 15:41:52 +02:00
d_output [ 1 ] , tt_output [ 1 ] ) ;
2018-06-27 15:01:31 +02:00
writeWrapperFunctions ( basename , " g1 " ) ;
2018-03-27 17:14:30 +02:00
2019-04-12 15:41:52 +02:00
// For order ≥ 2
int ncols = dynJacobianColsNbr ;
int ntt = temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) ;
for ( size_t i = 2 ; i < derivatives . size ( ) ; i + + )
2018-03-27 17:14:30 +02:00
{
2019-04-12 15:41:52 +02:00
ncols * = dynJacobianColsNbr ;
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 ( ) )
{
2020-06-23 17:50:50 +02:00
init_output < < gname < < " _i = zeros( " < < NNZDerivatives [ i ] < < " ,1); " < < endl
< < gname < < " _j = zeros( " < < NNZDerivatives [ i ] < < " ,1); " < < endl
< < gname < < " _v = zeros( " < < NNZDerivatives [ i ] < < " ,1); " < < endl ;
2019-04-12 15:41:52 +02:00
end_output < < gname < < " = sparse( "
2020-06-23 17:50:50 +02:00
< < gname < < " _i, " < < gname < < " _j, " < < gname < < " _v, "
2019-04-12 15:41:52 +02:00
< < nrows < < " , " < < ncols < < " ); " ;
}
else
init_output < < gname < < " = sparse([],[],[], " < < nrows < < " , " < < ncols < < " ); " ;
writeDynamicModelHelper ( basename , " dynamic_ " + gname , gname ,
" dynamic_ " + gname + " _tt " ,
ntt ,
" dynamic_ " + gprevname + " _tt " ,
init_output , end_output ,
d_output [ i ] , tt_output [ i ] ) ;
if ( i < = 3 )
writeWrapperFunctions ( basename , gname ) ;
2018-03-27 17:14:30 +02:00
}
2018-05-23 16:10:26 +02:00
2018-06-27 15:01:31 +02:00
writeDynamicMatlabCompatLayer ( basename ) ;
2009-12-16 18:13:23 +01:00
}
2018-09-05 18:27:13 +02:00
else if ( output_type = = ExprNodeOutputType : : CDynamicModel )
2022-06-02 10:50:21 +02:00
for ( size_t i = 0 ; i < d_output . size ( ) ; i + + )
{
string funcname = i = = 0 ? " resid " : " g " + to_string ( i ) ;
DynamicOutput < < " void dynamic_ " < < funcname < < " _tt(const double *restrict y, const double *restrict x, int nb_row_x, const double *restrict params, const double *restrict steady_state, int it_, double *restrict T) " < < endl
< < " { " < < endl
< < tt_output [ i ] . str ( )
< < " } " < < endl
< < endl
< < " void dynamic_ " < < funcname < < " (const double *restrict y, const double *restrict x, int nb_row_x, const double *restrict params, const double *restrict steady_state, int it_, const double *restrict T, " ;
if ( i = = 0 )
DynamicOutput < < " double *restrict residual " ;
else if ( i = = 1 )
DynamicOutput < < " double *restrict g1 " ;
else
DynamicOutput < < " double *restrict " < < funcname < < " _i, double *restrict " < < funcname < < " _j, double *restrict " < < funcname < < " _v " ;
DynamicOutput < < " ) " < < endl
< < " { " < < endl ;
if ( i = = 0 )
DynamicOutput < < " double lhs, rhs; " < < endl ;
DynamicOutput < < d_output [ i ] . str ( )
< < " } " < < endl
< < endl ;
}
2015-08-18 13:13:56 +02:00
else
{
2021-04-22 18:03:47 +02:00
stringstream output ;
2015-08-18 13:13:56 +02:00
2018-06-27 15:01:31 +02:00
output < < " module " < < basename < < " Dynamic " < < endl
2018-03-27 17:14:30 +02:00
< < " # " < < endl
< < " # NB: this file was automatically generated by Dynare " < < endl
2018-06-27 15:01:31 +02:00
< < " # from " < < basename < < " .mod " < < endl
2018-03-27 17:14:30 +02:00
< < " # " < < endl
2021-04-22 15:47:43 +02:00
< < " using StatsFuns " < < endl < < endl
2018-03-28 17:50:58 +02:00
< < " export tmp_nbr, dynamic!, dynamicResid!, dynamicG1!, dynamicG2!, dynamicG3! " < < endl < < endl
2018-03-27 17:14:30 +02:00
< < " #= " < < endl
< < " # The comments below apply to all functions contained in this module # " < < endl
< < " NB: The arguments contained on the first line of the function " < < endl
< < " definition are those that are modified in place " < < endl < < endl
< < " ## Exported Functions ## " < < endl
< < " dynamic! : Wrapper function; computes residuals, Jacobian, Hessian, " < < endl
< < " and third derivatives depending on the arguments provided " < < endl
< < " dynamicResid! : Computes the dynamic model residuals " < < endl
< < " dynamicG1! : Computes the dynamic model Jacobian " < < endl
< < " dynamicG2! : Computes the dynamic model Hessian " < < endl
< < " dynamicG3! : Computes the dynamic model third derivatives " < < endl < < endl
2018-03-29 11:31:25 +02:00
< < " ## Exported Variables ## " < < endl
< < " tmp_nbr : Vector{Int}(4) respectively the number of temporary variables " < < endl
< < " for the residuals, g1, g2 and g3. " < < endl < < endl
2018-03-27 17:14:30 +02:00
< < " ## Local Functions ## " < < endl
< < " dynamicResidTT! : Computes the dynamic model temporary terms for the residuals " < < endl
< < " dynamicG1TT! : Computes the dynamic model temporary terms for the Jacobian " < < endl
< < " dynamicG2TT! : Computes the dynamic model temporary terms for the Hessian " < < endl
< < " dynamicG3TT! : Computes the dynamic model temporary terms for the third derivatives " < < endl < < endl
< < " ## Function Arguments ## " < < endl
2018-03-29 11:31:25 +02:00
< < " T : Vector{Float64}(num_temp_terms), temporary terms " < < endl
< < " y : Vector{Float64}(num_dynamic_vars), endogenous variables in the order stored model_.lead_lag_incidence; see the manual " < < endl
< < " x : Matrix{Float64}(nperiods,model_.exo_nbr), exogenous variables (in declaration order) for all simulation periods " < < endl
< < " params : Vector{Float64}(model_.param_nbr), parameter values in declaration order " < < endl
< < " steady_state : Vector{Float64}(model_endo_nbr) " < < endl
< < " it_ : Int, time period for exogenous variables for which to evaluate the model " < < endl
< < " residual : Vector{Float64}(model_.eq_nbr), residuals of the dynamic model equations in order of declaration of the equations. " < < endl
< < " g1 : Matrix{Float64}(model_.eq_nbr, num_dynamic_vars), Jacobian matrix of the dynamic model equations " < < endl
< < " The rows and columns respectively correspond to equations in order of declaration and variables in order " < < endl
< < " stored in model_.lead_lag_incidence " < < endl
< < " g2 : spzeros(model_.eq_nbr, (num_dynamic_vars)^2) Hessian matrix of the dynamic model equations " < < endl
< < " The rows and columns respectively correspond to equations in order of declaration and variables in order " < < endl
< < " stored in model_.lead_lag_incidence " < < endl
< < " g3 : spzeros(model_.eq_nbr, (num_dynamic_vars)^3) Third order derivative matrix of the dynamic model equations; " < < endl
< < " The rows and columns respectively correspond to equations in order of declaration and variables in order " < < endl
< < " stored in model_.lead_lag_incidence " < < endl < < endl
< < " ## Remarks ## " < < endl
< < " [1] `num_dynamic_vars` is the number of non zero entries in the lead lag incidence matrix, `model_.lead_lag_incidence.` " < < endl
2019-12-20 16:59:30 +01:00
< < " [2] The size of `T`, ie the value of `num_temp_terms`, depends on the version of the dynamic model called. The number of temporary variables " < < endl
2018-03-29 11:31:25 +02:00
< < " used for the different returned objects (residuals, jacobian, hessian or third order derivatives) is given by the elements in `tmp_nbr` " < < endl
< < " exported vector. The first element is the number of temporaries used for the computation of the residuals, the second element is the " < < endl
< < " number of temporaries used for the evaluation of the jacobian matrix, etc. If one calls the version of the dynamic model computing the " < < endl
< < " residuals, the jacobian and hessian matrices, then `T` must have at least `sum(tmp_nbr[1:3])` elements. " < < endl
2018-03-27 17:14:30 +02:00
< < " =# " < < endl < < endl ;
2018-03-28 17:50:58 +02:00
// Write the number of temporary terms
output < < " tmp_nbr = zeros(Int,4) " < < endl
2018-11-15 16:39:53 +01:00
< < " tmp_nbr[1] = " < < temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) < < " # Number of temporary terms for the residuals " < < endl
< < " tmp_nbr[2] = " < < temporary_terms_derivatives [ 1 ] . size ( ) < < " # Number of temporary terms for g1 (jacobian) " < < endl
< < " tmp_nbr[3] = " < < temporary_terms_derivatives [ 2 ] . size ( ) < < " # Number of temporary terms for g2 (hessian) " < < endl
< < " tmp_nbr[4] = " < < temporary_terms_derivatives [ 3 ] . size ( ) < < " # Number of temporary terms for g3 (third order derivates) " < < endl < < endl ;
2018-03-28 17:50:58 +02:00
2018-03-27 17:14:30 +02:00
// dynamicResidTT!
output < < " function dynamicResidTT!(T::Vector{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
2019-04-12 15:41:52 +02:00
< < tt_output [ 0 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamic!
2021-08-18 16:52:35 +02:00
output < < " function dynamicResid!(T::Vector{Float64}, residual::AbstractVector{Float64}, " < < endl
2018-03-27 17:14:30 +02:00
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool) " < < endl
2018-11-15 16:39:53 +01:00
< < " @assert length(T) >= " < < temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) < < endl
2018-03-27 17:14:30 +02:00
< < " @assert length(residual) == " < < nrows < < endl
< < " @assert length(y)+size(x, 2) == " < < dynJacobianColsNbr < < endl
< < " @assert length(params) == " < < symbol_table . param_nbr ( ) < < endl
< < " if T_flag " < < endl
< < " dynamicResidTT!(T, y, x, params, steady_state, it_) " < < endl
< < " end " < < endl
2019-04-12 15:41:52 +02:00
< < d_output [ 0 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamicG1TT!
output < < " function dynamicG1TT!(T::Vector{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicResidTT!(T, y, x, params, steady_state, it_) " < < endl
2019-04-12 15:41:52 +02:00
< < tt_output [ 1 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamicG1!
output < < " function dynamicG1!(T::Vector{Float64}, g1::Matrix{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool) " < < endl
< < " @assert length(T) >= "
2018-11-15 16:39:53 +01:00
< < temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) < < endl
2018-03-27 17:14:30 +02:00
< < " @assert size(g1) == ( " < < nrows < < " , " < < dynJacobianColsNbr < < " ) " < < endl
< < " @assert length(y)+size(x, 2) == " < < dynJacobianColsNbr < < endl
< < " @assert length(params) == " < < symbol_table . param_nbr ( ) < < endl
< < " if T_flag " < < endl
< < " dynamicG1TT!(T, y, x, params, steady_state, it_) " < < endl
< < " end " < < endl
< < " fill!(g1, 0.0) " < < endl
2019-04-12 15:41:52 +02:00
< < d_output [ 1 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamicG2TT!
output < < " function dynamicG2TT!(T::Vector{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicG1TT!(T, y, x, params, steady_state, it_) " < < endl
2019-04-12 15:41:52 +02:00
< < tt_output [ 2 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamicG2!
output < < " function dynamicG2!(T::Vector{Float64}, g2::Matrix{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool) " < < endl
2018-11-15 16:39:53 +01:00
< < " @assert length(T) >= " < < temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) + temporary_terms_derivatives [ 2 ] . size ( ) < < endl
2018-03-27 17:14:30 +02:00
< < " @assert size(g2) == ( " < < nrows < < " , " < < hessianColsNbr < < " ) " < < endl
< < " @assert length(y)+size(x, 2) == " < < dynJacobianColsNbr < < endl
< < " @assert length(params) == " < < symbol_table . param_nbr ( ) < < endl
< < " if T_flag " < < endl
< < " dynamicG2TT!(T, y, x, params, steady_state, it_) " < < endl
< < " end " < < endl
< < " fill!(g2, 0.0) " < < endl
2019-04-12 15:41:52 +02:00
< < d_output [ 2 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamicG3TT!
output < < " function dynamicG3TT!(T::Vector{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicG2TT!(T, y, x, params, steady_state, it_) " < < endl
2019-04-12 15:41:52 +02:00
< < tt_output [ 3 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamicG3!
2015-08-20 11:32:26 +02:00
int ncols = hessianColsNbr * dynJacobianColsNbr ;
2018-03-27 17:14:30 +02:00
output < < " function dynamicG3!(T::Vector{Float64}, g3::Matrix{Float64}, " < < endl
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool) " < < endl
< < " @assert length(T) >= "
2018-11-15 16:39:53 +01:00
< < temporary_terms_mlv . size ( ) + temporary_terms_derivatives [ 0 ] . size ( ) + temporary_terms_derivatives [ 1 ] . size ( ) + temporary_terms_derivatives [ 2 ] . size ( ) + temporary_terms_derivatives [ 3 ] . size ( ) < < endl
2018-03-27 17:14:30 +02:00
< < " @assert size(g3) == ( " < < nrows < < " , " < < ncols < < " ) " < < endl
< < " @assert length(y)+size(x, 2) == " < < dynJacobianColsNbr < < endl
< < " @assert length(params) == " < < symbol_table . param_nbr ( ) < < endl
< < " if T_flag " < < endl
< < " dynamicG3TT!(T, y, x, params, steady_state, it_) " < < endl
< < " end " < < endl
< < " fill!(g3, 0.0) " < < endl
2019-04-12 15:41:52 +02:00
< < d_output [ 3 ] . str ( )
2018-03-27 17:14:30 +02:00
< < " return nothing " < < endl
< < " end " < < endl < < endl ;
// dynamic!
2021-08-18 16:52:35 +02:00
output < < " function dynamic!(T::Vector{Float64}, residual::AbstractVector{Float64}, " < < endl
2018-03-27 17:14:30 +02:00
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicResid!(T, residual, y, x, params, steady_state, it_, true) " < < endl
< < " return nothing " < < endl
< < " end " < < endl
< < endl
2021-08-18 16:52:35 +02:00
< < " function dynamic!(T::Vector{Float64}, residual::AbstractVector{Float64}, g1::Matrix{Float64}, " < < endl
2018-03-27 17:14:30 +02:00
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicG1!(T, g1, y, x, params, steady_state, it_, true) " < < endl
< < " dynamicResid!(T, residual, y, x, params, steady_state, it_, false) " < < endl
< < " return nothing " < < endl
< < " end " < < endl
< < endl
2021-08-18 16:52:35 +02:00
< < " function dynamic!(T::Vector{Float64}, residual::AbstractVector{Float64}, g1::Matrix{Float64}, g2::Matrix{Float64}, " < < endl
2018-03-27 17:14:30 +02:00
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicG2!(T, g2, y, x, params, steady_state, it_, true) " < < endl
< < " dynamicG1!(T, g1, y, x, params, steady_state, it_, false) " < < endl
< < " dynamicResid!(T, residual, y, x, params, steady_state, it_, false) " < < endl
< < " return nothing " < < endl
< < " end " < < endl
< < endl
2021-08-18 16:52:35 +02:00
< < " function dynamic!(T::Vector{Float64}, residual::AbstractVector{Float64}, g1::Matrix{Float64}, g2::Matrix{Float64}, g3::Matrix{Float64}, " < < endl
2018-03-27 17:14:30 +02:00
< < " y::Vector{Float64}, x::Matrix{Float64}, "
< < " params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int) " < < endl
< < " dynamicG3!(T, g3, y, x, params, steady_state, it_, true) " < < endl
< < " dynamicG2!(T, g2, y, x, params, steady_state, it_, false) " < < endl
< < " dynamicG1!(T, g1, y, x, params, steady_state, it_, false) " < < endl
< < " dynamicResid!(T, residual, y, x, params, steady_state, it_, false) " < < endl
< < " return nothing " < < endl
< < " end " < < endl
2021-04-26 12:52:18 +02:00
< < endl ;
// Write function definition if BinaryOpcode::powerDeriv is used
writePowerDerivJulia ( output ) ;
output < < " end " < < endl ;
2021-04-22 18:03:47 +02:00
writeToFileIfModified ( output , basename + " Dynamic.jl " ) ;
2015-08-18 13:13:56 +02:00
}
2009-12-16 18:13:23 +01:00
}
2009-04-14 16:39:53 +02:00
2019-05-03 19:24:55 +02:00
void
DynamicModel : : writeDynamicJacobianNonZeroElts ( const string & basename ) const
{
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
{
2019-12-16 19:42:59 +01:00
if ( symbol_table . getType ( getSymbIDByDerivID ( indices [ 1 ] ) ) ! = SymbolType : : endogenous )
2019-05-03 19:24:55 +02:00
continue ;
2019-12-16 19:42:59 +01:00
int tsid = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( indices [ 1 ] ) ) ;
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 ( ) ) ;
ofstream output { " + " + basename + " /dynamic_g1_nz.m " , ios : : out | ios : : binary } ;
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 ;
int idx = 1 ;
for ( const auto & it : nzij )
{
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
{
auto str = it - > str ( ) ;
if ( str [ 0 ] = = ' \' ' & & str [ str . size ( ) - 1 ] = = ' \' ' )
str = str . substr ( 1 , str . size ( ) - 2 ) ;
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 )
2022-06-02 10:50:21 +02:00
if ( auto tmp = all_equation_tags . getTagValueByEqnAndKey ( i , " endogenous " ) ; ! tmp . empty ( ) )
excluded_vars . push_back ( symbol_table . getID ( tmp ) ) ;
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
2021-04-19 14:51:34 +02:00
DynamicModel : : writeBlockDriverOutput ( ostream & output , const string & basename ,
2020-05-20 11:35:14 +02:00
const vector < int > & state_var , bool estimation_present ) const
{
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 < < " ).maximum_lag = " < < blocks [ blk ] . max_lag < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_lead = " < < blocks [ blk ] . max_lead < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_endo_lag = " < < blocks [ blk ] . max_endo_lag < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_endo_lead = " < < blocks [ blk ] . max_endo_lead < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_exo_lag = " < < blocks [ blk ] . max_exo_lag < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_exo_lead = " < < blocks [ blk ] . max_exo_lead < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_exo_det_lag = " < < blocks [ blk ] . max_exo_det_lag < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).maximum_exo_det_lead = " < < blocks [ blk ] . max_exo_det_lead < < " ; " < < 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
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).exogenous = [ " ;
2020-05-20 11:35:14 +02:00
for ( int exo : blocks_exo [ blk ] )
output < < " " < < exo + 1 ;
output < < " ]; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).exo_nbr = " < < blocks_exo [ blk ] . size ( ) < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).exogenous_det = [ " ;
2020-05-20 11:35:14 +02:00
for ( int exo_det : blocks_exo_det [ blk ] )
output < < " " < < exo_det + 1 ;
output < < " ]; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).exo_det_nbr = " < < blocks_exo_det [ blk ] . size ( ) < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).other_endogenous = [ " ;
2020-05-20 11:35:14 +02:00
for ( int other_endo : blocks_other_endo [ blk ] )
output < < " " < < other_endo + 1 ;
output < < " ]; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.block_structure.block( " < < blk + 1 < < " ).other_endogenous_block = [ " ;
2020-05-20 11:35:14 +02:00
for ( int other_endo : blocks_other_endo [ blk ] )
output < < " " < < endo2block [ other_endo ] + 1 ;
output < < " ]; " < < endl ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).tm1 = zeros( " < < blocks_other_endo [ blk ] . size ( ) < < " , " < < state_var . size ( ) < < " ); " < < endl ;
2020-05-20 11:35:14 +02:00
int line = 1 ;
for ( auto other_endo : blocks_other_endo [ blk ] )
{
if ( auto it = find ( state_var . begin ( ) , state_var . end ( ) , other_endo ) ;
it ! = state_var . end ( ) )
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).tm1( "
2020-05-20 11:35:14 +02:00
< < line < < " , "
< < distance ( state_var . begin ( ) , it ) + 1 < < " ) = 1; " < < endl ;
line + + ;
}
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).other_endo_nbr = " < < blocks_other_endo [ blk ] . size ( ) < < " ; " < < endl ;
2020-05-20 11:35:14 +02:00
int count_lead_lag_incidence = 0 ;
vector < int > local_state_var ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).lead_lag_incidence = [ " < < endl ;
2020-05-20 11:35:14 +02:00
for ( int lag = - 1 ; lag < = 1 ; lag + + )
{
for ( int var = 0 ; var < block_size ; var + + )
{
for ( int eq = 0 ; eq < block_size ; eq + + )
2022-05-04 16:01:34 +02:00
if ( blocks_derivatives [ blk ] . contains ( { eq , var , lag } ) )
2020-05-20 11:35:14 +02:00
{
if ( lag = = - 1 )
local_state_var . push_back ( getBlockVariableID ( blk , var ) ) ;
output < < " " < < + + count_lead_lag_incidence ;
goto var_found ;
}
output < < " 0 " ;
var_found :
;
}
output < < " ; " < < endl ;
}
output < < " ]; " < < endl ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).sorted_col_dr_ghx = [ " ;
2020-05-20 11:35:14 +02:00
for ( int lsv : local_state_var )
output < < distance ( state_var . begin ( ) , find ( state_var . begin ( ) , state_var . end ( ) , lsv ) ) + 1 < < " " ;
output < < " ]; " < < endl ;
count_lead_lag_incidence = 0 ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).lead_lag_incidence_other = [ " < < endl ;
2020-05-20 11:35:14 +02:00
for ( int lag = - 1 ; lag < = 1 ; lag + + )
{
for ( int other_endo : blocks_other_endo [ blk ] )
{
for ( int eq = 0 ; eq < block_size ; eq + + )
2022-05-04 16:01:34 +02:00
if ( blocks_derivatives_other_endo [ blk ] . contains ( { eq , other_endo , lag } ) )
2020-05-20 11:35:14 +02:00
{
output < < " " < < + + count_lead_lag_incidence ;
goto other_endo_found ;
}
output < < " 0 " ;
other_endo_found :
;
}
output < < " ; " < < endl ;
}
output < < " ]; " < < endl ;
2021-04-19 14:51:34 +02:00
output < < " M_.block_structure.block( " < < blk + 1 < < " ).n_static = " < < blocks [ blk ] . n_static < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).n_forward = " < < blocks [ blk ] . n_forward < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).n_backward = " < < blocks [ blk ] . n_backward < < " ; " < < endl
< < " M_.block_structure.block( " < < blk + 1 < < " ).n_mixed = " < < blocks [ blk ] . n_mixed < < " ; " < < 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
}
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 ] ;
int var = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( deriv_id ) ) ;
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
if ( estimation_present )
{
filesystem : : create_directories ( basename + " /model/bytecode " ) ;
string main_name = basename + " /model/bytecode/kfi " ;
ofstream KF_index_file ;
KF_index_file . open ( main_name , ios : : out | ios : : binary | ios : : ate ) ;
int n_obs = symbol_table . observedVariablesNbr ( ) ;
int n_state = state_var . size ( ) ;
for ( int it : state_var )
if ( symbol_table . isObservedVariable ( symbol_table . getID ( SymbolType : : endogenous , it ) ) )
n_obs - - ;
int n = n_obs + n_state ;
2021-04-19 14:51:34 +02:00
output < < " M_.nobs_non_statevar = " < < n_obs < < " ; " < < endl ;
2020-05-20 11:35:14 +02:00
int nb_diag = 0 ;
vector < int > i_nz_state_var ( n ) ;
for ( int i = 0 ; i < n_obs ; i + + )
i_nz_state_var [ i ] = n ;
int lp = n_obs ;
vector < int > state_equ ;
for ( int it : state_var )
state_equ . push_back ( eq_idx_block2orig [ endo_idx_orig2block [ it ] ] ) ;
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
{
int nze = 0 ;
for ( int i = 0 ; i < blocks [ blk ] . size ; i + + )
if ( int var = getBlockVariableID ( blk , i ) ;
find ( state_var . begin ( ) , state_var . end ( ) , var ) ! = state_var . end ( ) )
nze + + ;
if ( blk = = 0 )
{
set < pair < int , int > > row_state_var_incidence ;
for ( const auto & [ idx , ignore ] : blocks_derivatives [ blk ] )
if ( auto it_state_var = find ( state_var . begin ( ) , state_var . end ( ) , getBlockVariableID ( blk , get < 1 > ( idx ) ) ) ;
it_state_var ! = state_var . end ( ) )
if ( auto it_state_equ = find ( state_equ . begin ( ) , state_equ . end ( ) , getBlockEquationID ( blk , get < 0 > ( idx ) ) ) ;
it_state_equ ! = state_equ . end ( ) )
row_state_var_incidence . emplace ( it_state_equ - state_equ . begin ( ) , it_state_var - state_var . begin ( ) ) ;
auto row_state_var_incidence_it = row_state_var_incidence . begin ( ) ;
bool diag = true ;
int nb_diag_r = 0 ;
while ( row_state_var_incidence_it ! = row_state_var_incidence . end ( ) & & diag )
{
diag = ( row_state_var_incidence_it - > first = = row_state_var_incidence_it - > second ) ;
if ( diag )
{
int equ = row_state_var_incidence_it - > first ;
row_state_var_incidence_it + + ;
if ( equ ! = row_state_var_incidence_it - > first )
nb_diag_r + + ;
}
}
set < pair < int , int > > col_state_var_incidence ;
for ( auto [ equ , var ] : row_state_var_incidence )
col_state_var_incidence . emplace ( var , equ ) ;
auto col_state_var_incidence_it = col_state_var_incidence . begin ( ) ;
diag = true ;
int nb_diag_c = 0 ;
while ( col_state_var_incidence_it ! = col_state_var_incidence . end ( ) & & diag )
{
diag = ( col_state_var_incidence_it - > first = = col_state_var_incidence_it - > second ) ;
if ( diag )
{
int var = col_state_var_incidence_it - > first ;
col_state_var_incidence_it + + ;
if ( var ! = col_state_var_incidence_it - > first )
nb_diag_c + + ;
}
}
nb_diag = min ( nb_diag_r , nb_diag_c ) ;
row_state_var_incidence . clear ( ) ;
col_state_var_incidence . clear ( ) ;
}
for ( int i = 0 ; i < nze ; i + + )
i_nz_state_var [ lp + i ] = lp + nze ;
lp + = nze ;
}
2021-04-19 14:51:34 +02:00
output < < " M_.nz_state_var = [ " ;
2020-05-20 11:35:14 +02:00
for ( int i = 0 ; i < lp ; i + + )
output < < i_nz_state_var [ i ] < < " " ;
output < < " ]; " < < endl
2021-04-19 14:51:34 +02:00
< < " M_.n_diag = " < < nb_diag < < " ; " < < endl ;
2020-05-20 11:35:14 +02:00
KF_index_file . write ( reinterpret_cast < char * > ( & nb_diag ) , sizeof ( nb_diag ) ) ;
using index_KF = pair < int , pair < int , int > > ;
vector < index_KF > v_index_KF ;
for ( int i = 0 ; i < n ; i + + )
for ( int j = n_obs ; j < n ; j + + )
{
int j1 = j - n_obs ;
int j1_n_state = j1 * n_state - n_obs ;
if ( ( i < n_obs ) | | ( i > = nb_diag + n_obs ) | | ( j1 > = nb_diag ) )
for ( int k = n_obs ; k < i_nz_state_var [ i ] ; k + + )
v_index_KF . emplace_back ( i + j1 * n , pair ( i + k * n , k + j1_n_state ) ) ;
}
int size_v_index_KF = v_index_KF . size ( ) ;
KF_index_file . write ( reinterpret_cast < char * > ( & size_v_index_KF ) , sizeof ( size_v_index_KF ) ) ;
for ( auto & it : v_index_KF )
KF_index_file . write ( reinterpret_cast < char * > ( & it ) , sizeof ( index_KF ) ) ;
vector < index_KF > v_index_KF_2 ;
int n_n_obs = n * n_obs ;
for ( int i = 0 ; i < n ; i + + )
for ( int j = i ; j < n ; j + + )
if ( ( i < n_obs ) | | ( i > = nb_diag + n_obs ) | | ( j < n_obs ) | | ( j > = nb_diag + n_obs ) )
for ( int k = n_obs ; k < i_nz_state_var [ j ] ; k + + )
{
int k_n = k * n ;
v_index_KF_2 . emplace_back ( i * n + j , pair ( i + k_n - n_n_obs , j + k_n ) ) ;
}
int size_v_index_KF_2 = v_index_KF_2 . size ( ) ;
KF_index_file . write ( reinterpret_cast < char * > ( & size_v_index_KF_2 ) , sizeof ( size_v_index_KF_2 ) ) ;
for ( auto & it : v_index_KF_2 )
KF_index_file . write ( reinterpret_cast < char * > ( & it ) , sizeof ( index_KF ) ) ;
KF_index_file . close ( ) ;
}
}
2009-04-14 16:39:53 +02:00
void
2021-02-22 18:26:21 +01:00
DynamicModel : : writeDriverOutput ( ostream & output , const string & basename , bool block_decomposition , bool use_dll , bool occbin , bool estimation_present , 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 ) ;
2009-12-16 18:13:23 +01:00
output < < " " < < getDynJacobianCol ( varID ) + 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 = [ " ;
2021-04-19 14:51:34 +02:00
for ( size_t i = 0 ; i < temporary_terms_derivatives . size ( ) ; i + + )
output < < temporary_terms_derivatives [ i ] . size ( ) + ( i = = 0 ? temporary_terms_mlv . size ( ) : 0 ) < < " ; " ;
output < < " ]; " < < endl ;
2020-06-05 17:11:29 +02:00
2021-04-19 14:51:34 +02:00
/* Write mapping between model local variables and indices in the temporary
terms vector ( dynare # 1722 ) */
output < < " M_.model_local_variables_dynamic_tt_idxs = { " < < endl ;
for ( auto [ mlv , value ] : temporary_terms_mlv )
output < < " ' " < < symbol_table . getName ( mlv - > symb_id ) < < " ', "
< < temporary_terms_idxs . at ( mlv ) + 1 < < ' ; ' < < endl ;
output < < " }; " < < endl ;
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
2021-01-25 18:03:37 +01:00
if ( block_decomposition )
2021-04-19 14:51:34 +02:00
writeBlockDriverOutput ( output , basename , state_var , estimation_present ) ;
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 ;
output < < " M_.endo_trends( " < < i < < " ). "
< < ( 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 ( ) ;
output < < " M_.endo_trends( " < < i < < " ). "
< < ( 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 ;
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 )
2018-08-23 13:56:58 +02:00
var_model_table . setRhs ( rhsr ) ;
2021-07-16 12:26:57 +02:00
else
2018-08-31 12:35:51 +02:00
{
trend_component_model_table . setRhs ( rhsr ) ;
2018-09-13 12:21:23 +02:00
trend_component_model_table . setTargetVar ( 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 ;
2021-07-01 16:16:04 +02:00
int eqn ;
try
{
eqn = equation_tags . getEqnByTag ( " name " , eqtag ) ;
}
catch ( EquationTags : : TagNotFoundException & e )
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 ) ;
}
2018-11-28 14:32:26 +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 ) ;
}
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 ;
2018-11-28 14:32:26 +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 ( ) ) ) ;
2018-11-28 14:32:26 +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
}
var_model_table . setEqNums ( eqnums ) ;
var_model_table . setLhs ( lhsr ) ;
var_model_table . setRhs ( rhsr ) ;
var_model_table . setLhsExprT ( lhs_expr_tr ) ;
}
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
string eqtag = equation_tags . getTagValueByEqnAndKey ( eqn , " name " ) ;
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 )
{
cerr < < " ERROR: in Equation " < < eqtag
< < " . 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
{
cerr < < " ERROR: in Equation " < < eqtag
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 )
{
cerr < < " ERROR: in Equation " < < eqtag
< < " . 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
}
var_model_table . setDiff ( diff ) ;
var_model_table . setMaxLags ( lags ) ;
var_model_table . setOrigDiffVar ( 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-05-16 15:15:17 +02:00
if ( avi - > get_type ( ) = = AuxVarType : : endoLag & & avi - > get_orig_symb_id ( ) . value ( ) = = lhs_symb_id
& & avi - > get_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 ;
while ( avi - > get_type ( ) = = AuxVarType : : diffLag )
{
diff_lag_depth + + ;
if ( avi - > get_orig_symb_id ( ) = = lhs_symb_id & & lead_lag2 - diff_lag_depth = = lead_lag )
{
deriv_ids . push_back ( deriv_id2 ) ;
break ;
}
try
{
2022-05-16 15:15:17 +02:00
avi = & symbol_table . getAuxVarInfo ( avi - > get_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 ( ) )
{
cerr < < " ERROR: Equation ' " < < equation_tags . getTagValueByEqnAndKey ( eqns [ i ] , " name " ) < < " ' is not linear " < < endl ;
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 ( ) )
{
cerr < < " ERROR: Equation ' " < < equation_tags . getTagValueByEqnAndKey ( eqns [ i ] , " name " ) < < " ' is not linear " < < endl ;
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
}
}
var_model_table . setAR ( AR ) ;
var_model_table . setA0 ( A0 ) ;
2021-07-16 15:12:37 +02:00
var_model_table . setConstants ( 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
{
int i = 0 ;
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 ) ;
2021-07-06 19:04:59 +02:00
for ( 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
{
2021-07-01 16:16:04 +02:00
int eqn ;
try
2018-08-14 14:23:21 +02:00
{
2021-07-01 16:16:04 +02:00
eqn = equation_tags . getEqnByTag ( " name " , eqtag ) ;
}
catch ( EquationTags : : TagNotFoundException & e )
{
cerr < < " ERROR: no equation is named ' " < < eqtag < < " ' " < < endl ;
2018-08-14 14:23:21 +02:00
exit ( EXIT_FAILURE ) ;
}
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 ;
2021-07-01 16:16:04 +02:00
int eqn ;
try
{
eqn = equation_tags . getEqnByTag ( " name " , eqtag ) ;
}
catch ( EquationTags : : TagNotFoundException & e )
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
}
2018-11-28 14:32:26 +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
2018-08-14 14:23:21 +02: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 ;
2018-11-28 14:32:26 +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
2018-11-28 14:32:26 +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
}
2018-08-14 14:23:21 +02:00
trend_component_model_table . setRhs ( rhsr ) ;
2018-10-24 15:57:07 +02:00
trend_component_model_table . setVals ( eqnums , trend_eqnums , lhsr , 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
{
int i = 0 ;
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
2021-07-06 19:04:59 +02:00
for ( 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 + + ;
}
i = 0 ;
2021-07-06 19:04:59 +02:00
for ( 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
string eqtag = equation_tags . getTagValueByEqnAndKey ( eqn , " name " ) ;
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 )
{
cerr < < " ERROR: in Equation " < < eqtag
< < " . 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 )
{
cerr < < " ERROR: in Equation " < < eqtag
< < " . 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
}
2018-08-14 14:23:21 +02:00
trend_component_model_table . setDiff ( diff ) ;
trend_component_model_table . setMaxLags ( lags ) ;
trend_component_model_table . setOrigDiffVar ( 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 ( ) ;
2018-09-12 17:56:30 +02:00
trend_component_model_table . setAR ( ARr ) ;
2021-07-01 16:16:04 +02:00
auto [ A0r , A0starr ] = computeErrorComponentMatrices ( diff_subst_table ) ;
2019-02-19 12:08:00 +01:00
trend_component_model_table . setA0 ( A0r , 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 ) ;
}
string eqn = equation_tags . getTagValueByEqnAndKey ( & equation - & equations [ 0 ] , " name " ) ;
if ( eqn . empty ( ) )
{
cerr < < " Every equation with a 'pac_expectation' operator must have been assigned an equation tag name " < < endl ;
exit ( EXIT_FAILURE ) ;
}
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 ]
= arg2 - > getPacOptimizingShareAndExprNodes ( lhs_symb_id , lhs_orig_symb_id ) ;
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 ]
= barg2 - > getPacOptimizingShareAndExprNodes ( lhs_symb_id , undiff_lhs_symb_id ) ;
/* 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 ;
int component_idx = 1 ;
for ( auto & [ component , growth , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth , growth_info ] : pac_target_components )
{
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
{
2021-10-28 14:42:56 +02:00
int eq = equation_tags . getEqnByTag ( " name " , pac_eq_name . at ( model_name ) ) ;
2021-10-27 18:17:14 +02:00
auto substeq = dynamic_cast < BinaryOpNode * > ( equations [ eq ] - > substitutePacExpectation ( model_name , substexpr ) ) ;
assert ( substeq ) ;
equations [ eq ] = substeq ;
}
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
2018-11-22 14:32:40 +01:00
DynamicModel : : computingPass ( bool jacobianExo , int derivsOrder , int paramsDerivsOrder ,
2022-05-19 14:10:22 +02:00
const eval_context_t & eval_context , bool no_tmp_terms , bool block , bool use_dll )
2009-04-14 16:39:53 +02:00
{
2018-11-22 14:32:40 +01:00
assert ( jacobianExo | | ( derivsOrder < 2 & & paramsDerivsOrder = = 0 ) ) ;
2009-04-20 12:48:54 +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()
2009-04-20 12:48:54 +02:00
computeDynJacobianCols ( jacobianExo ) ;
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
dynJacobianColsNbr is not yet set . */
if ( log2 ( dynJacobianColsNbr ) * derivsOrder > = numeric_limits < int > : : digits )
{
cerr < < " ERROR: The dynamic derivatives matrix is too large. Please decrease the approximation order. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2009-04-20 12:48:54 +02:00
// Compute derivatives w.r. to all endogenous, and possibly exogenous and exogenous deterministic
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 ) ;
2018-07-17 18:34:07 +02:00
if ( type = = SymbolType : : endogenous | | ( jacobianExo & & ( 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
2021-01-25 18:03:37 +01:00
cout < < " Computing dynamic model 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
{
2018-12-20 17:04:28 +01:00
cout < < " Computing dynamic model 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
}
2018-09-21 17:13:19 +02:00
2021-01-25 18:03:37 +01:00
if ( block )
2018-09-21 17:13:19 +02:00
{
2020-05-06 18:09:44 +02:00
auto contemporaneous_jacobian = evaluateAndReduceJacobian ( eval_context ) ;
2009-12-16 14:21:31 +01:00
2022-04-19 17:06:37 +02:00
computeNonSingularNormalization ( contemporaneous_jacobian , true ) ;
2009-12-16 14:21:31 +01:00
2020-04-30 12:48:16 +02:00
auto [ prologue , epilogue ] = computePrologueAndEpilogue ( ) ;
2009-04-14 16:39:53 +02:00
2020-04-21 18:10:46 +02:00
auto first_order_endo_derivatives = collectFirstOrderDerivativesEndogenous ( ) ;
2009-05-13 01:03:40 +02:00
2020-03-20 15:23:23 +01:00
equationTypeDetermination ( first_order_endo_derivatives , mfs ) ;
2009-12-16 14:21:31 +01:00
2018-12-20 17:04:28 +01:00
cout < < " Finding the optimal block decomposition of the model ... " < < endl ;
2009-12-16 14:21:31 +01:00
2020-04-30 12:48:16 +02:00
computeBlockDecomposition ( prologue , epilogue ) ;
2010-07-23 11:20:24 +02:00
2020-04-30 12:48:16 +02:00
reduceBlockDecomposition ( ) ;
2009-12-16 14:21:31 +01:00
2020-04-15 17:56:28 +02:00
printBlockDecomposition ( ) ;
2009-12-16 14:21:31 +01:00
2020-03-19 17:46:10 +01:00
computeChainRuleJacobian ( ) ;
2009-08-25 11:43:01 +02:00
2020-03-20 15:23:23 +01:00
determineLinearBlocks ( ) ;
2009-08-25 11:43:01 +02:00
2020-05-06 14:02:58 +02:00
computeBlockDynJacobianCols ( ) ;
2009-08-25 11:43:01 +02:00
2009-04-14 16:39:53 +02:00
if ( ! no_tmp_terms )
2020-05-06 17:13:47 +02:00
computeBlockTemporaryTerms ( ) ;
2009-04-14 16:39:53 +02:00
}
else
2018-09-25 15:56:52 +02:00
{
computeTemporaryTerms ( ! use_dll , no_tmp_terms ) ;
2018-11-16 18:13:34 +01:00
/* Must be called after computeTemporaryTerms(), because it depends on
temporary_terms_mlv to be filled */
if ( paramsDerivsOrder > 0 & & ! no_tmp_terms )
computeParamsDerivativesTemporaryTerms ( ) ;
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 ( )
{
int i = 0 ;
2019-12-20 16:59:30 +01:00
for ( 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 ;
}
i = 0 ;
2019-12-16 19:42:59 +01:00
for ( auto it = xrefs . begin ( ) ; it ! = xrefs . end ( ) ; + + it , i + + )
2017-03-06 16:34:08 +01:00
{
computeRevXref ( xref_param , it - > second . param , i ) ;
computeRevXref ( xref_endo , it - > second . endo , i ) ;
computeRevXref ( xref_exo , it - > second . exo , i ) ;
computeRevXref ( xref_exo_det , it - > second . exo_det , i ) ;
}
}
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 ;
int i = 1 ;
2019-12-16 19:42:59 +01:00
for ( auto it = xrefs . begin ( ) ; it ! = xrefs . end ( ) ; + + it , i + + )
2017-03-06 16:34:08 +01:00
{
output < < " M_.xref1.param{ " < < i < < " } = [ " ;
2019-12-20 16:59:30 +01:00
for ( const auto & it1 : it - > second . param )
2018-06-04 12:26:16 +02:00
output < < symbol_table . getTypeSpecificID ( it1 . first ) + 1 < < " " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
output < < " M_.xref1.endo{ " < < i < < " } = [ " ;
2019-12-20 16:59:30 +01:00
for ( const auto & it1 : it - > second . endo )
2018-06-04 12:26:16 +02:00
output < < " struct('id', " < < symbol_table . getTypeSpecificID ( it1 . first ) + 1 < < " , 'shift', " < < it1 . second < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
output < < " M_.xref1.exo{ " < < i < < " } = [ " ;
2019-12-20 16:59:30 +01:00
for ( const auto & it1 : it - > second . exo )
2018-06-04 12:26:16 +02:00
output < < " struct('id', " < < symbol_table . getTypeSpecificID ( it1 . first ) + 1 < < " , 'shift', " < < it1 . second < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
output < < " M_.xref1.exo_det{ " < < i < < " } = [ " ;
2019-12-20 16:59:30 +01:00
for ( const auto & it1 : it - > second . exo_det )
2018-06-04 12:26:16 +02:00
output < < " struct('id', " < < symbol_table . getTypeSpecificID ( it1 . first ) + 1 < < " , 'shift', " < < it1 . second < < " ); " ;
2017-03-06 16:34:08 +01:00
output < < " ]; " < < endl ;
}
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
{
int last_tsid = - 1 ;
2019-12-20 16:59:30 +01:00
for ( const auto & it : xrefmap )
2017-03-06 16:34:08 +01:00
{
2018-06-04 12:26:16 +02:00
int tsid = symbol_table . getTypeSpecificID ( it . first . first ) + 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 ;
2019-12-16 19:42:59 +01:00
for ( const auto & it1 : it . second )
2017-03-06 16:34:08 +01:00
if ( type = = " param " )
2019-12-16 19:42:59 +01:00
output < < it1 + 1 < < " " ;
2017-03-06 16:34:08 +01:00
else
2019-12-16 19:42:59 +01:00
output < < " struct('shift', " < < it . first . second < < " , 'eq', " < < it1 + 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 ( ) ;
for ( int lag = - blocks [ blk ] . max_lag ; lag < = blocks [ blk ] . max_lead ; lag + + )
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
{
2020-04-23 16:04:02 +02:00
int nb_blocks = blocks . size ( ) ;
2020-03-19 17:46:10 +01:00
blocks_derivatives . resize ( nb_blocks ) ;
2020-04-24 12:29:02 +02:00
for ( int blk = 0 ; blk < 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 ( ) ;
// 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
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 :
d = derivatives [ 1 ] [ { eq_orig , deriv_id } ] ;
break ;
case BlockDerivativeType : : chainRule :
d = equations [ eq_orig ] - > getChainRuleDerivative ( deriv_id , recursive_vars ) ;
break ;
case BlockDerivativeType : : normalizedChainRule :
d = equation_type_and_normalized_equation [ eq_orig ] . second - > getChainRuleDerivative ( deriv_id , recursive_vars ) ;
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
}
}
}
void
2020-05-06 14:02:58 +02:00
DynamicModel : : computeBlockDynJacobianCols ( )
2009-12-16 14:21:31 +01:00
{
2020-04-23 16:04:02 +02:00
int nb_blocks = blocks . size ( ) ;
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 ) ;
// 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
{
2020-04-30 16:00:16 +02:00
int eq_orig = indices [ 0 ] ;
int block_eq = eq2block [ eq_orig ] ;
int eq = getBlockInitialEquationID ( block_eq , eq_orig ) ;
2019-12-16 19:42:59 +01:00
int var = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( indices [ 1 ] ) ) ;
int lag = getLagByDerivID ( indices [ 1 ] ) ;
switch ( getTypeByDerivID ( indices [ 1 ] ) )
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 ] )
{
int var_in_block = getBlockInitialVariableID ( block_eq , var ) ;
dynamic_endo [ block_eq ] . emplace ( lag , var_in_block ) ;
}
else
2009-12-16 18:13:23 +01:00
{
2020-04-30 16:00:16 +02:00
blocks_derivatives_other_endo [ block_eq ] [ { eq , var , lag } ] = derivatives [ 1 ] [ { eq_orig , getDerivID ( symbol_table . getID ( SymbolType : : endogenous , var ) , lag ) } ] ;
2020-05-06 14:02:58 +02:00
blocks_other_endo [ block_eq ] . insert ( var ) ;
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-04-30 16:00:16 +02:00
blocks_derivatives_exo [ block_eq ] [ { eq , var , lag } ] = derivatives [ 1 ] [ { eq_orig , getDerivID ( symbol_table . getID ( SymbolType : : exogenous , var ) , lag ) } ] ;
2020-05-06 14:02:58 +02:00
blocks_exo [ block_eq ] . insert ( var ) ;
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-04-30 16:00:16 +02:00
blocks_derivatives_exo_det [ block_eq ] [ { eq , var , lag } ] = derivatives [ 1 ] [ { eq_orig , getDerivID ( symbol_table . getID ( SymbolType : : exogenous , var ) , lag ) } ] ;
2020-05-06 14:02:58 +02:00
blocks_exo_det [ block_eq ] . insert ( var ) ;
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 ) ;
for ( int blk = 0 ; blk < nb_blocks ; blk + + )
{
int index = 0 ;
for ( auto [ lag , var ] : dynamic_endo [ blk ] )
blocks_jacob_cols_endo [ blk ] [ { var , lag } ] = index + + ;
index = 0 ;
for ( auto [ lag , var ] : dynamic_other_endo [ blk ] )
blocks_jacob_cols_other_endo [ blk ] [ { var , lag } ] = index + + ;
index = 0 ;
for ( auto [ lag , var ] : dynamic_exo [ blk ] )
blocks_jacob_cols_exo [ blk ] [ { var , lag } ] = index + + ;
index = 0 ;
for ( auto [ lag , var ] : dynamic_exo_det [ blk ] )
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 )
filesystem : : create_directories ( model_dir / " src " ) ;
2022-05-19 14:15:43 +02:00
filesystem : : create_directories ( model_dir / " bytecode " ) ;
2020-06-23 15:13:04 +02:00
2021-01-25 18:03:37 +01:00
if ( block )
2018-10-26 11:44:26 +02:00
{
2022-05-19 14:15:43 +02:00
writeDynamicBlockBytecode ( basename ) ;
if ( use_dll )
2020-06-23 15:13:04 +02:00
{
writeDynamicPerBlockCFiles ( basename ) ;
writeDynamicBlockCFile ( basename ) ;
2022-06-02 10:50:21 +02:00
vector < filesystem : : path > src_files ( blocks . size ( ) + 1 ) ;
2020-06-23 15:13:04 +02:00
for ( int blk = 0 ; blk < static_cast < int > ( blocks . size ( ) ) ; blk + + )
src_files [ blk ] = model_dir / " src " / ( " dynamic_ " + to_string ( blk + 1 ) + " .c " ) ;
src_files [ blocks . size ( ) ] = model_dir / " src " / " dynamic.c " ;
compileMEX ( basename , " dynamic " , mexext , src_files , matlabroot , dynareroot ) ;
}
else if ( julia )
{
cerr < < " 'block' option is not available with Julia " < < endl ;
exit ( EXIT_FAILURE ) ;
}
else // M-files
{
writeDynamicPerBlockMFiles ( basename ) ;
writeDynamicBlockMFile ( basename ) ;
}
2018-10-26 11:44:26 +02:00
}
2009-12-16 18:13:23 +01:00
else
2020-06-23 15:13:04 +02:00
{
2022-05-19 14:15:43 +02:00
writeDynamicBytecode ( basename ) ;
if ( use_dll )
2020-06-23 15:13:04 +02:00
{
writeDynamicCFile ( basename ) ;
compileMEX ( basename , " dynamic " , mexext , { model_dir / " src " / " dynamic.c " } ,
matlabroot , dynareroot ) ;
}
else if ( julia )
writeDynamicJuliaFile ( basename ) ;
else
writeDynamicMFile ( basename ) ;
}
2019-10-17 15:03:26 +02:00
writeSetAuxiliaryVariables ( basename , julia ) ;
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
if ( julia )
output < < " module " < < basename < < " DynamicSetAuxiliarySeries " < < endl
< < " export " < < func_name < < endl ;
output < < " function " ;
if ( ! julia )
output < < " ds = " ;
output < < func_name + " (ds, params) " < < endl
2018-03-02 17:50:35 +01:00
< < comment < < endl
< < comment < < " Status : Computes Auxiliary variables of the dynamic model and returns a dseries " < < endl
< < comment < < endl
< < comment < < " Warning : this file is generated automatically by Dynare " < < endl
< < comment < < " from model file (.mod) " < < endl < < endl
2021-04-23 17:55:28 +02:00
< < output_func_body . str ( )
< < " end " < < endl ;
if ( julia )
output < < " end " < < endl ;
2018-03-02 18:39:16 +01:00
2021-04-23 17:55:28 +02:00
writeToFileIfModified ( output , julia ? basename + " DynamicSetAuxiliarySeries.jl " : packageDir ( basename ) + " / " + func_name + " .m " ) ;
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 )
2018-07-17 18:34:07 +02:00
equation - > collectDynamicVariables ( SymbolType : : endogenous , dynvars ) ;
2009-04-17 18:26:23 +02:00
2009-09-30 17:10:31 +02:00
dynJacobianColsNbr = dynvars . size ( ) ;
2019-12-20 16:59:30 +01:00
for ( auto & equation : equations )
2009-04-17 18:26:23 +02:00
{
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 ;
}
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
2009-04-20 12:48:54 +02:00
DynamicModel : : computeDynJacobianCols ( bool jacobianExo )
2009-04-17 18:26:23 +02:00
{
/* Sort the dynamic endogenous variables by lexicographic order over (lag, type_specific_symbol_id)
and fill the dynamic columns for exogenous and exogenous deterministic */
map < pair < int , int > , int > ordered_dyn_endo ;
2022-06-02 10:50:21 +02:00
for ( auto & [ symb_lag , deriv_id ] : deriv_id_table )
2009-04-17 18:26:23 +02:00
{
2022-06-02 10:50:21 +02:00
auto & [ symb_id , lag ] = symb_lag ;
2009-04-17 18:26:23 +02:00
SymbolType type = symbol_table . getType ( symb_id ) ;
int tsid = symbol_table . getTypeSpecificID ( symb_id ) ;
2009-05-13 01:03:40 +02:00
2009-06-05 16:45:23 +02:00
switch ( type )
2009-04-17 18:26:23 +02:00
{
2018-07-17 18:34:07 +02:00
case SymbolType : : endogenous :
2018-06-04 16:36:46 +02:00
ordered_dyn_endo [ { lag , tsid } ] = deriv_id ;
2009-04-17 18:26:23 +02:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenous :
2009-04-20 12:48:54 +02:00
// At this point, dynJacobianColsNbr contains the number of dynamic endogenous
if ( jacobianExo )
dyn_jacobian_cols_table [ deriv_id ] = dynJacobianColsNbr + tsid ;
2009-04-17 18:26:23 +02:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : exogenousDet :
2009-04-20 12:48:54 +02:00
// At this point, dynJacobianColsNbr contains the number of dynamic endogenous
if ( jacobianExo )
dyn_jacobian_cols_table [ deriv_id ] = dynJacobianColsNbr + symbol_table . exo_nbr ( ) + tsid ;
2009-04-17 18:26:23 +02:00
break ;
2018-07-17 18:34:07 +02:00
case SymbolType : : parameter :
case SymbolType : : trend :
case SymbolType : : logTrend :
2010-10-15 19:05:16 +02:00
// We don't assign a dynamic jacobian column to parameters or trend variables
2009-04-20 15:58:15 +02:00
break ;
2009-04-17 18:26:23 +02:00
default :
// Shut up GCC
2009-04-20 15:58:15 +02:00
cerr < < " DynamicModel::computeDynJacobianCols: impossible case " < < endl ;
2009-04-17 18:26:23 +02:00
exit ( EXIT_FAILURE ) ;
}
}
// Fill in dynamic jacobian columns for endogenous
int sorted_id = 0 ;
2019-12-20 16:59:30 +01:00
for ( auto & it : ordered_dyn_endo )
2019-12-16 19:42:59 +01:00
dyn_jacobian_cols_table [ it . second ] = sorted_id + + ;
2009-04-20 12:48:54 +02:00
// Set final value for dynJacobianColsNbr
if ( jacobianExo )
dynJacobianColsNbr + = symbol_table . exo_nbr ( ) + symbol_table . exo_det_nbr ( ) ;
2009-04-17 18:26:23 +02:00
}
int
2018-06-04 12:50:53 +02:00
DynamicModel : : getDynJacobianCol ( int deriv_id ) const noexcept ( false )
2009-04-17 18:26:23 +02:00
{
2019-12-16 19:42:59 +01:00
if ( auto it = dyn_jacobian_cols_table . find ( deriv_id ) ;
it = = dyn_jacobian_cols_table . end ( ) )
2009-04-17 18:26:23 +02:00
throw UnknownDerivIDException ( ) ;
else
return it - > second ;
}
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 ] )
cerr < < " (line " < < * equations_lineno [ eq ] < < " ) " ;
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-20 15:58:15 +02:00
void
2015-07-28 14:59:55 +02:00
DynamicModel : : writeParamsDerivativesFile ( const string & basename , bool julia ) const
2009-12-16 18:13:23 +01:00
{
2018-11-15 16:39:53 +01:00
if ( ! params_derivatives . size ( ) )
2009-12-16 18:13:23 +01:00
return ;
2009-04-20 15:58:15 +02:00
2018-09-05 18:27:13 +02:00
ExprNodeOutputType output_type = ( julia ? ExprNodeOutputType : : juliaDynamicModel : ExprNodeOutputType : : matlabDynamicModel ) ;
2019-12-20 16:59:30 +01:00
ostringstream tt_output ; // Used for storing model temp vars and equations
ostringstream rp_output ; // 1st deriv. of residuals w.r.t. parameters
ostringstream gp_output ; // 1st deriv. of Jacobian w.r.t. parameters
ostringstream rpp_output ; // 2nd deriv of residuals w.r.t. parameters
ostringstream gpp_output ; // 2nd deriv of Jacobian w.r.t. parameters
ostringstream hp_output ; // 1st deriv. of Hessian w.r.t. parameters
ostringstream g3p_output ; // 1st deriv. of 3rd deriv. matrix w.r.t. parameters
2009-09-08 10:06:06 +02:00
2018-11-16 16:53:07 +01:00
temporary_terms_t temp_term_union ;
2011-04-12 16:41:29 +02:00
deriv_node_temp_terms_t tef_terms ;
2011-03-07 11:59:12 +01:00
2018-11-16 18:13:34 +01:00
writeModelLocalVariableTemporaryTerms ( temp_term_union , params_derivs_temporary_terms_idxs , tt_output , output_type , tef_terms ) ;
2018-11-30 12:22:13 +01:00
for ( const auto & it : params_derivs_temporary_terms )
writeTemporaryTerms ( it . second , temp_term_union , params_derivs_temporary_terms_idxs , tt_output , output_type , tef_terms ) ;
2009-09-08 10:06:06 +02:00
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d1 ] : params_derivatives . find ( { 0 , 1 } ) - > second )
2009-12-16 18:13:23 +01:00
{
2019-12-16 19:42:59 +01:00
auto [ eq , param ] = vectorToTuple < 2 > ( indices ) ;
2009-09-08 10:06:06 +02:00
2009-12-16 18:13:23 +01:00
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
2009-04-20 15:58:15 +02:00
2019-08-22 15:55:00 +02:00
rp_output < < " rp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < eq + 1 < < " , " < < param_col
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d1 - > writeOutput ( rp_output , output_type , temp_term_union , params_derivs_temporary_terms_idxs , tef_terms ) ;
rp_output < < " ; " < < endl ;
2009-12-16 18:13:23 +01:00
}
2009-04-20 15:58:15 +02:00
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d2 ] : params_derivatives . find ( { 1 , 1 } ) - > second )
2010-03-16 10:15:19 +01:00
{
2019-12-16 19:42:59 +01:00
auto [ eq , var , param ] = vectorToTuple < 3 > ( indices ) ;
2010-03-16 10:15:19 +01:00
2010-06-07 16:42:27 +02:00
int var_col = getDynJacobianCol ( var ) + 1 ;
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
2010-03-16 10:15:19 +01:00
2019-08-22 15:55:00 +02:00
gp_output < < " gp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < eq + 1 < < " , " < < var_col
< < " , " < < param_col < < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d2 - > writeOutput ( gp_output , output_type , temp_term_union , params_derivs_temporary_terms_idxs , tef_terms ) ;
gp_output < < " ; " < < endl ;
2010-03-16 10:15:19 +01:00
}
2010-06-07 18:46:57 +02:00
int i = 1 ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d2 ] : params_derivatives . find ( { 0 , 2 } ) - > second )
2009-12-16 18:13:23 +01:00
{
2019-12-16 19:42:59 +01:00
auto [ eq , param1 , param2 ] = vectorToTuple < 3 > ( indices ) ;
2009-04-20 15:58:15 +02:00
2010-06-07 16:42:27 +02:00
int param1_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param1 ) ) + 1 ;
int param2_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param2 ) ) + 1 ;
2009-04-30 15:14:33 +02:00
2019-08-22 15:55:00 +02:00
rpp_output < < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param1_col < < " ; " < < endl
< < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param2_col < < " ; " < < endl
< < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d2 - > writeOutput ( rpp_output , output_type , temp_term_union , params_derivs_temporary_terms_idxs , tef_terms ) ;
rpp_output < < " ; " < < endl ;
2018-06-05 15:34:34 +02:00
i + + ;
2018-11-22 15:41:11 +01:00
if ( param1 ! = param2 )
{
// Treat symmetric elements
2019-08-22 15:55:00 +02:00
rpp_output < < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param2_col < < " ; " < < endl
< < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param1_col < < " ; " < < endl
< < " rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " =rpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i - 1 < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " ; " < < endl ;
2018-11-22 15:41:11 +01:00
i + + ;
}
2009-12-16 18:13:23 +01:00
}
2009-07-21 17:50:12 +02:00
2010-06-07 18:46:57 +02:00
i = 1 ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d2 ] : params_derivatives . find ( { 1 , 2 } ) - > second )
2010-03-15 16:02:07 +01:00
{
2019-12-16 19:42:59 +01:00
auto [ eq , var , param1 , param2 ] = vectorToTuple < 4 > ( indices ) ;
2010-03-15 16:02:07 +01:00
int var_col = getDynJacobianCol ( var ) + 1 ;
int param1_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param1 ) ) + 1 ;
int param2_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param2 ) ) + 1 ;
2019-08-22 15:55:00 +02:00
gpp_output < < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var_col < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param1_col < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param2_col < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d2 - > writeOutput ( gpp_output , output_type , temp_term_union , params_derivs_temporary_terms_idxs , tef_terms ) ;
gpp_output < < " ; " < < endl ;
2018-06-05 15:34:34 +02:00
i + + ;
2018-11-22 15:41:11 +01:00
if ( param1 ! = param2 )
{
// Treat symmetric elements
2019-08-22 15:55:00 +02:00
gpp_output < < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var_col < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param2_col < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param1_col < < " ; " < < endl
< < " gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " =gpp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i - 1 < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " ; " < < endl ;
2018-11-22 15:41:11 +01:00
i + + ;
}
2010-03-15 16:02:07 +01:00
}
2010-03-11 16:46:19 +01:00
2010-06-07 18:46:57 +02:00
i = 1 ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d2 ] : params_derivatives . find ( { 2 , 1 } ) - > second )
2010-03-11 16:46:19 +01:00
{
2019-12-16 19:42:59 +01:00
auto [ eq , var1 , var2 , param ] = vectorToTuple < 4 > ( indices ) ;
2010-03-11 16:46:19 +01:00
int var1_col = getDynJacobianCol ( var1 ) + 1 ;
int var2_col = getDynJacobianCol ( var2 ) + 1 ;
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
2019-08-22 15:55:00 +02:00
hp_output < < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var1_col < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var2_col < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param_col < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d2 - > writeOutput ( hp_output , output_type , temp_term_union , params_derivs_temporary_terms_idxs , tef_terms ) ;
hp_output < < " ; " < < endl ;
2018-06-05 15:34:34 +02:00
i + + ;
2018-11-22 17:49:47 +01:00
if ( var1 ! = var2 )
{
// Treat symmetric elements
2019-08-22 15:55:00 +02:00
hp_output < < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var2_col < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var1_col < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param_col < < " ; " < < endl
< < " hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type )
< < " =hp " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i - 1 < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " ; " < < endl ;
2018-11-22 17:49:47 +01:00
i + + ;
}
2010-03-11 16:46:19 +01:00
}
2019-08-22 17:00:36 +02:00
i = 1 ;
2019-12-16 19:42:59 +01:00
for ( const auto & [ indices , d2 ] : params_derivatives . find ( { 3 , 1 } ) - > second )
2019-08-22 17:00:36 +02:00
{
2019-12-16 19:42:59 +01:00
auto [ eq , var1 , var2 , var3 , param ] = vectorToTuple < 5 > ( indices ) ;
2019-08-22 17:00:36 +02:00
int var1_col = getDynJacobianCol ( var1 ) + 1 ;
int var2_col = getDynJacobianCol ( var2 ) + 1 ;
int var3_col = getDynJacobianCol ( var3 ) + 1 ;
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
g3p_output < < " g3p " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,1 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < eq + 1 < < " ; " < < endl
< < " g3p " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,2 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var1_col < < " ; " < < endl
< < " g3p " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,3 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var2_col < < " ; " < < endl
< < " g3p " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,4 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < var3_col < < " ; " < < endl
< < " g3p " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,5 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " < < param_col < < " ; " < < endl
< < " g3p " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < i < < " ,6 "
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < " = " ;
d2 - > writeOutput ( g3p_output , output_type , temp_term_union , params_derivs_temporary_terms_idxs , tef_terms ) ;
g3p_output < < " ; " < < endl ;
i + + ;
}
2018-06-27 15:01:31 +02:00
string filename = julia ? basename + " DynamicParamsDerivs.jl " : packageDir ( basename ) + " /dynamic_params_derivs.m " ;
2017-01-05 17:31:48 +01:00
ofstream paramsDerivsFile ;
2018-06-27 15:12:12 +02:00
paramsDerivsFile . open ( filename , ios : : out | ios : : binary ) ;
2017-01-05 17:31:48 +01:00
if ( ! paramsDerivsFile . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( ! julia )
{
// Check that we don't have more than 32 nested parenthesis because Matlab does not suppor this. See Issue #1201
map < string , string > tmp_paren_vars ;
bool message_printed = false ;
2018-11-16 18:13:34 +01:00
fixNestedParenthesis ( tt_output , tmp_paren_vars , message_printed ) ;
2019-08-22 15:55:00 +02:00
fixNestedParenthesis ( rp_output , tmp_paren_vars , message_printed ) ;
fixNestedParenthesis ( gp_output , tmp_paren_vars , message_printed ) ;
fixNestedParenthesis ( rpp_output , tmp_paren_vars , message_printed ) ;
fixNestedParenthesis ( gpp_output , tmp_paren_vars , message_printed ) ;
fixNestedParenthesis ( hp_output , tmp_paren_vars , message_printed ) ;
2019-08-22 17:00:36 +02:00
fixNestedParenthesis ( g3p_output , tmp_paren_vars , message_printed ) ;
paramsDerivsFile < < " function [rp, gp, rpp, gpp, hp, g3p] = dynamic_params_derivs(y, x, params, steady_state, it_, ss_param_deriv, ss_param_2nd_deriv) " < < endl
2017-01-05 17:31:48 +01:00
< < " % " < < endl
< < " % Compute the derivatives of the dynamic model with respect to the parameters " < < endl
< < " % Inputs : " < < 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
< < " % params [M_.param_nbr by 1] double vector of parameter values in declaration order " < < endl
< < " % steady_state [M_.endo_nbr by 1] double vector of steady state values " < < endl
< < " % it_ scalar double time period for exogenous variables for which to evaluate the model " < < endl
< < " % ss_param_deriv [M_.eq_nbr by #params] Jacobian matrix of the steady states values with respect to the parameters " < < endl
< < " % ss_param_2nd_deriv [M_.eq_nbr by #params by #params] Hessian matrix of the steady states values with respect to the parameters " < < endl
< < " % " < < endl
< < " % Outputs: " < < endl
< < " % rp [M_.eq_nbr by #params] double Jacobian matrix of dynamic model equations with respect to parameters " < < endl
< < " % Dynare may prepend or append auxiliary equations, see M_.aux_vars " < < endl
< < " % gp [M_.endo_nbr by #dynamic variables by #params] double Derivative of the Jacobian matrix of the dynamic model equations with respect to the parameters " < < endl
< < " % rows: equations in order of declaration " < < endl
< < " % columns: variables in order stored in M_.lead_lag_incidence " < < endl
< < " % rpp [#second_order_residual_terms by 4] double Hessian matrix of second derivatives of residuals with respect to parameters; " < < endl
< < " % rows: respective derivative term " < < endl
< < " % 1st column: equation number of the term appearing " < < endl
< < " % 2nd column: number of the first parameter in derivative " < < endl
< < " % 3rd column: number of the second parameter in derivative " < < endl
< < " % 4th column: value of the Hessian term " < < endl
< < " % gpp [#second_order_Jacobian_terms by 5] double Hessian matrix of second derivatives of the Jacobian with respect to the parameters; " < < endl
< < " % rows: respective derivative term " < < endl
< < " % 1st column: equation number of the term appearing " < < endl
< < " % 2nd column: column number of variable in Jacobian of the dynamic model " < < endl
< < " % 3rd column: number of the first parameter in derivative " < < endl
< < " % 4th column: number of the second parameter in derivative " < < endl
< < " % 5th column: value of the Hessian term " < < endl
< < " % hp [#first_order_Hessian_terms by 5] double Jacobian matrix of derivatives of the dynamic Hessian with respect to the parameters; " < < endl
< < " % rows: respective derivative term " < < endl
< < " % 1st column: equation number of the term appearing " < < endl
< < " % 2nd column: column number of first variable in Hessian of the dynamic model " < < endl
< < " % 3rd column: column number of second variable in Hessian of the dynamic model " < < endl
< < " % 4th column: number of the parameter in derivative " < < endl
< < " % 5th column: value of the Hessian term " < < endl
2019-08-22 17:00:36 +02:00
< < " % g3p [#first_order_g3_terms by 6] double Jacobian matrix of derivatives of g3 (dynamic 3rd derivs) with respect to the parameters; " < < endl
< < " % rows: respective derivative term " < < endl
< < " % 1st column: equation number of the term appearing " < < endl
< < " % 2nd column: column number of first variable in g3 of the dynamic model " < < endl
< < " % 3rd column: column number of second variable in g3 of the dynamic model " < < endl
< < " % 4th column: column number of third variable in g3 of the dynamic model " < < endl
< < " % 5th column: number of the parameter in derivative " < < endl
< < " % 6th column: value of the Hessian term " < < endl
2017-01-05 17:31:48 +01:00
< < " % " < < endl
< < " % " < < endl
< < " % Warning : this file is generated automatically by Dynare " < < endl
< < " % from model file (.mod) " < < endl < < endl
2018-05-28 15:23:15 +02:00
< < " T = NaN( " < < params_derivs_temporary_terms_idxs . size ( ) < < " ,1); " < < endl
2018-11-16 18:13:34 +01:00
< < tt_output . str ( )
2017-02-24 11:20:54 +01:00
< < " rp = zeros( " < < equations . size ( ) < < " , "
2017-01-05 17:31:48 +01:00
< < symbol_table . param_nbr ( ) < < " ); " < < endl
2019-08-22 15:55:00 +02:00
< < rp_output . str ( )
2017-02-24 11:20:54 +01:00
< < " gp = zeros( " < < equations . size ( ) < < " , " < < dynJacobianColsNbr < < " , " < < symbol_table . param_nbr ( ) < < " ); " < < endl
2019-08-22 15:55:00 +02:00
< < gp_output . str ( )
2017-01-05 17:31:48 +01:00
< < " if nargout >= 3 " < < endl
2018-11-15 16:39:53 +01:00
< < " rpp = zeros( " < < params_derivatives . find ( { 0 , 2 } ) - > second . size ( ) < < " ,4); " < < endl
2019-08-22 15:55:00 +02:00
< < rpp_output . str ( )
2018-11-15 16:39:53 +01:00
< < " gpp = zeros( " < < params_derivatives . find ( { 1 , 2 } ) - > second . size ( ) < < " ,5); " < < endl
2019-08-22 15:55:00 +02:00
< < gpp_output . str ( )
2017-01-05 17:31:48 +01:00
< < " end " < < endl
< < " if nargout >= 5 " < < endl
2018-11-15 16:39:53 +01:00
< < " hp = zeros( " < < params_derivatives . find ( { 2 , 1 } ) - > second . size ( ) < < " ,5); " < < endl
2019-08-22 15:55:00 +02:00
< < hp_output . str ( )
2017-01-05 17:31:48 +01:00
< < " end " < < endl
2019-08-22 17:00:36 +02:00
< < " if nargout >= 6 " < < endl
< < " g3p = zeros( " < < params_derivatives . find ( { 3 , 1 } ) - > second . size ( ) < < " ,6); " < < endl
< < g3p_output . str ( )
< < " end " < < endl
2017-01-05 17:31:48 +01:00
< < " end " < < endl ;
}
else
paramsDerivsFile < < " module " < < basename < < " DynamicParamsDerivs " < < endl
< < " # " < < endl
< < " # NB: this file was automatically generated by Dynare " < < endl
< < " # from " < < basename < < " .mod " < < endl
< < " # " < < endl
< < " export params_derivs " < < endl < < endl
< < " function params_derivs(y, x, paramssteady_state, it_, "
< < " ss_param_deriv, ss_param_2nd_deriv) " < < endl
2018-11-16 18:13:34 +01:00
< < tt_output . str ( )
2017-02-24 11:20:54 +01:00
< < " rp = zeros( " < < equations . size ( ) < < " , "
2017-01-05 17:31:48 +01:00
< < symbol_table . param_nbr ( ) < < " ); " < < endl
2019-08-22 15:55:00 +02:00
< < rp_output . str ( )
2017-02-24 11:20:54 +01:00
< < " gp = zeros( " < < equations . size ( ) < < " , " < < dynJacobianColsNbr < < " , " < < symbol_table . param_nbr ( ) < < " ); " < < endl
2019-08-22 15:55:00 +02:00
< < gp_output . str ( )
2018-11-15 16:39:53 +01:00
< < " rpp = zeros( " < < params_derivatives . find ( { 0 , 2 } ) - > second . size ( ) < < " ,4); " < < endl
2019-08-22 15:55:00 +02:00
< < rpp_output . str ( )
2018-11-15 16:39:53 +01:00
< < " gpp = zeros( " < < params_derivatives . find ( { 1 , 2 } ) - > second . size ( ) < < " ,5); " < < endl
2019-08-22 15:55:00 +02:00
< < gpp_output . str ( )
2018-11-15 16:39:53 +01:00
< < " hp = zeros( " < < params_derivatives . find ( { 2 , 1 } ) - > second . size ( ) < < " ,5); " < < endl
2019-08-22 15:55:00 +02:00
< < hp_output . str ( )
2019-08-22 17:00:36 +02:00
< < " g3p = zeros( " < < params_derivatives . find ( { 3 , 1 } ) - > second . size ( ) < < " ,6); " < < endl
< < g3p_output . str ( )
< < " (rp, gp, rpp, gpp, hp, g3p) " < < endl
2017-01-05 17:31:48 +01:00
< < " end " < < endl
< < " end " < < endl ;
2009-12-16 18:13:23 +01:00
paramsDerivsFile . close ( ) ;
}
2009-07-21 17:50:12 +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
{
2018-06-04 12:26:16 +02:00
const expr_t value = local_variables_table . find ( used_local_var ) - > second ;
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 ;
2018-06-05 18:38:53 +02:00
int i = 0 ;
2019-12-20 16:59:30 +01:00
for ( 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-01-20 16:15:43 +01:00
return substituteUnaryOps ( set < int > ( 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
try
{
int eqn = equation_tags . getEqnByTag ( " name " , eq_tags . at ( " name " ) ) ;
BinaryOpNode * orig_eq = equations [ eqn ] ;
/* 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 ” */
equations [ eqn ] = AddEqual ( AddPlus ( AddMinus ( orig_eq - > arg1 , orig_eq - > arg2 ) , term ) , Zero ) ;
// It’ s unclear how to update lineno and tags, so don’ t do it
}
catch ( EquationTags : : TagNotFoundException & e )
{
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 ( ) )
{
try
{
/* 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 ” */
int eqn = static_only_equations_equation_tags . getEqnByTag ( " name " , eq_tags . at ( " name " ) ) ;
BinaryOpNode * orig_eq = static_only_equations [ eqn ] ;
static_only_equations [ eqn ] = AddEqual ( AddPlus ( AddMinus ( orig_eq - > arg1 , orig_eq - > arg2 ) , basic_term ) , Zero ) ;
// It’ s unclear how to update lineno and tags, so don’ t do it
}
catch ( EquationTags : : TagNotFoundException & e )
{
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
2018-09-25 19:15:22 +02:00
DynamicModel : : isChecksumMatching ( const string & basename , bool block ) 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
2020-06-17 16:49:12 +02:00
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 ;
writeModelLocalVariableTemporaryTerms ( temp_term_union , temporary_terms_idxs ,
buffer , buffer_type , tef_terms ) ;
2015-05-10 18:16:11 +02:00
2019-10-07 15:57:19 +02:00
writeTemporaryTerms ( temporary_terms_derivatives [ 0 ] ,
temp_term_union , temporary_terms_idxs ,
buffer , buffer_type , tef_terms ) ;
2015-05-10 18:16:11 +02:00
2019-10-07 15:57:19 +02:00
writeModelEquations ( buffer , buffer_type , 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
{
2019-10-07 15:20:07 +02:00
cerr < < " ERROR: Can't open file " < < filename < < endl ;
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 ) ;
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 ;
2020-12-09 16:45:30 +01:00
for ( auto it = variableMapping . begin ( ) ; it ! = variableMapping . end ( ) ; + + it )
{
if ( it ! = variableMapping . begin ( ) )
output < < " , " ;
auto [ var , eqs ] = * it ;
output < < R " ({ " name " : " ) " << symbol_table.getName(var) << R " ( " , " equations " :[) " ;
bool first_eq = true ;
2021-02-10 16:48:46 +01:00
for ( int it2 : eqs )
if ( auto tmp = equation_tags . getTagValueByEqnAndKey ( it2 , " name " ) ;
2020-12-09 16:45:30 +01:00
! tmp . empty ( ) )
{
if ( first_eq )
first_eq = false ;
else
output < < " , " ;
output < < ' " ' < < tmp < < ' " ' ;
}
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-01 21:57:04 +02:00
for ( auto it = xrefmap . begin ( ) ; it ! = xrefmap . end ( ) ; + + it )
2017-03-10 17:23:35 +01:00
{
2022-06-01 21:57:04 +02:00
if ( it ! = xrefmap . begin ( ) )
2017-03-10 17:23:35 +01:00
output < < " , " ;
2019-04-03 16:32:52 +02:00
output < < R " ({ " name " : " ) " << symbol_table.getName(it->first.first) << R " ( " ) "
< < R " (, " shift " : ) " < < it - > first . second
< < R " (, " equations " : [) " ;
2019-12-16 19:42:59 +01:00
for ( auto it1 = it - > second . begin ( ) ; it1 ! = it - > second . end ( ) ; + + it1 )
2017-03-10 17:23:35 +01:00
{
if ( it1 ! = it - > second . begin ( ) )
output < < " , " ;
output < < * it1 + 1 ;
}
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 ) ;
2017-06-28 17:11:24 +02:00
output < < " " < < getDynJacobianCol ( varID ) + 1 ;
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
{
2019-12-20 16:59:30 +01:00
ostringstream model_local_vars_output ; // Used for storing model local vars
vector < ostringstream > d_output ( derivatives . size ( ) ) ; // Derivatives output (at all orders, including 0=residual)
2017-02-20 12:18:11 +01:00
deriv_node_temp_terms_t tef_terms ;
2019-04-18 14:34:48 +02:00
temporary_terms_t temp_term_union ;
2017-02-20 12:18:11 +01:00
2020-06-05 16:07:52 +02:00
writeJsonModelLocalVariables ( model_local_vars_output , true , tef_terms ) ;
2017-02-20 12:18:11 +01:00
2019-04-18 17:07:55 +02:00
writeJsonTemporaryTerms ( temporary_terms_derivatives [ 0 ] , temp_term_union , d_output [ 0 ] , tef_terms , " " ) ;
d_output [ 0 ] < < " , " ;
writeJsonModelEquations ( d_output [ 0 ] , true ) ;
2017-02-20 12:18:11 +01:00
2019-04-18 17:07:55 +02:00
int ncols = dynJacobianColsNbr ;
for ( size_t i = 1 ; i < derivatives . size ( ) ; i + + )
{
string matrix_name = i = = 1 ? " jacobian " : i = = 2 ? " hessian " : i = = 3 ? " third_derivative " : to_string ( i ) + " th_derivative " ;
writeJsonTemporaryTerms ( temporary_terms_derivatives [ i ] , temp_term_union , d_output [ i ] , tef_terms , matrix_name ) ;
temp_term_union . insert ( temporary_terms_derivatives [ i ] . begin ( ) , temporary_terms_derivatives [ i ] . end ( ) ) ;
d_output [ i ] < < R " (, " ) " << matrix_name << R " ( " : {) "
2019-04-03 16:32:52 +02:00
< < R " ( " nrows " : ) " < < equations . size ( )
2019-04-18 17:07:55 +02:00
< < R " (, " ncols " : ) " < < ncols
2019-04-03 16:32:52 +02:00
< < R " (, " entries " : [) " ;
2017-02-20 12:18:11 +01:00
2019-04-18 17:07:55 +02:00
for ( auto it = derivatives [ i ] . begin ( ) ; it ! = derivatives [ i ] . end ( ) ; + + it )
{
if ( it ! = derivatives [ i ] . begin ( ) )
d_output [ i ] < < " , " ;
2017-02-20 12:18:11 +01:00
2019-04-18 17:07:55 +02:00
const vector < int > & vidx = it - > first ;
expr_t d = it - > second ;
int eq = vidx [ 0 ] ;
2017-06-29 12:42:28 +02:00
2019-04-18 17:07:55 +02:00
int col_idx = 0 ;
for ( size_t j = 1 ; j < vidx . size ( ) ; j + + )
{
col_idx * = dynJacobianColsNbr ;
col_idx + = getDynJacobianCol ( vidx [ j ] ) ;
}
2017-06-29 12:42:28 +02:00
2019-04-18 17:07:55 +02:00
if ( writeDetails )
d_output [ i ] < < R " ({ " eq " : ) " < < eq + 1 ;
else
d_output [ i ] < < R " ({ " row " : ) " < < eq + 1 ;
2017-06-29 12:42:28 +02:00
2019-04-18 17:07:55 +02:00
d_output [ i ] < < R " (, " col " : ) " < < ( i > 1 ? " [ " : " " ) < < col_idx + 1 ;
if ( i = = 2 & & vidx [ 1 ] ! = vidx [ 2 ] ) // Symmetric elements in hessian
{
int col_idx_sym = getDynJacobianCol ( vidx [ 2 ] ) * dynJacobianColsNbr + getDynJacobianCol ( vidx [ 1 ] ) ;
d_output [ i ] < < " , " < < col_idx_sym + 1 ;
}
if ( i > 1 )
d_output [ i ] < < " ] " ;
if ( writeDetails )
for ( size_t j = 1 ; j < vidx . size ( ) ; j + + )
d_output [ i ] < < R " (, " var ) " << (i > 1 ? to_string(j) : " " ) << R " ( " : " ) " << symbol_table.getName(getSymbIDByDerivID(vidx[j])) << R " ( " ) "
2019-12-20 16:59:30 +01:00
< < R " (, " shift ) " << (i > 1 ? to_string(j) : " " ) << R " ( " : ) " < < getLagByDerivID ( vidx [ j ] ) ;
2019-04-18 17:07:55 +02:00
d_output [ i ] < < R " (, " val " : " ) " ;
d - > writeJsonOutput ( d_output [ i ] , temp_term_union , tef_terms ) ;
d_output [ i ] < < R " ( " } ) " << endl;
2017-03-02 18:34:18 +01:00
}
2019-12-20 16:59:30 +01:00
d_output [ i ] < < " ]} " ;
2019-04-18 17:07:55 +02:00
2019-12-20 16:59:30 +01:00
ncols * = dynJacobianColsNbr ;
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 " : {) " ;
2019-04-18 17:07:55 +02:00
output < < model_local_vars_output . str ( ) ;
for ( const auto & it : d_output )
output < < " , " < < it . str ( ) ;
output < < " } " ;
2017-02-20 12:18:11 +01:00
}
void
2017-03-02 18:34:18 +01:00
DynamicModel : : writeJsonParamsDerivativesFile ( 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 ;
2019-12-20 16:59:30 +01:00
ostringstream model_local_vars_output ; // Used for storing model local vars
ostringstream model_output ; // Used for storing model temp vars and equations
ostringstream rp_output ; // 1st deriv. of residuals w.r.t. parameters
ostringstream gp_output ; // 1st deriv. of Jacobian w.r.t. parameters
ostringstream rpp_output ; // 2nd deriv of residuals w.r.t. parameters
ostringstream gpp_output ; // 2nd deriv of Jacobian w.r.t. parameters
ostringstream hp_output ; // 1st deriv. of Hessian w.r.t. parameters
ostringstream g3p_output ; // 1st deriv. of 3rd deriv. matrix w.r.t. parameters
2017-02-20 12:18:11 +01:00
deriv_node_temp_terms_t tef_terms ;
2020-06-05 16:07:52 +02:00
writeJsonModelLocalVariables ( model_local_vars_output , true , tef_terms ) ;
2017-02-20 12:18:11 +01:00
2018-11-16 18:24:06 +01:00
temporary_terms_t temp_term_union ;
2018-11-30 12:22:13 +01:00
for ( const auto & it : params_derivs_temporary_terms )
2019-04-18 14:34:48 +02:00
writeJsonTemporaryTerms ( it . second , temp_term_union , model_output , tef_terms , " all " ) ;
2018-11-16 18:24:06 +01:00
2019-08-22 15:55:00 +02:00
rp_output < < R " ( " deriv_wrt_params " : {) "
< < R " ( " neqs " : ) " < < equations . size ( )
< < R " (, " nparamcols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " entries " : [) " ;
2018-11-15 16:39:53 +01:00
auto & rp = params_derivatives . find ( { 0 , 1 } ) - > second ;
2019-12-16 19:42:59 +01:00
for ( auto it = rp . begin ( ) ; it ! = rp . end ( ) ; + + it )
2017-02-20 12:18:11 +01:00
{
2018-11-15 16:39:53 +01:00
if ( it ! = rp . begin ( ) )
2019-08-22 15:55:00 +02:00
rp_output < < " , " ;
2017-02-20 12:18:11 +01:00
2019-09-11 15:59:23 +02:00
auto [ eq , param ] = vectorToTuple < 2 > ( it - > first ) ;
2017-02-20 12:18:11 +01:00
expr_t d1 = it - > second ;
2017-03-02 18:34:18 +01:00
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
if ( writeDetails )
2019-08-22 15:55:00 +02:00
rp_output < < R " ({ " eq " : ) " < < eq + 1 ;
2017-03-02 18:34:18 +01:00
else
2019-08-22 15:55:00 +02:00
rp_output < < R " ({ " row " : ) " < < eq + 1 ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
rp_output < < R " (, " param_col " : ) " < < param_col + 1 ;
2017-06-29 12:42:28 +02:00
if ( writeDetails )
2019-08-22 15:55:00 +02:00
rp_output < < R " (, " param " : " ) " << symbol_table.getName(getSymbIDByDerivID(param)) << R " ( " ) " ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
rp_output < < R " (, " val " : " ) " ;
d1 - > writeJsonOutput ( rp_output , temp_term_union , tef_terms ) ;
rp_output < < R " ( " } ) " << endl;
2017-02-20 12:18:11 +01:00
}
2019-08-22 15:55:00 +02:00
rp_output < < " ]} " ;
2018-11-15 16:39:53 +01:00
2019-08-22 15:55:00 +02:00
gp_output < < R " ( " deriv_jacobian_wrt_params " : {) "
< < R " ( " neqs " : ) " < < equations . size ( )
< < R " (, " nvarcols " : ) " < < dynJacobianColsNbr
< < R " (, " nparamcols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " entries " : [) " ;
2018-11-15 16:39:53 +01:00
auto & gp = params_derivatives . find ( { 1 , 1 } ) - > second ;
2019-12-16 19:42:59 +01:00
for ( auto it = gp . begin ( ) ; it ! = gp . end ( ) ; + + it )
2017-02-20 12:18:11 +01:00
{
2018-11-15 16:39:53 +01:00
if ( it ! = gp . begin ( ) )
2019-08-22 15:55:00 +02:00
gp_output < < " , " ;
2017-02-20 12:18:11 +01:00
2019-09-11 15:59:23 +02:00
auto [ eq , var , param ] = vectorToTuple < 3 > ( it - > first ) ;
2017-02-20 12:18:11 +01:00
expr_t d2 = it - > second ;
2017-03-02 18:34:18 +01:00
int var_col = getDynJacobianCol ( var ) + 1 ;
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
if ( writeDetails )
2019-08-22 15:55:00 +02:00
gp_output < < R " ({ " eq " : ) " < < eq + 1 ;
2017-03-02 18:34:18 +01:00
else
2019-08-22 15:55:00 +02:00
gp_output < < R " ({ " row " : ) " < < eq + 1 ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
gp_output < < R " (, " var_col " : ) " < < var_col + 1
< < R " (, " param_col " : ) " < < param_col + 1 ;
2017-06-29 12:42:28 +02:00
if ( writeDetails )
2019-08-22 15:55:00 +02:00
gp_output < < R " (, " var " : " ) " << symbol_table.getName(getSymbIDByDerivID(var)) << R " ( " ) "
< < R " (, " lag " : ) " < < getLagByDerivID ( var )
< < R " (, " param " : " ) " << symbol_table.getName(getSymbIDByDerivID(param)) << R " ( " ) " ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
gp_output < < R " (, " val " : " ) " ;
d2 - > writeJsonOutput ( gp_output , temp_term_union , tef_terms ) ;
gp_output < < R " ( " } ) " << endl;
2017-02-20 12:18:11 +01:00
}
2019-08-22 15:55:00 +02:00
gp_output < < " ]} " ;
2017-02-20 12:18:11 +01:00
2019-08-22 15:55:00 +02:00
rpp_output < < R " ( " second_deriv_residuals_wrt_params " : {) "
< < R " ( " nrows " : ) " < < equations . size ( )
< < R " (, " nparam1cols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " nparam2cols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " entries " : [) " ;
2018-11-15 16:39:53 +01:00
auto & rpp = params_derivatives . find ( { 0 , 2 } ) - > second ;
for ( auto it = rpp . begin ( ) ; it ! = rpp . end ( ) ; + + it )
2017-02-20 12:18:11 +01:00
{
2018-11-15 16:39:53 +01:00
if ( it ! = rpp . begin ( ) )
2019-08-22 15:55:00 +02:00
rpp_output < < " , " ;
2017-02-20 12:18:11 +01:00
2019-09-11 15:59:23 +02:00
auto [ eq , param1 , param2 ] = vectorToTuple < 3 > ( it - > first ) ;
2017-02-20 12:18:11 +01:00
expr_t d2 = it - > second ;
2017-03-02 18:34:18 +01:00
int param1_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param1 ) ) + 1 ;
int param2_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param2 ) ) + 1 ;
if ( writeDetails )
2019-08-22 15:55:00 +02:00
rpp_output < < R " ({ " eq " : ) " < < eq + 1 ;
2017-03-02 18:34:18 +01:00
else
2019-08-22 15:55:00 +02:00
rpp_output < < R " ({ " row " : ) " < < eq + 1 ;
rpp_output < < R " (, " param1_col " : ) " < < param1_col + 1
< < R " (, " param2_col " : ) " < < param2_col + 1 ;
2017-06-29 12:42:28 +02:00
if ( writeDetails )
2019-08-22 15:55:00 +02:00
rpp_output < < R " (, " param1 " : " ) " << symbol_table.getName(getSymbIDByDerivID(param1)) << R " ( " ) "
< < R " (, " param2 " : " ) " << symbol_table.getName(getSymbIDByDerivID(param2)) << R " ( " ) " ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
rpp_output < < R " (, " val " : " ) " ;
d2 - > writeJsonOutput ( rpp_output , temp_term_union , tef_terms ) ;
rpp_output < < R " ( " } ) " << endl;
2017-02-20 12:18:11 +01:00
}
2019-08-22 15:55:00 +02:00
rpp_output < < " ]} " ;
2018-11-15 16:39:53 +01:00
2019-08-22 15:55:00 +02:00
gpp_output < < R " ( " second_deriv_jacobian_wrt_params " : {) "
< < R " ( " neqs " : ) " < < equations . size ( )
< < R " (, " nvarcols " : ) " < < dynJacobianColsNbr
< < R " (, " nparam1cols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " nparam2cols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " entries " : [) " ;
2018-11-15 16:39:53 +01:00
auto & gpp = params_derivatives . find ( { 1 , 2 } ) - > second ;
for ( auto it = gpp . begin ( ) ; it ! = gpp . end ( ) ; + + it )
2017-02-20 12:18:11 +01:00
{
2018-11-15 16:39:53 +01:00
if ( it ! = gpp . begin ( ) )
2019-08-22 15:55:00 +02:00
gpp_output < < " , " ;
2017-02-20 12:18:11 +01:00
2019-09-11 15:59:23 +02:00
auto [ eq , var , param1 , param2 ] = vectorToTuple < 4 > ( it - > first ) ;
2017-02-20 12:18:11 +01:00
expr_t d2 = it - > second ;
2017-03-02 18:34:18 +01:00
int var_col = getDynJacobianCol ( var ) + 1 ;
int param1_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param1 ) ) + 1 ;
int param2_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param2 ) ) + 1 ;
if ( writeDetails )
2019-08-22 15:55:00 +02:00
gpp_output < < R " ({ " eq " : ) " < < eq + 1 ;
2017-03-02 18:34:18 +01:00
else
2019-08-22 15:55:00 +02:00
gpp_output < < R " ({ " row " : ) " < < eq + 1 ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
gpp_output < < R " (, " var_col " : ) " < < var_col + 1
< < R " (, " param1_col " : ) " < < param1_col + 1
< < R " (, " param2_col " : ) " < < param2_col + 1 ;
2017-06-29 12:42:28 +02:00
if ( writeDetails )
2019-08-22 15:55:00 +02:00
gpp_output < < R " (, " var " : " ) " << symbol_table.getName(var) << R " ( " ) "
< < R " (, " lag " : ) " < < getLagByDerivID ( var )
< < R " (, " param1 " : " ) " << symbol_table.getName(getSymbIDByDerivID(param1)) << R " ( " ) "
< < R " (, " param2 " : " ) " << symbol_table.getName(getSymbIDByDerivID(param2)) << R " ( " ) " ;
gpp_output < < R " (, " val " : " ) " ;
d2 - > writeJsonOutput ( gpp_output , temp_term_union , tef_terms ) ;
gpp_output < < R " ( " } ) " << endl;
}
gpp_output < < " ]} " < < endl ;
hp_output < < R " ( " derivative_hessian_wrt_params " : {) "
< < R " ( " neqs " : ) " < < equations . size ( )
< < R " (, " nvar1cols " : ) " < < dynJacobianColsNbr
< < R " (, " nvar2cols " : ) " < < dynJacobianColsNbr
< < R " (, " nparamcols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " entries " : [) " ;
2018-11-15 16:39:53 +01:00
auto & hp = params_derivatives . find ( { 2 , 1 } ) - > second ;
for ( auto it = hp . begin ( ) ; it ! = hp . end ( ) ; + + it )
2017-02-20 12:18:11 +01:00
{
2018-11-15 16:39:53 +01:00
if ( it ! = hp . begin ( ) )
2019-08-22 15:55:00 +02:00
hp_output < < " , " ;
2017-02-20 12:18:11 +01:00
2019-09-11 15:59:23 +02:00
auto [ eq , var1 , var2 , param ] = vectorToTuple < 4 > ( it - > first ) ;
2017-02-20 12:18:11 +01:00
expr_t d2 = it - > second ;
2017-03-02 18:34:18 +01:00
int var1_col = getDynJacobianCol ( var1 ) + 1 ;
int var2_col = getDynJacobianCol ( var2 ) + 1 ;
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
if ( writeDetails )
2019-08-22 15:55:00 +02:00
hp_output < < R " ({ " eq " : ) " < < eq + 1 ;
2017-03-02 18:34:18 +01:00
else
2019-08-22 15:55:00 +02:00
hp_output < < R " ({ " row " : ) " < < eq + 1 ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
hp_output < < R " (, " var1_col " : ) " < < var1_col + 1
< < R " (, " var2_col " : ) " < < var2_col + 1
< < R " (, " param_col " : ) " < < param_col + 1 ;
2017-06-29 12:42:28 +02:00
if ( writeDetails )
2019-08-22 15:55:00 +02:00
hp_output < < R " (, " var1 " : " ) " << symbol_table.getName(getSymbIDByDerivID(var1)) << R " ( " ) "
< < R " (, " lag1 " : ) " < < getLagByDerivID ( var1 )
< < R " (, " var2 " : " ) " << symbol_table.getName(getSymbIDByDerivID(var2)) << R " ( " ) "
< < R " (, " lag2 " : ) " < < getLagByDerivID ( var2 )
< < R " (, " param " : " ) " << symbol_table.getName(getSymbIDByDerivID(param)) << R " ( " ) " ;
2017-06-29 12:42:28 +02:00
2019-08-22 15:55:00 +02:00
hp_output < < R " (, " val " : " ) " ;
d2 - > writeJsonOutput ( hp_output , temp_term_union , tef_terms ) ;
hp_output < < R " ( " } ) " << endl;
2017-02-20 12:18:11 +01:00
}
2019-08-22 15:55:00 +02:00
hp_output < < " ]} " < < endl ;
2017-02-20 12:18:11 +01:00
2019-08-22 17:00:36 +02:00
g3p_output < < R " ( " derivative_g3_wrt_params " : {) "
< < R " ( " neqs " : ) " < < equations . size ( )
< < R " (, " nvar1cols " : ) " < < dynJacobianColsNbr
< < R " (, " nvar2cols " : ) " < < dynJacobianColsNbr
< < R " (, " nvar3cols " : ) " < < dynJacobianColsNbr
< < R " (, " nparamcols " : ) " < < symbol_table . param_nbr ( )
< < R " (, " entries " : [) " ;
auto & g3p = params_derivatives . find ( { 3 , 1 } ) - > second ;
for ( auto it = g3p . begin ( ) ; it ! = g3p . end ( ) ; + + it )
{
if ( it ! = g3p . begin ( ) )
g3p_output < < " , " ;
2019-09-11 15:59:23 +02:00
auto [ eq , var1 , var2 , var3 , param ] = vectorToTuple < 5 > ( it - > first ) ;
2019-08-22 17:00:36 +02:00
expr_t d2 = it - > second ;
int var1_col = getDynJacobianCol ( var1 ) + 1 ;
int var2_col = getDynJacobianCol ( var2 ) + 1 ;
int var3_col = getDynJacobianCol ( var3 ) + 1 ;
int param_col = symbol_table . getTypeSpecificID ( getSymbIDByDerivID ( param ) ) + 1 ;
if ( writeDetails )
g3p_output < < R " ({ " eq " : ) " < < eq + 1 ;
else
g3p_output < < R " ({ " row " : ) " < < eq + 1 ;
g3p_output < < R " (, " var1_col " : ) " < < var1_col + 1
< < R " (, " var2_col " : ) " < < var2_col + 1
< < R " (, " var3_col " : ) " < < var3_col + 1
< < R " (, " param_col " : ) " < < param_col + 1 ;
if ( writeDetails )
g3p_output < < R " (, " var1 " : " ) " << symbol_table.getName(getSymbIDByDerivID(var1)) << R " ( " ) "
< < R " (, " lag1 " : ) " < < getLagByDerivID ( var1 )
< < R " (, " var2 " : " ) " << symbol_table.getName(getSymbIDByDerivID(var2)) << R " ( " ) "
< < R " (, " lag2 " : ) " < < getLagByDerivID ( var2 )
< < R " (, " var3 " : " ) " << symbol_table.getName(getSymbIDByDerivID(var3)) << R " ( " ) "
< < R " (, " lag3 " : ) " < < getLagByDerivID ( var3 )
< < R " (, " param " : " ) " << symbol_table.getName(getSymbIDByDerivID(param)) << R " ( " ) " ;
g3p_output < < R " (, " val " : " ) " ;
d2 - > writeJsonOutput ( g3p_output , temp_term_union , tef_terms ) ;
g3p_output < < R " ( " } ) " << endl;
}
g3p_output < < " ]} " < < endl ;
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 " : {) " ;
2017-03-02 18:34:18 +01:00
output < < model_local_vars_output . str ( )
2017-02-20 12:18:11 +01:00
< < " , " < < model_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 ( ) )
{
cerr < < " ERROR: in equation " < < equation_tags . getTagValueByEqnAndKey ( eq , " name " )
< < " , 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 ( ) )
{
cerr < < " ERROR: in equation " < < equation_tags . getTagValueByEqnAndKey ( eq , " name " )
< < " , the pac_target_nonstationary operator does not match a corresponding 'pac_target_info' block " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}