2018-08-14 14:23:21 +02:00
/*
2022-01-06 14:35:39 +01:00
* Copyright © 2018 - 2022 Dynare Team
2018-08-14 14:23:21 +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/>.
2018-08-14 14:23:21 +02:00
*/
# include <algorithm>
2021-10-26 18:06:26 +02:00
# include <cassert>
2018-08-14 14:23:21 +02:00
# include "SubModel.hh"
2021-10-27 16:26:52 +02:00
# include "DynamicModel.hh"
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : TrendComponentModelTable ( SymbolTable & symbol_table_arg ) :
2018-10-04 17:18:27 +02:00
symbol_table { symbol_table_arg }
2018-08-14 14:23:21 +02:00
{
}
void
TrendComponentModelTable : : addTrendComponentModel ( string name_arg ,
vector < string > eqtags_arg ,
2018-09-13 12:21:23 +02:00
vector < string > target_eqtags_arg )
2018-08-14 14:23:21 +02:00
{
if ( isExistingTrendComponentModelName ( name_arg ) )
{
cerr < < " Error: a trend component model already exists with the name " < < name_arg < < endl ;
exit ( EXIT_FAILURE ) ;
}
eqtags [ name_arg ] = move ( eqtags_arg ) ;
2018-09-13 12:21:23 +02:00
target_eqtags [ name_arg ] = move ( target_eqtags_arg ) ;
2018-08-14 14:23:21 +02:00
names . insert ( move ( name_arg ) ) ;
}
void
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : setVals ( map < string , vector < int > > eqnums_arg , map < string , vector < int > > target_eqnums_arg ,
2018-10-24 15:57:07 +02:00
map < string , vector < int > > lhs_arg , map < string , vector < expr_t > > lhs_expr_t_arg )
2018-08-14 14:23:21 +02:00
{
eqnums = move ( eqnums_arg ) ;
2018-09-13 12:21:23 +02:00
target_eqnums = move ( target_eqnums_arg ) ;
2018-09-12 11:56:04 +02:00
lhs = move ( lhs_arg ) ;
lhs_expr_t = move ( lhs_expr_t_arg ) ;
2018-08-14 14:23:21 +02:00
for ( const auto & it : eqnums )
{
vector < int > nontrend_vec ;
for ( auto eq : it . second )
2018-09-13 12:21:23 +02:00
if ( find ( target_eqnums [ it . first ] . begin ( ) , target_eqnums [ it . first ] . end ( ) , eq ) = = target_eqnums [ it . first ] . end ( ) )
2018-08-14 14:23:21 +02:00
nontrend_vec . push_back ( eq ) ;
2018-09-13 12:21:23 +02:00
nontarget_eqnums [ it . first ] = nontrend_vec ;
2018-08-14 14:23:21 +02:00
}
2018-09-12 11:56:04 +02:00
for ( const auto & name : names )
{
2018-09-13 12:21:23 +02:00
vector < int > nontarget_lhs_vec , target_lhs_vec ;
2018-09-12 11:56:04 +02:00
vector < int > lhsv = getLhs ( name ) ;
vector < int > eqnumsv = getEqNums ( name ) ;
2018-09-13 12:21:23 +02:00
for ( int nontrend_it : getNonTargetEqNums ( name ) )
nontarget_lhs_vec . push_back ( lhsv . at ( distance ( eqnumsv . begin ( ) , find ( eqnumsv . begin ( ) , eqnumsv . end ( ) , nontrend_it ) ) ) ) ;
nontarget_lhs [ name ] = nontarget_lhs_vec ;
2018-08-31 12:35:51 +02:00
2018-09-13 12:21:23 +02:00
for ( int trend_it : getTargetEqNums ( name ) )
target_lhs_vec . push_back ( lhsv . at ( distance ( eqnumsv . begin ( ) , find ( eqnumsv . begin ( ) , eqnumsv . end ( ) , trend_it ) ) ) ) ;
target_lhs [ name ] = target_lhs_vec ;
2018-09-12 11:56:04 +02:00
}
2018-08-14 14:23:21 +02:00
}
void
TrendComponentModelTable : : setRhs ( map < string , vector < set < pair < int , int > > > > rhs_arg )
{
rhs = move ( rhs_arg ) ;
}
void
2022-05-05 18:39:04 +02:00
TrendComponentModelTable : : setTargetVar ( map < string , vector < optional < int > > > target_vars_arg )
2018-08-14 14:23:21 +02:00
{
2018-09-13 12:21:23 +02:00
target_vars = move ( target_vars_arg ) ;
2018-08-14 14:23:21 +02:00
}
void
TrendComponentModelTable : : setMaxLags ( map < string , vector < int > > max_lags_arg )
{
max_lags = move ( max_lags_arg ) ;
}
void
TrendComponentModelTable : : setDiff ( map < string , vector < bool > > diff_arg )
{
diff = move ( diff_arg ) ;
}
void
2022-05-16 15:56:54 +02:00
TrendComponentModelTable : : setOrigDiffVar ( map < string , vector < optional < int > > > orig_diff_var_arg )
2018-08-14 14:23:21 +02:00
{
orig_diff_var = move ( orig_diff_var_arg ) ;
}
2018-09-07 10:56:40 +02:00
void
TrendComponentModelTable : : setAR ( map < string , map < tuple < int , int , int > , expr_t > > AR_arg )
{
AR = move ( AR_arg ) ;
}
2018-09-10 17:13:51 +02:00
void
2022-01-28 16:38:50 +01:00
TrendComponentModelTable : : setA0 ( map < string , map < tuple < int , int > , expr_t > > A0_arg ,
map < string , map < tuple < int , int > , expr_t > > A0star_arg )
2018-09-10 17:13:51 +02:00
{
2019-02-19 12:08:00 +01:00
A0 = move ( A0_arg ) ;
A0star = move ( A0star_arg ) ;
2018-09-10 17:13:51 +02:00
}
2021-07-01 16:16:04 +02:00
const map < string , vector < string > > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getEqTags ( ) const
{
return eqtags ;
}
2021-07-01 16:16:04 +02:00
const vector < string > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getEqTags ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return eqtags . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
void
TrendComponentModelTable : : checkModelName ( const string & name_arg ) const
{
if ( ! isExistingTrendComponentModelName ( name_arg ) )
{
cerr < < name_arg
< < " is not a recognized equation tag of a trend component model equation " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2019-02-14 11:44:06 +01:00
TrendComponentModelTable : : getNonTargetLhs ( const string & name_arg ) const
2018-09-12 11:56:04 +02:00
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return nontarget_lhs . at ( name_arg ) ;
2018-09-12 11:56:04 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : getTargetLhs ( const string & name_arg ) const
2018-09-12 11:56:04 +02:00
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return target_lhs . at ( name_arg ) ;
2018-09-12 11:56:04 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getLhs ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return lhs . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < expr_t > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getLhsExprT ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return lhs_expr_t . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
2021-07-01 16:16:04 +02:00
const map < string , vector < string > > &
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : getTargetEqTags ( ) const
2018-08-14 14:23:21 +02:00
{
2018-09-13 12:21:23 +02:00
return target_eqtags ;
2018-08-14 14:23:21 +02:00
}
2021-07-01 16:16:04 +02:00
const map < string , vector < int > > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getEqNums ( ) const
{
return eqnums ;
}
2021-07-01 16:16:04 +02:00
const map < string , vector < int > > &
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : getTargetEqNums ( ) const
2018-09-03 15:05:30 +02:00
{
2018-09-13 12:21:23 +02:00
return target_eqnums ;
2018-09-03 15:05:30 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : getTargetEqNums ( const string & name_arg ) const
2018-09-10 17:13:51 +02:00
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return target_eqnums . at ( name_arg ) ;
2018-09-10 17:13:51 +02:00
}
2021-07-01 16:16:04 +02:00
const map < string , vector < int > > &
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : getNonTargetEqNums ( ) const
2018-09-10 17:13:51 +02:00
{
2018-09-13 12:21:23 +02:00
return nontarget_eqnums ;
2018-09-10 17:13:51 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-09-13 12:21:23 +02:00
TrendComponentModelTable : : getNonTargetEqNums ( const string & name_arg ) const
2018-08-14 14:23:21 +02:00
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return nontarget_eqnums . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getEqNums ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return eqnums . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getMaxLags ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return max_lags . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
int
TrendComponentModelTable : : getMaxLag ( const string & name_arg ) const
{
int max_lag_int = 0 ;
for ( auto it : getMaxLags ( name_arg ) )
max_lag_int = max ( max_lag_int , it ) ;
return max_lag_int ;
}
2021-07-01 16:16:04 +02:00
const vector < bool > &
2018-08-14 14:23:21 +02:00
TrendComponentModelTable : : getDiff ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return diff . at ( name_arg ) ;
2018-08-14 14:23:21 +02:00
}
void
2018-09-07 10:56:40 +02:00
TrendComponentModelTable : : writeOutput ( const string & basename , ostream & output ) const
2018-08-14 14:23:21 +02:00
{
2018-09-25 12:17:34 +02:00
if ( names . empty ( ) )
return ;
2022-10-11 15:59:56 +02:00
const filesystem : : path filename { DataTree : : packageDir ( basename ) / " trend_component_ar_a0.m " } ;
2022-07-11 16:09:07 +02:00
ofstream ar_ec_output { filename , ios : : out | ios : : binary } ;
2018-09-10 17:13:51 +02:00
if ( ! ar_ec_output . is_open ( ) )
2018-09-07 10:56:40 +02:00
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2018-09-07 10:56:40 +02:00
exit ( EXIT_FAILURE ) ;
}
2019-02-19 12:08:00 +01:00
ar_ec_output < < " function [AR, A0, A0star] = trend_component_ar_a0(model_name, params) " < < endl
2019-12-20 16:59:30 +01:00
< < " %function [AR, A0, A0star] = trend_component_ar_a0(model_name, params) " < < endl
< < " % File automatically generated by the Dynare preprocessor " < < endl < < endl ;
2018-09-07 10:56:40 +02:00
2018-08-14 14:23:21 +02:00
for ( const auto & name : names )
{
2018-08-20 10:50:28 +02:00
output < < " M_.trend_component. " < < name < < " .model_name = ' " < < name < < " '; " < < endl
2018-08-14 14:23:21 +02:00
< < " M_.trend_component. " < < name < < " .eqtags = { " ;
for ( const auto & it : eqtags . at ( name ) )
output < < " ' " < < it < < " '; " ;
output < < " }; " < < endl
< < " M_.trend_component. " < < name < < " .eqn = [ " ;
for ( auto it : eqnums . at ( name ) )
output < < it + 1 < < " " ;
output < < " ]; " < < endl
2018-09-13 12:21:23 +02:00
< < " M_.trend_component. " < < name < < " .targets = [ " ;
2018-08-14 14:23:21 +02:00
for ( auto it : eqnums . at ( name ) )
2018-09-13 12:21:23 +02:00
if ( find ( target_eqnums . at ( name ) . begin ( ) , target_eqnums . at ( name ) . end ( ) , it )
= = target_eqnums . at ( name ) . end ( ) )
2018-08-14 14:23:21 +02:00
output < < " false " ;
else
output < < " true " ;
output < < " ]; " < < endl
< < " M_.trend_component. " < < name < < " .lhs = [ " ;
for ( auto it : lhs . at ( name ) )
output < < symbol_table . getTypeSpecificID ( it ) + 1 < < " " ;
output < < " ]; " < < endl
< < " M_.trend_component. " < < name < < " .max_lag = [ " ;
for ( auto it : max_lags . at ( name ) )
output < < it < < " " ;
output < < " ]; " < < endl
< < " M_.trend_component. " < < name < < " .diff = [ " ;
2022-05-16 12:26:21 +02:00
for ( bool it : diff . at ( name ) )
output < < boolalpha < < it < < " " ;
2018-08-14 14:23:21 +02:00
output < < " ]; " < < endl
< < " M_.trend_component. " < < name < < " .orig_diff_var = [ " ;
2022-05-16 15:56:54 +02:00
for ( const auto & it : orig_diff_var . at ( name ) )
output < < ( it ? symbol_table . getTypeSpecificID ( * it ) + 1 : - 1 ) < < " " ;
2018-08-22 14:29:07 +02:00
output < < " ]; " < < endl
< < " M_.trend_component. " < < name < < " .nonstationary = [ " ;
2018-10-24 15:57:07 +02:00
for ( size_t i = 0 ; i < diff . at ( name ) . size ( ) ; i + + )
output < < " true " ;
2018-08-14 14:23:21 +02:00
output < < " ]; " < < endl ;
2022-06-03 16:24:26 +02:00
for ( int i { 1 } ;
const auto & it : rhs . at ( name ) )
2018-08-14 14:23:21 +02:00
{
output < < " M_.trend_component. " < < name < < " .rhs.vars_at_eq{ " < < i < < " }.var = [ " ;
2021-07-01 16:16:04 +02:00
for ( auto [ var , lag ] : it )
output < < symbol_table . getTypeSpecificID ( var ) + 1 < < " " ;
2018-08-14 14:23:21 +02:00
output < < " ]; " < < endl
< < " M_.trend_component. " < < name < < " .rhs.vars_at_eq{ " < < i < < " }.lag = [ " ;
2021-07-01 16:16:04 +02:00
for ( auto [ var , lag ] : it )
output < < lag < < " " ;
2018-08-14 14:23:21 +02:00
output < < " ]; " < < endl ;
i + + ;
}
2018-09-13 12:21:23 +02:00
output < < " M_.trend_component. " < < name < < " .target_vars = [ " ;
2022-05-05 18:39:04 +02:00
for ( const optional < int > & it : target_vars . at ( name ) )
output < < ( it ? symbol_table . getTypeSpecificID ( * it ) + 1 : - 1 ) < < " " ;
2018-08-31 12:35:51 +02:00
output < < " ]; " < < endl ;
2018-09-07 10:56:40 +02:00
2019-02-21 09:47:13 +01:00
vector < string > target_eqtags_vec = target_eqtags . at ( name ) ;
output < < " M_.trend_component. " < < name < < " .target_eqtags = { " ;
for ( auto it : target_eqtags_vec )
output < < " ' " < < it < < " '; " ;
output < < " }; " < < endl ;
vector < string > eqtags_vec = eqtags . at ( name ) ;
output < < " M_.trend_component. " < < name < < " .target_eqn = [ " ;
for ( auto it : target_eqtags_vec )
2022-06-02 10:50:21 +02:00
output < < distance ( eqtags_vec . begin ( ) , find ( eqtags_vec . begin ( ) , eqtags_vec . end ( ) , it ) ) + 1 < < " " ;
2019-02-21 09:47:13 +01:00
output < < " ]; " < < endl ;
2018-09-13 12:21:23 +02:00
vector < int > target_lhs_vec = getTargetLhs ( name ) ;
2019-02-14 11:44:06 +01:00
vector < int > nontarget_lhs_vec = getNonTargetLhs ( name ) ;
2018-09-10 17:13:51 +02:00
ar_ec_output < < " if strcmp(model_name, ' " < < name < < " ') " < < endl
2019-12-20 16:59:30 +01:00
< < " % AR " < < endl
< < " AR = zeros( " < < nontarget_lhs_vec . size ( ) < < " , " < < nontarget_lhs_vec . size ( ) < < " , " < < getMaxLag ( name ) < < " ); " < < endl ;
2021-07-01 16:16:04 +02:00
for ( const auto & [ key , expr ] : AR . at ( name ) )
2018-09-07 10:56:40 +02:00
{
2021-07-01 16:16:04 +02:00
auto [ eqn , lag , lhs_symb_id ] = key ;
2019-04-23 11:07:32 +02:00
int colidx = static_cast < int > ( distance ( nontarget_lhs_vec . begin ( ) , find ( nontarget_lhs_vec . begin ( ) , nontarget_lhs_vec . end ( ) , lhs_symb_id ) ) ) ;
2019-02-19 12:08:00 +01:00
ar_ec_output < < " AR( " < < eqn + 1 < < " , " < < colidx + 1 < < " , " < < lag < < " ) = " ;
2021-07-01 16:16:04 +02:00
expr - > writeOutput ( ar_ec_output , ExprNodeOutputType : : matlabDynamicModel ) ;
2018-09-10 17:13:51 +02:00
ar_ec_output < < " ; " < < endl ;
}
2019-02-15 11:12:07 +01:00
2018-09-10 17:13:51 +02:00
ar_ec_output < < endl
2019-02-19 12:08:00 +01:00
< < " % A0 " < < endl
2022-01-28 16:38:50 +01:00
< < " A0 = zeros( " < < nontarget_lhs_vec . size ( ) < < " , " < < nontarget_lhs_vec . size ( ) < < " ); " < < endl ;
2021-07-01 16:16:04 +02:00
for ( const auto & [ key , expr ] : A0 . at ( name ) )
2018-09-10 17:13:51 +02:00
{
2022-01-28 16:38:50 +01:00
auto [ eqn , colidx ] = key ;
ar_ec_output < < " A0( " < < eqn + 1 < < " , " < < colidx + 1 < < " ) = " ;
2021-07-01 16:16:04 +02:00
expr - > writeOutput ( ar_ec_output , ExprNodeOutputType : : matlabDynamicModel ) ;
2018-09-10 17:13:51 +02:00
ar_ec_output < < " ; " < < endl ;
2018-09-07 10:56:40 +02:00
}
2019-02-19 12:08:00 +01:00
ar_ec_output < < endl
< < " % A0star " < < endl
2022-01-28 16:38:50 +01:00
< < " A0star = zeros( " < < nontarget_lhs_vec . size ( ) < < " , " < < target_lhs_vec . size ( ) < < " ); " < < endl ;
2021-07-01 16:16:04 +02:00
for ( const auto & [ key , expr ] : A0star . at ( name ) )
2019-02-19 12:08:00 +01:00
{
2022-01-28 16:38:50 +01:00
auto [ eqn , colidx ] = key ;
ar_ec_output < < " A0star( " < < eqn + 1 < < " , " < < colidx + 1 < < " ) = " ;
2021-07-01 16:16:04 +02:00
expr - > writeOutput ( ar_ec_output , ExprNodeOutputType : : matlabDynamicModel ) ;
2019-02-19 12:08:00 +01:00
ar_ec_output < < " ; " < < endl ;
}
2018-09-10 17:13:51 +02:00
ar_ec_output < < " return " < < endl
2019-12-20 16:59:30 +01:00
< < " end " < < endl < < endl ;
2018-08-14 14:23:21 +02:00
}
2018-09-10 17:13:51 +02:00
ar_ec_output < < " error([model_name ' is not a valid trend_component_model name']) " < < endl
2019-12-20 16:59:30 +01:00
< < " end " < < endl ;
2018-09-10 17:13:51 +02:00
ar_ec_output . close ( ) ;
2018-08-14 14:23:21 +02:00
}
void
TrendComponentModelTable : : writeJsonOutput ( ostream & output ) const
{
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & name : names )
2018-08-14 14:23:21 +02:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2018-08-14 14:23:21 +02:00
output < < " , " ;
2019-04-03 16:32:52 +02:00
output < < R " ({ " statementName " : " trend_component_model " ,) "
< < R " ( " model_name " : " ) " << name << R " ( " ,) "
< < R " ( " eqtags " : [) " ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something2 { false } ;
const auto & it : eqtags . at ( name ) )
2018-08-22 09:15:00 +02:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something2 , true ) )
2018-08-22 09:15:00 +02:00
output < < " , " ;
2022-06-03 16:24:26 +02:00
output < < R " ( " ) " << it << R " ( " ) " ;
2018-08-22 09:15:00 +02:00
}
2019-04-03 16:32:52 +02:00
output < < R " (], " target_eqtags " : [) " ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something2 { false } ;
const auto & it : target_eqtags . at ( name ) )
2018-08-22 09:15:00 +02:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something2 , true ) )
2018-08-22 09:15:00 +02:00
output < < " , " ;
2022-06-03 16:24:26 +02:00
output < < R " ( " ) " << it << R " ( " ) " ;
2018-08-22 09:15:00 +02:00
}
output < < " ]} " ;
2018-08-14 14:23:21 +02:00
}
}
2018-08-21 11:46:59 +02:00
VarModelTable : : VarModelTable ( SymbolTable & symbol_table_arg ) :
2018-10-04 17:18:27 +02:00
symbol_table { symbol_table_arg }
2018-08-21 11:46:59 +02:00
{
}
void
2021-07-07 10:54:04 +02:00
VarModelTable : : addVarModel ( string name_arg , bool structural_arg , vector < string > eqtags_arg )
2018-08-21 11:46:59 +02:00
{
if ( isExistingVarModelName ( name_arg ) )
{
cerr < < " Error: a VAR model already exists with the name " < < name_arg < < endl ;
exit ( EXIT_FAILURE ) ;
}
2021-07-07 10:54:04 +02:00
structural [ name_arg ] = structural_arg ;
2018-08-21 11:46:59 +02:00
eqtags [ name_arg ] = move ( eqtags_arg ) ;
names . insert ( move ( name_arg ) ) ;
}
void
2018-09-06 17:53:07 +02:00
VarModelTable : : writeOutput ( const string & basename , ostream & output ) const
2018-08-21 11:46:59 +02:00
{
2018-09-25 12:17:34 +02:00
if ( names . empty ( ) )
return ;
2022-10-11 15:59:56 +02:00
const filesystem : : path filename { DataTree : : packageDir ( basename ) / " varmatrices.m " } ;
2022-07-11 16:09:07 +02:00
ofstream ar_output { filename , ios : : out | ios : : binary } ;
2018-09-06 17:53:07 +02:00
if ( ! ar_output . is_open ( ) )
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2018-09-06 17:53:07 +02:00
exit ( EXIT_FAILURE ) ;
}
2021-07-16 15:12:37 +02:00
ar_output < < " function [ar, a0, constants] = varmatrices(model_name, params, reducedform) " < < endl
2021-07-16 08:33:26 +02:00
< < " % File automatically generated by the Dynare preprocessor " < < endl < < endl
< < " if nargin<3 " < < endl
< < " reducedform = false; " < < endl
< < " end " < < endl < < endl ;
2018-09-06 17:53:07 +02:00
2018-08-21 11:46:59 +02:00
for ( const auto & name : names )
{
2021-07-07 10:54:04 +02:00
output < < " M_.var. " < < name < < " .model_name = ' " < < name < < " '; " < < endl
2022-05-16 12:26:21 +02:00
< < " M_.var. " < < name < < " .structural = " < < boolalpha < < structural . at ( name ) < < " ; " < < endl
2021-07-07 10:54:04 +02:00
< < " M_.var. " < < name < < " .eqtags = { " ;
2018-08-21 11:46:59 +02:00
for ( const auto & it : eqtags . at ( name ) )
output < < " ' " < < it < < " '; " ;
output < < " }; " < < endl
< < " M_.var. " < < name < < " .eqn = [ " ;
for ( auto it : eqnums . at ( name ) )
output < < it + 1 < < " " ;
output < < " ]; " < < endl
< < " M_.var. " < < name < < " .lhs = [ " ;
for ( auto it : lhs . at ( name ) )
output < < symbol_table . getTypeSpecificID ( it ) + 1 < < " " ;
output < < " ]; " < < endl
< < " M_.var. " < < name < < " .max_lag = [ " ;
for ( auto it : max_lags . at ( name ) )
output < < it < < " " ;
output < < " ]; " < < endl
< < " M_.var. " < < name < < " .diff = [ " ;
2022-05-16 12:26:21 +02:00
for ( bool it : diff . at ( name ) )
output < < boolalpha < < it < < " " ;
2018-08-21 11:46:59 +02:00
output < < " ]; " < < endl
2018-10-24 15:57:07 +02:00
< < " M_.var. " < < name < < " .nonstationary = M_.var. " < < name < < " .diff; " < < endl
2018-08-21 11:46:59 +02:00
< < " M_.var. " < < name < < " .orig_diff_var = [ " ;
2022-05-16 15:56:54 +02:00
for ( const auto & it : orig_diff_var . at ( name ) )
output < < ( it ? symbol_table . getTypeSpecificID ( * it ) + 1 : - 1 ) < < " " ;
2018-08-21 11:46:59 +02:00
output < < " ]; " < < endl ;
2022-06-03 16:24:26 +02:00
for ( int i { 1 } ;
const auto & it : rhs . at ( name ) )
2018-08-21 11:46:59 +02:00
{
output < < " M_.var. " < < name < < " .rhs.vars_at_eq{ " < < i < < " }.var = [ " ;
2021-07-01 16:16:04 +02:00
for ( auto [ var , lag ] : it )
output < < symbol_table . getTypeSpecificID ( var ) + 1 < < " " ;
2018-08-21 11:46:59 +02:00
output < < " ]; " < < endl
< < " M_.var. " < < name < < " .rhs.vars_at_eq{ " < < i < < " }.lag = [ " ;
2021-07-01 16:16:04 +02:00
for ( auto [ var , lag ] : it )
output < < lag < < " " ;
2018-08-21 11:46:59 +02:00
output < < " ]; " < < endl ;
i + + ;
}
2018-09-06 17:53:07 +02:00
2019-03-14 17:20:45 +01:00
vector < int > lhs = getLhsOrigIds ( name ) ;
2018-09-06 17:53:07 +02:00
ar_output < < " if strcmp(model_name, ' " < < name < < " ') " < < endl
< < " ar = zeros( " < < lhs . size ( ) < < " , " < < lhs . size ( ) < < " , " < < getMaxLag ( name ) < < " ); " < < endl ;
2021-07-01 16:16:04 +02:00
for ( const auto & [ key , expr ] : AR . at ( name ) )
2018-09-06 17:53:07 +02:00
{
2021-07-01 16:16:04 +02:00
auto [ eqn , lag , lhs_symb_id ] = key ;
2019-04-23 11:07:32 +02:00
int colidx = static_cast < int > ( distance ( lhs . begin ( ) , find ( lhs . begin ( ) , lhs . end ( ) , lhs_symb_id ) ) ) ;
2021-07-16 08:33:26 +02:00
ar_output < < " ar( " < < eqn + 1 < < " , " < < colidx + 1 < < " , " < < lag < < " ) = " ;
2021-07-01 16:16:04 +02:00
expr - > writeOutput ( ar_output , ExprNodeOutputType : : matlabDynamicModel ) ;
2018-09-12 18:21:34 +02:00
ar_output < < " ; " < < endl ;
2018-09-06 17:53:07 +02:00
}
2021-07-16 08:33:26 +02:00
ar_output < < " if nargout>1 " < < endl
< < " a0 = eye( " < < lhs . size ( ) < < " ); " < < endl ;
2021-07-07 10:54:04 +02:00
for ( const auto & [ key , expr ] : A0 . at ( name ) )
{
auto [ eqn , lhs_symb_id ] = key ;
int colidx = static_cast < int > ( distance ( lhs . begin ( ) , find ( lhs . begin ( ) , lhs . end ( ) , lhs_symb_id ) ) ) ;
2021-07-16 08:33:26 +02:00
if ( eqn ! = colidx )
{
ar_output < < " a0( " < < eqn + 1 < < " , " < < colidx + 1 < < " ) = " ;
expr - > writeOutput ( ar_output , ExprNodeOutputType : : matlabDynamicModel ) ;
ar_output < < " ; " < < endl ;
}
2021-07-07 10:54:04 +02:00
}
2021-07-16 08:33:26 +02:00
ar_output < < " if reducedform " < < endl
< < " for i=1: " < < getMaxLag ( name ) < < endl
< < " ar(:,:,i) = a0 \\ ar(:,:,i); " < < endl
< < " end " < < endl
2021-07-16 22:39:00 +02:00
< < " if nargout<3 " < < endl
< < " a0 = eye( " < < lhs . size ( ) < < " ); " < < endl
< < " end " < < endl
2021-07-16 08:33:26 +02:00
< < " end " < < endl
2021-07-16 15:12:37 +02:00
< < " if nargout>2 " < < endl
2021-07-16 19:50:02 +02:00
< < " constants = zeros( " < < lhs . size ( ) < < " ,1); " < < endl ;
2021-07-16 15:12:37 +02:00
for ( auto [ eqn , expr ] : constants . at ( name ) )
{
ar_output < < " constants( " < < eqn + 1 < < " ) = " ;
expr - > writeOutput ( ar_output , ExprNodeOutputType : : matlabDynamicModel ) ;
ar_output < < " ; " < < endl ;
}
ar_output < < " end " < < endl
2021-07-16 22:39:00 +02:00
< < " if reducedform " < < endl
< < " constants = a0 \\ constants; " < < endl
< < " a0 = eye( " < < lhs . size ( ) < < " ); " < < endl
< < " end " < < endl
2021-07-16 08:33:26 +02:00
< < " end " < < endl
2021-07-07 10:54:04 +02:00
< < " return " < < endl
2018-09-06 17:53:07 +02:00
< < " end " < < endl < < endl ;
2018-08-21 11:46:59 +02:00
}
2021-07-16 08:33:26 +02:00
ar_output < < " error('%s is not a valid var_model name', model_name) " < < endl ;
2018-09-06 17:53:07 +02:00
ar_output . close ( ) ;
2018-08-21 11:46:59 +02:00
}
void
VarModelTable : : writeJsonOutput ( ostream & output ) const
{
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & name : names )
2018-08-21 11:46:59 +02:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2018-08-21 11:46:59 +02:00
output < < " , " ;
2019-04-03 16:32:52 +02:00
output < < R " ({ " statementName " : " var_model " ,) "
2021-07-07 15:08:17 +02:00
< < R " ( " model_name " : " ) " << name << R " ( " ,) "
< < R " ( " eqtags " : [) " ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something2 { false } ;
const auto & it : eqtags . at ( name ) )
2018-08-21 11:46:59 +02:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something2 , true ) )
2021-07-07 15:08:17 +02:00
output < < " , " ;
2022-06-03 16:24:26 +02:00
output < < R " ( " ) " << it << R " ( " ) " ;
2018-08-21 11:46:59 +02:00
}
2021-07-07 15:08:17 +02:00
output < < " ]} " ;
2018-08-21 11:46:59 +02:00
}
}
2021-07-07 10:54:04 +02:00
const map < string , bool > &
VarModelTable : : getStructural ( ) const
{
return structural ;
}
2021-07-01 16:16:04 +02:00
const map < string , vector < string > > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getEqTags ( ) const
{
return eqtags ;
}
2021-07-01 16:16:04 +02:00
const vector < string > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getEqTags ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return eqtags . at ( name_arg ) ;
2018-08-21 11:46:59 +02:00
}
void
VarModelTable : : checkModelName ( const string & name_arg ) const
{
if ( ! isExistingVarModelName ( name_arg ) )
{
cerr < < name_arg
< < " is not a recognized equation tag of a VAR model equation " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
void
VarModelTable : : setEqNums ( map < string , vector < int > > eqnums_arg )
{
eqnums = move ( eqnums_arg ) ;
}
void
VarModelTable : : setLhs ( map < string , vector < int > > lhs_arg )
{
lhs = move ( lhs_arg ) ;
2019-03-14 17:20:45 +01:00
for ( auto it : lhs )
{
vector < int > lhsvec ;
for ( auto ids : it . second )
{
int lhs_last_orig_symb_id = ids ;
int lhs_orig_symb_id = ids ;
2022-01-28 16:28:14 +01:00
if ( symbol_table . isDiffAuxiliaryVariable ( lhs_orig_symb_id ) )
2019-03-14 17:20:45 +01:00
try
2019-12-20 16:59:30 +01:00
{
lhs_last_orig_symb_id = lhs_orig_symb_id ;
lhs_orig_symb_id = symbol_table . getOrigSymbIdForAuxVar ( lhs_orig_symb_id ) ;
}
2019-03-14 17:20:45 +01:00
catch ( . . . )
{
}
lhsvec . emplace_back ( lhs_last_orig_symb_id ) ;
}
lhs_orig_symb_ids [ it . first ] = lhsvec ;
}
2018-08-21 11:46:59 +02:00
}
void
VarModelTable : : setRhs ( map < string , vector < set < pair < int , int > > > > rhs_arg )
{
rhs = move ( rhs_arg ) ;
}
void
VarModelTable : : setLhsExprT ( map < string , vector < expr_t > > lhs_expr_t_arg )
{
lhs_expr_t = move ( lhs_expr_t_arg ) ;
}
2021-07-01 16:16:04 +02:00
const map < string , vector < int > > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getEqNums ( ) const
{
return eqnums ;
}
2021-07-01 16:16:04 +02:00
const vector < bool > &
2018-10-24 15:57:07 +02:00
VarModelTable : : getDiff ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return diff . at ( name_arg ) ;
2018-10-24 15:57:07 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getEqNums ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return eqnums . at ( name_arg ) ;
2018-08-21 11:46:59 +02:00
}
void
VarModelTable : : setMaxLags ( map < string , vector < int > > max_lags_arg )
{
max_lags = move ( max_lags_arg ) ;
}
void
VarModelTable : : setDiff ( map < string , vector < bool > > diff_arg )
{
diff = move ( diff_arg ) ;
}
void
2022-05-16 15:56:54 +02:00
VarModelTable : : setOrigDiffVar ( map < string , vector < optional < int > > > orig_diff_var_arg )
2018-08-21 11:46:59 +02:00
{
orig_diff_var = move ( orig_diff_var_arg ) ;
}
2018-09-06 17:53:07 +02:00
void
2018-09-07 10:14:18 +02:00
VarModelTable : : setAR ( map < string , map < tuple < int , int , int > , expr_t > > AR_arg )
2018-09-06 17:53:07 +02:00
{
AR = move ( AR_arg ) ;
}
2021-07-07 10:54:04 +02:00
void
VarModelTable : : setA0 ( map < string , map < tuple < int , int > , expr_t > > A0_arg )
{
A0 = move ( A0_arg ) ;
}
2021-07-16 15:12:37 +02:00
void
VarModelTable : : setConstants ( map < string , map < int , expr_t > > constants_arg )
{
constants = move ( constants_arg ) ;
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getMaxLags ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return max_lags . at ( name_arg ) ;
2018-08-21 11:46:59 +02:00
}
int
VarModelTable : : getMaxLag ( const string & name_arg ) const
{
int max_lag_int = 0 ;
for ( auto it : getMaxLags ( name_arg ) )
max_lag_int = max ( max_lag_int , it ) ;
return max_lag_int ;
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getLhs ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return lhs . at ( name_arg ) ;
2018-08-21 11:46:59 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < int > &
2019-03-14 17:20:45 +01:00
VarModelTable : : getLhsOrigIds ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return lhs_orig_symb_ids . at ( name_arg ) ;
2019-03-14 17:20:45 +01:00
}
2021-07-01 16:16:04 +02:00
const vector < set < pair < int , int > > > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getRhs ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return rhs . at ( name_arg ) ;
2018-08-21 11:46:59 +02:00
}
2021-07-01 16:16:04 +02:00
const vector < expr_t > &
2018-08-21 11:46:59 +02:00
VarModelTable : : getLhsExprT ( const string & name_arg ) const
{
checkModelName ( name_arg ) ;
2022-09-27 12:51:22 +02:00
return lhs_expr_t . at ( name_arg ) ;
2018-08-21 11:46:59 +02:00
}
2021-10-27 16:26:52 +02:00
2022-01-20 16:15:43 +01:00
VarExpectationModelTable : : VarExpectationModelTable ( SymbolTable & symbol_table_arg ) :
symbol_table { symbol_table_arg }
{
}
void
VarExpectationModelTable : : addVarExpectationModel ( string name_arg , expr_t expression_arg , string aux_model_name_arg , string horizon_arg , expr_t discount_arg , int time_shift_arg )
{
if ( isExistingVarExpectationModelName ( name_arg ) )
{
cerr < < " Error: a var_expectation_model already exists with the name " < < name_arg < < endl ;
exit ( EXIT_FAILURE ) ;
}
expression [ name_arg ] = expression_arg ;
aux_model_name [ name_arg ] = move ( aux_model_name_arg ) ;
horizon [ name_arg ] = move ( horizon_arg ) ;
discount [ name_arg ] = discount_arg ;
time_shift [ name_arg ] = time_shift_arg ;
names . insert ( move ( name_arg ) ) ;
}
bool
VarExpectationModelTable : : isExistingVarExpectationModelName ( const string & name_arg ) const
{
2022-05-04 16:01:34 +02:00
return names . contains ( name_arg ) ;
2022-01-20 16:15:43 +01:00
}
bool
VarExpectationModelTable : : empty ( ) const
{
return names . empty ( ) ;
}
void
2022-06-24 15:45:35 +02:00
VarExpectationModelTable : : writeOutput ( ostream & output ) const
2022-01-20 16:15:43 +01:00
{
for ( const auto & name : names )
{
string mstruct = " M_.var_expectation. " + name ;
output < < mstruct < < " .auxiliary_model_name = ' " < < aux_model_name . at ( name ) < < " '; " < < endl
< < mstruct < < " .horizon = " < < horizon . at ( name ) < < ' ; ' < < endl
< < mstruct < < " .time_shift = " < < time_shift . at ( name ) < < ' ; ' < < endl ;
auto & vpc = vars_params_constants . at ( name ) ;
if ( ! vpc . size ( ) )
{
cerr < < " ERROR: VarExpectationModelStatement::writeOutput: matchExpression() has not been called " < < endl ;
exit ( EXIT_FAILURE ) ;
}
ostringstream vars_list , params_list , constants_list ;
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & [ variable_id , param_id , constant ] : vpc )
2022-01-20 16:15:43 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2022-01-20 16:15:43 +01:00
{
vars_list < < " , " ;
params_list < < " , " ;
constants_list < < " , " ;
}
2022-06-03 16:24:26 +02:00
vars_list < < symbol_table . getTypeSpecificID ( variable_id ) + 1 ;
if ( param_id )
params_list < < symbol_table . getTypeSpecificID ( * param_id ) + 1 ;
2022-01-20 16:15:43 +01:00
else
2022-05-16 17:42:24 +02:00
params_list < < " NaN " ;
2022-06-03 16:24:26 +02:00
constants_list < < constant ;
2022-01-20 16:15:43 +01:00
}
output < < mstruct < < " .expr.vars = [ " < < vars_list . str ( ) < < " ]; " < < endl
< < mstruct < < " .expr.params = [ " < < params_list . str ( ) < < " ]; " < < endl
< < mstruct < < " .expr.constants = [ " < < constants_list . str ( ) < < " ]; " < < endl ;
if ( auto disc_var = dynamic_cast < const VariableNode * > ( discount . at ( name ) ) ;
disc_var )
output < < mstruct < < " .discount_index = " < < symbol_table . getTypeSpecificID ( disc_var - > symb_id ) + 1 < < ' ; ' < < endl ;
else
{
output < < mstruct < < " .discount_value = " ;
discount . at ( name ) - > writeOutput ( output ) ;
output < < ' ; ' < < endl ;
}
output < < mstruct < < " .param_indices = [ " ;
for ( int param_id : aux_param_symb_ids . at ( name ) )
output < < symbol_table . getTypeSpecificID ( param_id ) + 1 < < ' ' ;
output < < " ]; " < < endl ;
}
}
void
VarExpectationModelTable : : substituteUnaryOpsInExpression ( const lag_equivalence_table_t & nodes , ExprNode : : subst_table_t & subst_table , vector < BinaryOpNode * > & neweqs )
{
for ( const auto & name : names )
expression [ name ] = expression [ name ] - > substituteUnaryOpNodes ( nodes , subst_table , neweqs ) ;
}
void
VarExpectationModelTable : : substituteDiffNodesInExpression ( const lag_equivalence_table_t & nodes , ExprNode : : subst_table_t & subst_table , vector < BinaryOpNode * > & neweqs )
{
for ( const auto & name : names )
expression [ name ] = expression [ name ] - > substituteDiff ( nodes , subst_table , neweqs ) ;
}
void
VarExpectationModelTable : : transformPass ( ExprNode : : subst_table_t & diff_subst_table ,
DynamicModel & dynamic_model , const VarModelTable & var_model_table ,
const TrendComponentModelTable & trend_component_model_table )
{
map < string , expr_t > var_expectation_subst_table ;
for ( const auto & name : names )
{
// Collect information about the auxiliary model
int max_lag ;
vector < int > lhs ;
if ( var_model_table . isExistingVarModelName ( aux_model_name [ name ] ) )
{
max_lag = var_model_table . getMaxLag ( aux_model_name [ name ] ) ;
lhs = var_model_table . getLhs ( aux_model_name [ name ] ) ;
}
else if ( trend_component_model_table . isExistingTrendComponentModelName ( aux_model_name [ name ] ) )
{
max_lag = trend_component_model_table . getMaxLag ( aux_model_name [ name ] ) + 1 ;
lhs = dynamic_model . getUndiffLHSForPac ( aux_model_name [ name ] , diff_subst_table ) ;
}
else
{
cerr < < " ERROR: var_expectation_model " < < name
< < " refers to nonexistent auxiliary model " < < aux_model_name [ name ] < < endl ;
exit ( EXIT_FAILURE ) ;
}
// Match the linear combination in the expression option
try
{
auto vpc = expression [ name ] - > matchLinearCombinationOfVariables ( ) ;
for ( const auto & [ variable_id , lag , param_id , constant ] : vpc )
{
if ( lag ! = 0 )
throw ExprNode : : MatchFailureException { " lead/lags are not allowed " } ;
if ( symbol_table . getType ( variable_id ) ! = SymbolType : : endogenous )
throw ExprNode : : MatchFailureException { " Variable is not an endogenous " } ;
vars_params_constants [ name ] . emplace_back ( variable_id , param_id , constant ) ;
}
}
catch ( ExprNode : : MatchFailureException & e )
{
cerr < < " ERROR: expression in var_expectation_model " < < name < < " is not of the expected form: " < < e . message < < endl ;
exit ( EXIT_FAILURE ) ;
}
/* Create auxiliary parameters and the expression to be substituted into
the var_expectations statement */
expr_t subst_expr = dynamic_model . Zero ;
if ( var_model_table . isExistingVarModelName ( aux_model_name [ name ] ) )
{
/* If the auxiliary model is a VAR, add a parameter corresponding to
the constant . */
string constant_param_name = " var_expectation_model_ " + name + " _constant " ;
int constant_param_id = symbol_table . addSymbol ( constant_param_name , SymbolType : : parameter ) ;
aux_param_symb_ids [ name ] . push_back ( constant_param_id ) ;
subst_expr = dynamic_model . AddPlus ( subst_expr , dynamic_model . AddVariable ( constant_param_id ) ) ;
}
for ( int lag = 0 ; lag < max_lag ; lag + + )
for ( auto variable : lhs )
{
string param_name = " var_expectation_model_ " + name + ' _ ' + symbol_table . getName ( variable ) + ' _ ' + to_string ( lag ) ;
int new_param_id = symbol_table . addSymbol ( param_name , SymbolType : : parameter ) ;
aux_param_symb_ids [ name ] . push_back ( new_param_id ) ;
subst_expr = dynamic_model . AddPlus ( subst_expr ,
dynamic_model . AddTimes ( dynamic_model . AddVariable ( new_param_id ) ,
dynamic_model . AddVariable ( variable , - lag + time_shift [ name ] ) ) ) ;
}
2022-05-04 16:01:34 +02:00
if ( var_expectation_subst_table . contains ( name ) )
2022-01-20 16:15:43 +01:00
{
cerr < < " ERROR: model name ' " < < name < < " ' is used by several var_expectation_model statements " < < endl ;
exit ( EXIT_FAILURE ) ;
}
var_expectation_subst_table [ name ] = subst_expr ;
}
// Actually substitute var_expectation statements
dynamic_model . substituteVarExpectation ( var_expectation_subst_table ) ;
/* At this point, we know that all var_expectation operators have been
substituted , because of the error check performed in
VarExpectationNode : : substituteVarExpectation ( ) . */
}
void
VarExpectationModelTable : : writeJsonOutput ( ostream & output ) const
{
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & name : names )
2022-01-20 16:15:43 +01:00
{
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2022-02-15 20:58:36 +01:00
output < < " , " ;
2022-01-20 16:15:43 +01:00
output < < R " ({ " statementName " : " var_expectation_model " ,) "
< < R " ( " model_name " : " ) " << name << R " ( " , ) "
< < R " ( " expression " : " ) " ;
expression . at ( name ) - > writeOutput ( output ) ;
output < < R " ( " , ) "
< < R " ( " auxiliary_model_name " : " ) " << aux_model_name.at(name) << R " ( " , ) "
< < R " ( " horizon " : " ) " << horizon.at(name) << R " ( " , ) "
< < R " ( " discount " : " ) " ;
discount . at ( name ) - > writeOutput ( output ) ;
2022-01-20 16:16:58 +01:00
output < < R " ( " , ) "
< < R " ( " time_shift " : ) " < < time_shift . at ( name )
< < R " (}) " ;
2022-01-20 16:15:43 +01:00
}
}
2021-10-27 16:26:52 +02:00
PacModelTable : : PacModelTable ( SymbolTable & symbol_table_arg ) :
symbol_table { symbol_table_arg }
{
}
void
2021-11-18 17:08:08 +01:00
PacModelTable : : addPacModel ( string name_arg , string aux_model_name_arg , string discount_arg , expr_t growth_arg , string auxname_arg , PacTargetKind kind_arg )
2021-10-27 16:26:52 +02:00
{
if ( isExistingPacModelName ( name_arg ) )
{
cerr < < " Error: a PAC model already exists with the name " < < name_arg < < endl ;
exit ( EXIT_FAILURE ) ;
}
aux_model_name [ name_arg ] = move ( aux_model_name_arg ) ;
discount [ name_arg ] = move ( discount_arg ) ;
growth [ name_arg ] = growth_arg ;
original_growth [ name_arg ] = growth_arg ;
2021-11-18 17:08:08 +01:00
auxname [ name_arg ] = move ( auxname_arg ) ;
kind [ name_arg ] = kind_arg ;
2021-10-27 16:26:52 +02:00
names . insert ( move ( name_arg ) ) ;
}
bool
PacModelTable : : isExistingPacModelName ( const string & name_arg ) const
{
2022-05-04 16:01:34 +02:00
return names . contains ( name_arg ) ;
2021-10-27 16:26:52 +02:00
}
bool
PacModelTable : : empty ( ) const
{
return names . empty ( ) ;
}
void
2022-06-24 15:45:35 +02:00
PacModelTable : : checkPass ( ModFileStructure & mod_file_struct )
2021-10-27 16:26:52 +02:00
{
for ( auto & [ name , gv ] : growth )
if ( gv )
2021-10-26 18:06:26 +02:00
{
2022-05-04 16:01:34 +02:00
if ( target_info . contains ( name ) )
2021-10-26 18:06:26 +02:00
{
cerr < < " ERROR: for PAC model ' " < < name < < " ', it is not possible to declare a 'growth' option in the 'pac_model' command when there is also a 'pac_target_info' block " < < endl ;
exit ( EXIT_FAILURE ) ;
}
gv - > collectVariables ( SymbolType : : exogenous , mod_file_struct . pac_params ) ;
}
2021-11-18 17:08:08 +01:00
for ( auto & [ name , auxn ] : auxname )
2022-05-04 16:01:34 +02:00
if ( ! auxn . empty ( ) & & target_info . contains ( name ) )
2021-11-18 17:08:08 +01:00
{
cerr < < " ERROR: for PAC model ' " < < name < < " ', it is not possible to declare an 'auxname' option in the 'pac_model' command when there is also a 'pac_target_info' block " < < endl ;
exit ( EXIT_FAILURE ) ;
}
for ( auto & [ name , k ] : kind )
if ( k ! = PacTargetKind : : unspecified )
{
2022-05-04 16:01:34 +02:00
if ( target_info . contains ( name ) )
2021-11-18 17:08:08 +01:00
{
cerr < < " ERROR: for PAC model ' " < < name < < " ', it is not possible to declare a 'kind' option in the 'pac_model' command when there is also a 'pac_target_info' block " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( aux_model_name [ name ] . empty ( ) )
{
cerr < < " ERROR: for PAC model ' " < < name < < " ', it is not possible to declare a 'kind' option in the 'pac_model' command since this is a MCE model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2021-10-26 18:06:26 +02:00
for ( const auto & [ name , ti ] : target_info )
for ( auto & [ expr , gv , auxname , kind , coeff , growth_neutrality_param , h_indices , original_gv , gv_info ] : get < 2 > ( ti ) )
if ( gv )
gv - > collectVariables ( SymbolType : : exogenous , mod_file_struct . pac_params ) ;
for ( const auto & [ name , ti ] : target_info )
{
auto & [ target , auxname_target_nonstationary , components ] = ti ;
if ( ! target )
{
cerr < < " ERROR: the block 'pac_target_info( " < < name < < " )' is missing the 'target' statement " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( auxname_target_nonstationary . empty ( ) )
{
cerr < < " ERROR: the block 'pac_target_info( " < < name < < " )' is missing the 'auxname_target_nonstationary' statement " < < endl ;
exit ( EXIT_FAILURE ) ;
}
int nonstationary_nb = 0 ;
for ( auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : components )
{
if ( auxname . empty ( ) )
{
cerr < < " ERROR: the block 'pac_target_info( " < < name < < " )' is missing the 'auxname' statement in some 'component' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( kind = = PacTargetKind : : unspecified )
{
cerr < < " ERROR: the block 'pac_target_info( " < < name < < " )' is missing the 'kind' statement in some 'component' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( kind = = PacTargetKind : : ll & & growth_component )
{
cerr < < " ERROR: in the block 'pac_target_info( " < < name < < " )', a component of 'kind ll' (i.e. stationary) has a 'growth' option. This is not permitted. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if ( kind = = PacTargetKind : : dd | | kind = = PacTargetKind : : dl )
nonstationary_nb + + ;
}
if ( ! nonstationary_nb )
{
cerr < < " ERROR: the block 'pac_target_info( " < < name < < " )' must contain at least one nonstationary component (i.e. of 'kind' equal to either 'dd' or 'dl'). " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2021-10-27 16:26:52 +02:00
}
2022-01-18 12:40:15 +01:00
void
PacModelTable : : substituteUnaryOpsInGrowth ( const lag_equivalence_table_t & nodes , ExprNode : : subst_table_t & subst_table , vector < BinaryOpNode * > & neweqs )
{
for ( auto & [ name , gv ] : growth )
if ( gv )
gv = gv - > substituteUnaryOpNodes ( nodes , subst_table , neweqs ) ;
for ( auto & [ name , ti ] : target_info )
for ( auto & [ expr , gv , auxname , kind , coeff , growth_neutrality_param , h_indices , original_gv , gv_info ] : get < 2 > ( ti ) )
if ( gv )
gv = gv - > substituteUnaryOpNodes ( nodes , subst_table , neweqs ) ;
}
2021-10-27 16:26:52 +02:00
void
PacModelTable : : findDiffNodesInGrowth ( lag_equivalence_table_t & diff_nodes ) const
{
for ( auto & [ name , gv ] : growth )
if ( gv )
gv - > findDiffNodes ( diff_nodes ) ;
2021-10-26 18:06:26 +02:00
for ( const auto & [ name , ti ] : target_info )
for ( auto & [ expr , gv , auxname , kind , coeff , growth_neutrality_param , h_indices , original_gv , gv_info ] : get < 2 > ( ti ) )
if ( gv )
gv - > findDiffNodes ( diff_nodes ) ;
2021-10-27 16:26:52 +02:00
}
void
PacModelTable : : substituteDiffNodesInGrowth ( const lag_equivalence_table_t & diff_nodes , ExprNode : : subst_table_t & diff_subst_table , vector < BinaryOpNode * > & neweqs )
{
for ( auto & [ name , gv ] : growth )
if ( gv )
gv = gv - > substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ;
2021-10-26 18:06:26 +02:00
for ( auto & [ name , ti ] : target_info )
for ( auto & [ expr , gv , auxname , kind , coeff , growth_neutrality_param , h_indices , original_gv , gv_info ] : get < 2 > ( ti ) )
if ( gv )
gv = gv - > substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ;
2021-10-27 16:26:52 +02:00
}
void
2021-10-26 18:06:26 +02:00
PacModelTable : : transformPass ( const lag_equivalence_table_t & unary_ops_nodes ,
ExprNode : : subst_table_t & unary_ops_subst_table ,
const lag_equivalence_table_t & diff_nodes ,
ExprNode : : subst_table_t & diff_subst_table ,
2021-10-27 16:26:52 +02:00
DynamicModel & dynamic_model , const VarModelTable & var_model_table ,
const TrendComponentModelTable & trend_component_model_table )
{
2021-10-28 14:42:56 +02:00
// model name → expression for pac_expectation
map < string , expr_t > pac_expectation_substitution ;
2021-10-27 18:17:14 +02:00
2021-10-27 16:26:52 +02:00
for ( const auto & name : names )
{
/* Fill the growth_info structure.
Cannot be done in an earlier pass since growth terms can be
transformed by DynamicModel : : substituteDiff ( ) . */
if ( growth [ name ] )
try
{
2022-05-16 17:42:24 +02:00
growth_info [ name ] = growth [ name ] - > matchLinearCombinationOfVariablesPlusConstant ( ) ;
2021-10-27 16:26:52 +02:00
}
catch ( ExprNode : : MatchFailureException & e )
{
2021-12-03 15:48:22 +01:00
cerr < < " ERROR: PAC growth must be a linear combination of variables " < < endl ;
exit ( EXIT_FAILURE ) ;
2021-10-27 16:26:52 +02:00
}
2021-10-26 18:06:26 +02:00
// Perform transformations for the pac_target_info block (if any)
2022-05-04 16:01:34 +02:00
if ( target_info . contains ( name ) )
2021-10-26 18:06:26 +02:00
{
// Substitute unary ops and diffs in the target…
expr_t & target = get < 0 > ( target_info [ name ] ) ;
vector < BinaryOpNode * > neweqs ;
target = target - > substituteUnaryOpNodes ( unary_ops_nodes , unary_ops_subst_table , neweqs ) ;
if ( neweqs . size ( ) > 0 )
{
cerr < < " ERROR: the 'target' expression of 'pac_target_info( " < < name < < " )' contains a variable with a unary operator that is not present in the model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
target = target - > substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ;
if ( neweqs . size ( ) > 0 )
{
cerr < < " ERROR: the 'target' expression of 'pac_target_info( " < < name < < " )' contains a diff'd variable that is not present in the model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
// …and in component expressions
auto & components = get < 2 > ( target_info [ name ] ) ;
for ( auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : components )
{
component = component - > substituteUnaryOpNodes ( unary_ops_nodes , unary_ops_subst_table , neweqs ) ;
if ( neweqs . size ( ) > 0 )
{
cerr < < " ERROR: a 'component' expression of 'pac_target_info( " < < name < < " )' contains a variable with a unary operator that is not present in the model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
component = component - > substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ;
if ( neweqs . size ( ) > 0 )
{
cerr < < " ERROR: a 'component' expression of 'pac_target_info( " < < name < < " )' contains a diff'd variable that is not present in the model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
/* Fill the growth_info structure.
Cannot be done in an earlier pass since growth terms can be
transformed by DynamicModel : : substituteDiff ( ) . */
for ( auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : components )
{
if ( growth_component )
try
{
2022-05-16 17:42:24 +02:00
growth_component_info = growth_component - > matchLinearCombinationOfVariablesPlusConstant ( ) ;
2021-10-26 18:06:26 +02:00
}
catch ( ExprNode : : MatchFailureException & e )
{
cerr < < " ERROR: PAC growth must be a linear combination of variables " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
// Identify the model equation defining the target
expr_t target_expr ;
try
{
target_expr = dynamic_model . getRHSFromLHS ( target ) ;
}
catch ( ExprNode : : MatchFailureException )
{
cerr < < " ERROR: there is no equation whose LHS is equal to the 'target' of 'pac_target_info( " < < name < < " )' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2022-01-17 12:57:37 +01:00
// Substitute unary ops and diffs in that equation, before parsing (see dynare#1837)
target_expr = target_expr - > substituteUnaryOpNodes ( unary_ops_nodes , unary_ops_subst_table , neweqs ) ;
if ( neweqs . size ( ) > 0 )
{
cerr < < " ERROR: the equation defining the target of 'pac_target_info( " < < name < < " )' contains a variable with a unary operator that is not present in the model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
target_expr = target_expr - > substituteDiff ( diff_nodes , diff_subst_table , neweqs ) ;
if ( neweqs . size ( ) > 0 )
{
cerr < < " ERROR: the equation defining the target of 'pac_target_info( " < < name < < " )' contains a diff'd variable that is not present in the model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2021-10-26 18:06:26 +02:00
// Parse that model equation
vector < pair < int , expr_t > > terms ;
expr_t constant ;
try
{
tie ( terms , constant ) = target_expr - > matchLinearCombinationOfEndogenousWithConstant ( ) ;
}
catch ( ExprNode : : MatchFailureException )
{
cerr < < " ERROR: the model equation defining the 'target' of 'pac_target_info( " < < name < < " )' is not of the right form (should be a linear combination of endogenous variables) " < < endl ;
exit ( EXIT_FAILURE ) ;
}
// Associate the coefficients of the linear combination with the right components
for ( auto [ var , coeff ] : terms )
if ( auto it = find_if ( components . begin ( ) , components . end ( ) ,
2023-01-05 18:11:33 +01:00
[ & ] ( const auto & v ) { return get < 0 > ( v ) = = dynamic_model . AddVariable ( var ) ; } ) ;
2021-10-26 18:06:26 +02:00
it ! = components . end ( ) )
get < 4 > ( * it ) = coeff ;
else
{
cerr < < " ERROR: the model equation defining the 'target' of 'pac_target_info( " < < name < < " )' contains a variable ( " < < symbol_table . getName ( var ) < < " ) that is not declared as a 'component' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
// Verify that all declared components appear in that equation
for ( const auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : components )
if ( ! coeff )
{
cerr < < " ERROR: a 'component' of 'pac_target_info( " < < name < < " )' does not appear in the model equation defining the 'target' " < < endl ;
exit ( EXIT_FAILURE ) ;
}
/* Add the variable and equation defining the stationary part of the
target . Note that it includes the constant . */
expr_t yns = constant ;
for ( const auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : components )
if ( kind ! = PacTargetKind : : ll )
yns = dynamic_model . AddPlus ( yns , dynamic_model . AddTimes ( coeff , component ) ) ;
int target_nonstationary_id = symbol_table . addPacTargetNonstationaryAuxiliaryVar ( get < 1 > ( target_info [ name ] ) , yns ) ;
expr_t neweq = dynamic_model . AddEqual ( dynamic_model . AddVariable ( target_nonstationary_id ) , yns ) ;
2022-05-05 18:39:27 +02:00
dynamic_model . addEquation ( neweq , nullopt ) ;
2021-10-26 18:06:26 +02:00
dynamic_model . addAuxEquation ( neweq ) ;
/* Perform the substitution of the pac_target_nonstationary operator.
This needs to be done here , otherwise
DynamicModel : : analyzePacEquationStructure ( ) will not be able to
identify the error - correction part */
dynamic_model . substitutePacTargetNonstationary ( name , dynamic_model . AddVariable ( target_nonstationary_id , - 1 ) ) ;
}
2021-10-27 18:17:14 +02:00
// Collect some information about PAC models
2021-10-27 16:26:52 +02:00
int max_lag ;
if ( trend_component_model_table . isExistingTrendComponentModelName ( aux_model_name [ name ] ) )
{
2021-10-27 18:17:14 +02:00
aux_model_type [ name ] = " trend_component " ;
2021-10-27 16:26:52 +02:00
max_lag = trend_component_model_table . getMaxLag ( aux_model_name [ name ] ) + 1 ;
2021-10-27 18:17:14 +02:00
lhs [ name ] = dynamic_model . getUndiffLHSForPac ( aux_model_name [ name ] , diff_subst_table ) ;
2021-10-27 16:26:52 +02:00
}
else if ( var_model_table . isExistingVarModelName ( aux_model_name [ name ] ) )
{
2021-10-27 18:17:14 +02:00
aux_model_type [ name ] = " var " ;
2021-10-27 16:26:52 +02:00
max_lag = var_model_table . getMaxLag ( aux_model_name [ name ] ) ;
2021-10-27 18:17:14 +02:00
lhs [ name ] = var_model_table . getLhs ( aux_model_name [ name ] ) ;
2021-10-27 16:26:52 +02:00
}
else if ( aux_model_name [ name ] . empty ( ) )
max_lag = 0 ;
else
{
cerr < < " Error: aux_model_name not recognized as VAR model or Trend Component model " < < endl ;
exit ( EXIT_FAILURE ) ;
}
2021-10-28 14:42:56 +02:00
dynamic_model . analyzePacEquationStructure ( name , eq_name , equation_info ) ;
2021-10-27 18:17:14 +02:00
// Declare parameter for growth neutrality correction
if ( growth [ name ] )
{
string param_name = name + " _pac_growth_neutrality_correction " ;
try
{
int param_idx = symbol_table . addSymbol ( param_name , SymbolType : : parameter ) ;
growth_neutrality_params [ name ] = param_idx ;
}
catch ( SymbolTable : : AlreadyDeclaredException )
{
cerr < < " The variable/parameter ' " < < param_name < < " ' conflicts with the auxiliary parameter that will be generated for the growth neutrality correction of the ' " < < name < < " ' PAC model. Please rename that parameter. " < < endl ;
exit ( EXIT_FAILURE ) ;
}
}
2021-10-27 16:26:52 +02:00
2021-10-27 18:17:14 +02:00
// Compute the expressions that will be substituted for the pac_expectation operators
2021-10-28 14:42:56 +02:00
expr_t growth_correction_term = dynamic_model . Zero ;
if ( growth [ name ] )
growth_correction_term = dynamic_model . AddTimes ( growth [ name ] , dynamic_model . AddVariable ( growth_neutrality_params [ name ] ) ) ;
2021-10-27 18:17:14 +02:00
if ( aux_model_name [ name ] . empty ( ) )
2021-10-26 18:06:26 +02:00
{
2022-05-04 16:01:34 +02:00
if ( target_info . contains ( name ) )
2021-10-26 18:06:26 +02:00
{
cerr < < " ERROR: the block 'pac_target_info( " < < name < < " )' is not supported in the context of a PAC model with model-consistent expectations (MCE). " < < endl ;
exit ( EXIT_FAILURE ) ;
}
else
dynamic_model . computePacModelConsistentExpectationSubstitution ( name ,
symbol_table . getID ( discount [ name ] ) ,
pacEquationMaxLag ( name ) ,
growth_correction_term ,
2021-11-18 17:08:08 +01:00
auxname [ name ] ,
2021-10-26 18:06:26 +02:00
diff_subst_table ,
aux_var_symb_ids ,
aux_param_symb_ids ,
pac_expectation_substitution ) ;
}
2021-10-27 18:17:14 +02:00
else
2021-10-26 18:06:26 +02:00
{
2022-05-04 16:01:34 +02:00
if ( target_info . contains ( name ) )
2021-10-26 18:06:26 +02:00
{
assert ( growth_correction_term = = dynamic_model . Zero ) ;
dynamic_model . computePacBackwardExpectationSubstitutionWithComponents ( name , lhs [ name ] ,
max_lag ,
aux_model_type [ name ] ,
get < 2 > ( target_info [ name ] ) ,
pac_expectation_substitution ) ;
}
else
dynamic_model . computePacBackwardExpectationSubstitution ( name , lhs [ name ] , max_lag ,
aux_model_type [ name ] ,
growth_correction_term ,
2021-11-18 17:08:08 +01:00
auxname [ name ] ,
2021-10-26 18:06:26 +02:00
aux_var_symb_ids ,
aux_param_symb_ids ,
pac_expectation_substitution ) ;
}
2021-10-27 16:26:52 +02:00
}
2021-10-27 18:17:14 +02:00
// Actually perform the substitution of pac_expectation
2021-10-28 14:42:56 +02:00
dynamic_model . substitutePacExpectation ( pac_expectation_substitution , eq_name ) ;
2021-10-27 16:26:52 +02:00
dynamic_model . checkNoRemainingPacExpectation ( ) ;
2021-10-26 18:06:26 +02:00
// Check that there is no remaining pac_target_nonstationary operator
dynamic_model . checkNoRemainingPacTargetNonstationary ( ) ;
2021-10-27 16:26:52 +02:00
}
void
2022-06-24 15:45:35 +02:00
PacModelTable : : writeOutput ( ostream & output ) const
2021-10-27 16:26:52 +02:00
{
2021-10-26 18:06:26 +02:00
// Helper to print the “growth_info” structure (linear decomposition of growth)
auto growth_info_helper = [ & ] ( const string & fieldname , const growth_info_t & gi )
{
2022-06-03 16:24:26 +02:00
for ( int i { 1 } ;
auto [ growth_symb_id , growth_lag , param_id , constant ] : gi )
2021-10-26 18:06:26 +02:00
{
string structname = fieldname + " ( " + to_string ( i + + ) + " ). " ;
2022-05-16 17:42:24 +02:00
if ( growth_symb_id )
2021-10-26 18:06:26 +02:00
{
string var_field = " endo_id " ;
2022-05-16 17:42:24 +02:00
if ( symbol_table . getType ( * growth_symb_id ) = = SymbolType : : exogenous )
2021-10-26 18:06:26 +02:00
{
var_field = " exo_id " ;
output < < structname < < " endo_id = 0; " < < endl ;
}
else
output < < structname < < " exo_id = 0; " < < endl ;
try
{
// case when this is not the highest lag of the growth variable
2022-05-16 17:42:24 +02:00
int aux_symb_id = symbol_table . searchAuxiliaryVars ( * growth_symb_id , growth_lag ) ;
2021-10-26 18:06:26 +02:00
output < < structname < < var_field < < " = " < < symbol_table . getTypeSpecificID ( aux_symb_id ) + 1 < < " ; " < < endl
< < structname < < " lag = 0; " < < endl ;
}
catch ( . . . )
{
try
{
// case when this is the highest lag of the growth variable
int tmp_growth_lag = growth_lag + 1 ;
2022-05-16 17:42:24 +02:00
int aux_symb_id = symbol_table . searchAuxiliaryVars ( * growth_symb_id , tmp_growth_lag ) ;
2021-10-26 18:06:26 +02:00
output < < structname < < var_field < < " = " < < symbol_table . getTypeSpecificID ( aux_symb_id ) + 1 < < " ; " < < endl
< < structname < < " lag = -1; " < < endl ;
}
catch ( . . . )
{
// case when there is no aux var for the variable
2022-05-16 17:42:24 +02:00
output < < structname < < var_field < < " = " < < symbol_table . getTypeSpecificID ( * growth_symb_id ) + 1 < < " ; " < < endl
2021-10-26 18:06:26 +02:00
< < structname < < " lag = " < < growth_lag < < " ; " < < endl ;
}
}
}
else
output < < structname < < " endo_id = 0; " < < endl
< < structname < < " exo_id = 0; " < < endl
< < structname < < " lag = 0; " < < endl ;
output < < structname < < " param_id = "
2022-05-16 17:42:24 +02:00
< < ( param_id ? symbol_table . getTypeSpecificID ( * param_id ) + 1 : 0 ) < < " ; " < < endl
2021-10-26 18:06:26 +02:00
< < structname < < " constant = " < < constant < < " ; " < < endl ;
}
} ;
2021-10-27 16:26:52 +02:00
for ( const auto & name : names )
{
output < < " M_.pac. " < < name < < " .auxiliary_model_name = ' " < < aux_model_name . at ( name ) < < " '; " < < endl
< < " M_.pac. " < < name < < " .discount_index = " < < symbol_table . getTypeSpecificID ( discount . at ( name ) ) + 1 < < " ; " < < endl ;
if ( growth . at ( name ) )
{
output < < " M_.pac. " < < name < < " .growth_str = ' " ;
original_growth . at ( name ) - > writeJsonOutput ( output , { } , { } , true ) ;
output < < " '; " < < endl ;
2021-10-26 18:06:26 +02:00
growth_info_helper ( " M_.pac. " + name + " .growth_linear_comb " , growth_info . at ( name ) ) ;
2021-10-27 16:26:52 +02:00
}
}
2021-10-27 18:17:14 +02:00
2021-11-17 18:12:29 +01:00
// Write the auxiliary parameter IDs created for the pac_expectation operator
for ( auto & [ name , ids ] : aux_param_symb_ids )
2021-10-27 18:17:14 +02:00
{
2021-11-17 18:12:29 +01:00
output < < " M_.pac. " < < name < < " . " < < ( aux_model_name . at ( name ) . empty ( ) ? " mce.alpha " : " h_param_indices " ) < < " = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto id : ids )
output < < symbol_table . getTypeSpecificID ( id ) + 1 < < " " ;
output < < " ]; " < < endl ;
}
2021-11-16 17:58:20 +01:00
// Write the auxiliary variable IDs created for the pac_expectation operator
for ( auto & [ name , id ] : aux_var_symb_ids )
output < < " M_.pac. " < < name < < " . " < < ( aux_model_name . at ( name ) . empty ( ) ? " mce.z1 " : " aux_id " )
< < " = " < < symbol_table . getTypeSpecificID ( id ) + 1 < < " ; " < < endl ;
2021-10-27 18:17:14 +02:00
2021-10-28 14:42:56 +02:00
// Write PAC equation name info
for ( auto & [ name , eq ] : eq_name )
output < < " M_.pac. " < < name < < " .eq_name = ' " < < eq < < " '; " < < endl ;
2021-10-27 18:17:14 +02:00
for ( auto & [ model , growth_neutrality_param_index ] : growth_neutrality_params )
output < < " M_.pac. " < < model < < " .growth_neutrality_param_index = "
< < symbol_table . getTypeSpecificID ( growth_neutrality_param_index ) + 1 < < " ; " < < endl ;
for ( auto & [ model , type ] : aux_model_type )
output < < " M_.pac. " < < model < < " .auxiliary_model_type = ' " < < type < < " '; " < < endl ;
2021-11-18 17:08:08 +01:00
for ( auto & [ name , k ] : kind )
if ( ! aux_model_name . empty ( ) )
output < < " M_.pac. " < < name < < " .kind = ' "
< < ( k = = PacTargetKind : : unspecified ? " " : kindToString ( k ) ) < < " '; " < < endl ;
2021-10-28 14:42:56 +02:00
for ( auto & [ name , val ] : equation_info )
2021-10-27 18:17:14 +02:00
{
2022-05-16 17:42:24 +02:00
auto & [ lhs_pac_var , optim_share_index , ar_params_and_vars , ec_params_and_vars , non_optim_vars_params_and_constants , additive_vars_params_and_constants , optim_additive_vars_params_and_constants ] = val ;
2021-10-28 14:42:56 +02:00
output < < " M_.pac. " < < name < < " .lhs_var = "
2021-10-27 18:17:14 +02:00
< < symbol_table . getTypeSpecificID ( lhs_pac_var . first ) + 1 < < " ; " < < endl ;
2022-05-16 17:42:58 +02:00
if ( optim_share_index )
2021-10-28 14:42:56 +02:00
output < < " M_.pac. " < < name < < " .share_of_optimizing_agents_index = "
2022-05-16 17:42:58 +02:00
< < symbol_table . getTypeSpecificID ( * optim_share_index ) + 1 < < " ; " < < endl ;
2021-10-27 18:17:14 +02:00
2021-10-28 14:42:56 +02:00
output < < " M_.pac. " < < name < < " .ec.params = "
2021-10-27 18:17:14 +02:00
< < symbol_table . getTypeSpecificID ( ec_params_and_vars . first ) + 1 < < " ; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ec.vars = [ " ;
2022-05-16 17:42:24 +02:00
for ( auto & it : ec_params_and_vars . second )
2021-10-27 18:17:14 +02:00
output < < symbol_table . getTypeSpecificID ( get < 0 > ( it ) ) + 1 < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ec.istarget = [ " ;
2022-05-16 17:42:24 +02:00
for ( auto & it : ec_params_and_vars . second )
2022-05-16 12:26:21 +02:00
output < < boolalpha < < get < 1 > ( it ) < < " " ;
2021-10-27 18:17:14 +02:00
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ec.scale = [ " ;
2022-05-16 17:42:24 +02:00
for ( auto & it : ec_params_and_vars . second )
2021-10-27 18:17:14 +02:00
output < < get < 2 > ( it ) < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ec.isendo = [ " ;
2022-05-16 17:42:24 +02:00
for ( auto & it : ec_params_and_vars . second )
2021-10-27 18:17:14 +02:00
switch ( symbol_table . getType ( get < 0 > ( it ) ) )
{
case SymbolType : : endogenous :
output < < " true " ;
break ;
case SymbolType : : exogenous :
output < < " false " ;
break ;
default :
cerr < < " expecting endogenous or exogenous " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ar.params = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & [ pid , vid , vlag ] : ar_params_and_vars )
2022-05-16 17:42:24 +02:00
output < < ( pid ? symbol_table . getTypeSpecificID ( * pid ) + 1 : - 1 ) < < " " ;
2021-10-27 18:17:14 +02:00
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ar.vars = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & [ pid , vid , vlag ] : ar_params_and_vars )
2022-05-16 17:42:24 +02:00
output < < ( vid ? symbol_table . getTypeSpecificID ( * vid ) + 1 : - 1 ) < < " " ;
2021-10-27 18:17:14 +02:00
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .ar.lags = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & [ pid , vid , vlag ] : ar_params_and_vars )
output < < vlag < < " " ;
2021-10-28 14:42:56 +02:00
output < < " ]; " < < endl
< < " M_.pac. " < < name < < " .max_lag = " < < pacEquationMaxLag ( name ) < < " ; " < < endl ;
2021-10-27 18:17:14 +02:00
if ( ! non_optim_vars_params_and_constants . empty ( ) )
{
2021-10-28 14:42:56 +02:00
output < < " M_.pac. " < < name < < " .non_optimizing_behaviour.params = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : non_optim_vars_params_and_constants )
2022-05-16 17:42:24 +02:00
if ( get < 2 > ( it ) )
output < < symbol_table . getTypeSpecificID ( * get < 2 > ( it ) ) + 1 < < " " ;
2021-10-27 18:17:14 +02:00
else
output < < " NaN " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .non_optimizing_behaviour.vars = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : non_optim_vars_params_and_constants )
output < < symbol_table . getTypeSpecificID ( get < 0 > ( it ) ) + 1 < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .non_optimizing_behaviour.isendo = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : non_optim_vars_params_and_constants )
switch ( symbol_table . getType ( get < 0 > ( it ) ) )
{
case SymbolType : : endogenous :
output < < " true " ;
break ;
case SymbolType : : exogenous :
output < < " false " ;
break ;
default :
cerr < < " expecting endogenous or exogenous " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .non_optimizing_behaviour.lags = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : non_optim_vars_params_and_constants )
output < < get < 1 > ( it ) < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .non_optimizing_behaviour.scaling_factor = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : non_optim_vars_params_and_constants )
output < < get < 3 > ( it ) < < " " ;
output < < " ]; " < < endl ;
}
if ( ! additive_vars_params_and_constants . empty ( ) )
{
2021-10-28 14:42:56 +02:00
output < < " M_.pac. " < < name < < " .additive.params = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : additive_vars_params_and_constants )
2022-05-16 17:42:24 +02:00
if ( get < 2 > ( it ) )
output < < symbol_table . getTypeSpecificID ( * get < 2 > ( it ) ) + 1 < < " " ;
2021-10-27 18:17:14 +02:00
else
output < < " NaN " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .additive.vars = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : additive_vars_params_and_constants )
output < < symbol_table . getTypeSpecificID ( get < 0 > ( it ) ) + 1 < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .additive.isendo = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : additive_vars_params_and_constants )
switch ( symbol_table . getType ( get < 0 > ( it ) ) )
{
case SymbolType : : endogenous :
output < < " true " ;
break ;
case SymbolType : : exogenous :
output < < " false " ;
break ;
default :
cerr < < " expecting endogenous or exogenous " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .additive.lags = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : additive_vars_params_and_constants )
output < < get < 1 > ( it ) < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .additive.scaling_factor = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : additive_vars_params_and_constants )
output < < get < 3 > ( it ) < < " " ;
output < < " ]; " < < endl ;
}
if ( ! optim_additive_vars_params_and_constants . empty ( ) )
{
2021-10-28 14:42:56 +02:00
output < < " M_.pac. " < < name < < " .optim_additive.params = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : optim_additive_vars_params_and_constants )
2022-05-16 17:42:24 +02:00
if ( get < 2 > ( it ) )
output < < symbol_table . getTypeSpecificID ( * get < 2 > ( it ) ) + 1 < < " " ;
2021-10-27 18:17:14 +02:00
else
output < < " NaN " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .optim_additive.vars = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : optim_additive_vars_params_and_constants )
output < < symbol_table . getTypeSpecificID ( get < 0 > ( it ) ) + 1 < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .optim_additive.isendo = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : optim_additive_vars_params_and_constants )
switch ( symbol_table . getType ( get < 0 > ( it ) ) )
{
case SymbolType : : endogenous :
output < < " true " ;
break ;
case SymbolType : : exogenous :
output < < " false " ;
break ;
default :
cerr < < " expecting endogenous or exogenous " < < endl ;
exit ( EXIT_FAILURE ) ;
}
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .optim_additive.lags = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : optim_additive_vars_params_and_constants )
output < < get < 1 > ( it ) < < " " ;
output < < " ]; " < < endl
2021-10-28 14:42:56 +02:00
< < " M_.pac. " < < name < < " .optim_additive.scaling_factor = [ " ;
2021-10-27 18:17:14 +02:00
for ( auto & it : optim_additive_vars_params_and_constants )
output < < get < 3 > ( it ) < < " " ;
output < < " ]; " < < endl ;
}
}
2021-10-26 18:06:26 +02:00
for ( auto & [ name , val ] : target_info )
2022-06-03 16:24:26 +02:00
for ( int component_idx { 1 } ;
auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : get < 2 > ( val ) )
{
string fieldname = " M_.pac. " + name + " .components( " + to_string ( component_idx ) + " ) " ;
output < < fieldname < < " .aux_id = " < < symbol_table . getTypeSpecificID ( auxname ) + 1 < < " ; " < < endl
< < fieldname < < " .endo_var = " < < symbol_table . getTypeSpecificID ( dynamic_cast < VariableNode * > ( component ) - > symb_id ) + 1 < < " ; " < < endl
< < fieldname < < " .kind = ' " < < kindToString ( kind ) < < " '; " < < endl
< < fieldname < < " .h_param_indices = [ " ;
for ( int id : h_indices )
output < < symbol_table . getTypeSpecificID ( id ) + 1 < < " " ;
output < < " ]; " < < endl
< < fieldname < < " .coeff_str = ' " ;
coeff - > writeJsonOutput ( output , { } , { } , true ) ;
output < < " '; " < < endl ;
if ( growth_component )
{
output < < fieldname < < " .growth_neutrality_param_index = " < < symbol_table . getTypeSpecificID ( growth_neutrality_param ) + 1 < < " ; " < < endl
< < fieldname < < " .growth_str = ' " ;
original_growth_component - > writeJsonOutput ( output , { } , { } , true ) ;
output < < " '; " < < endl ;
growth_info_helper ( fieldname + " .growth_linear_comb " , growth_component_info ) ;
}
component_idx + + ;
}
2021-10-27 16:26:52 +02:00
}
void
PacModelTable : : writeJsonOutput ( ostream & output ) const
{
2022-06-03 16:24:26 +02:00
for ( bool printed_something { false } ;
const auto & name : names )
2021-10-27 16:26:52 +02:00
{
2021-10-26 18:06:26 +02:00
/* The calling method has already added a comma, so don’ t output one for
the first statement */
2022-06-03 16:24:26 +02:00
if ( exchange ( printed_something , true ) )
2021-10-27 16:26:52 +02:00
output < < " , " ;
output < < R " ({ " statementName " : " pac_model " ,) "
< < R " ( " model_name " : " ) " << name << R " ( " ,) "
< < R " ( " auxiliary_model_name " : " ) " << aux_model_name.at(name) << R " ( " ,) "
< < R " ( " discount_index " : ) " < < symbol_table . getTypeSpecificID ( discount . at ( name ) ) + 1 ;
if ( growth . at ( name ) )
{
output < < R " (, " growth_str " : " ) " ;
original_growth . at ( name ) - > writeJsonOutput ( output , { } , { } , true ) ;
output < < R " ( " ) " ;
}
output < < " } " < < endl ;
}
2021-10-26 18:06:26 +02:00
for ( auto & [ name , val ] : target_info )
{
output < < R " (, { " statementName " : " pac_target_info " , " model_name " : " ) " << name
< < R " ( " , " target " : " ) " ;
get < 0 > ( val ) - > writeJsonOutput ( output , { } , { } , true ) ;
output < < R " ( " , " auxname_target_nonstationary " : " ) " < < get < 1 > ( val )
< < R " ( " , " components " : [ ) " ;
for ( auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : get < 2 > ( val ) )
{
if ( component ! = get < 0 > ( get < 2 > ( val ) . front ( ) ) )
output < < " , " ;
output < < R " ({ " component " : " ) " ;
component - > writeJsonOutput ( output , { } , { } , true ) ;
output < < R " ( " , " auxname " : " ) " < < auxname
< < R " ( " , " kind " : " ) " < < kindToString ( kind ) ;
if ( growth_component )
{
output < < R " ( " , " growth_str " : " ) " ;
original_growth_component - > writeJsonOutput ( output , { } , { } , true ) ;
}
output < < R " ( " } ) " ;
}
output < < " ]} " < < endl ;
}
2021-10-27 16:26:52 +02:00
}
2021-10-28 14:42:56 +02:00
int
PacModelTable : : pacEquationMaxLag ( const string & name_arg ) const
{
return get < 2 > ( equation_info . at ( name_arg ) ) . size ( ) ;
}
2021-10-26 18:06:26 +02:00
string
PacModelTable : : kindToString ( PacTargetKind kind )
{
switch ( kind )
{
case PacTargetKind : : unspecified :
cerr < < " Internal error: kind should not be unspecified " < < endl ;
exit ( EXIT_FAILURE ) ;
case PacTargetKind : : ll :
return " ll " ;
case PacTargetKind : : dl :
return " dl " ;
case PacTargetKind : : dd :
return " dd " ;
}
// Silent GCC warning
assert ( false ) ;
}
void
PacModelTable : : setTargetExpr ( const string & name_arg , expr_t target )
{
get < 0 > ( target_info [ name_arg ] ) = target ;
}
void
PacModelTable : : setTargetAuxnameNonstationary ( const string & name_arg , string auxname )
{
get < 1 > ( target_info [ name_arg ] ) = move ( auxname ) ;
}
void
PacModelTable : : addTargetComponent ( const string & name_arg , target_component_t component )
{
get < 7 > ( component ) = get < 1 > ( component ) ; // original_growth = growth
get < 2 > ( target_info [ name_arg ] ) . emplace_back ( move ( component ) ) ;
}
void
PacModelTable : : writeTargetCoefficientsFile ( const string & basename ) const
{
if ( target_info . empty ( ) )
return ;
2022-10-11 15:59:56 +02:00
filesystem : : path filename { DataTree : : packageDir ( basename ) / " pac_target_coefficients.m " } ;
2022-07-11 16:09:07 +02:00
ofstream output { filename , ios : : out | ios : : binary } ;
2021-10-26 18:06:26 +02:00
if ( ! output . is_open ( ) )
{
2022-10-11 15:59:56 +02:00
cerr < < " ERROR: Can't open file " < < filename . string ( ) < < " for writing " < < endl ;
2021-10-26 18:06:26 +02:00
exit ( EXIT_FAILURE ) ;
}
output < < " function coeffs = pac_target_coefficients(model_name, params) " < < endl ;
for ( auto & [ model_name , val ] : target_info )
{
output < < " if strcmp(model_name, ' " < < model_name < < " ') " < < endl
< < " coeffs = NaN( " < < get < 2 > ( val ) . size ( ) < < " ,1); " < < endl ;
2022-06-03 16:24:26 +02:00
for ( int i { 1 } ;
auto & [ component , growth_component , auxname , kind , coeff , growth_neutrality_param , h_indices , original_growth_component , growth_component_info ] : get < 2 > ( val ) )
2021-10-26 18:06:26 +02:00
{
output < < " coeffs( " < < i + + < < " ) = " ;
coeff - > writeOutput ( output , ExprNodeOutputType : : matlabDynamicModel ) ;
output < < " ; " < < endl ;
}
output < < " return " < < endl
< < " end " < < endl ;
}
output < < " error([ 'Unknown PAC model: ' model_name ]) " < < endl
< < " end " < < endl ;
output . close ( ) ;
}