diff --git a/ComputingTasks.cc b/ComputingTasks.cc index 4cc96f966207086fcfa9e22d4b7e8424ff5043ca..08740ebcabd2daf4cdb62ddd3544ab3d4e09f341 100644 --- a/ComputingTasks.cc +++ b/ComputingTasks.cc @@ -27,6 +27,11 @@ using namespace std; #include "ComputingTasks.hh" #include "Statement.hh" +#include <boost/algorithm/string/trim.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/tokenizer.hpp> + SteadyStatement::SteadyStatement(const OptionsList &options_list_arg) : options_list(options_list_arg) { @@ -1345,6 +1350,144 @@ SvarIdentificationStatement::writeOutput(ostream &output, const string &basename MarkovSwitchingStatement::MarkovSwitchingStatement(const OptionsList &options_list_arg) : options_list(options_list_arg) { + OptionsList::num_options_t::const_iterator it_num = options_list.num_options.find("ms.restrictions"); + if (it_num != options_list.num_options.end()) + { + using namespace boost; + OptionsList::num_options_t::const_iterator it_num_regimes = + options_list.num_options.find("ms.number_of_regimes"); + if (it_num_regimes == options_list.num_options.end()) + { + cerr << "ERROR: should not arrive here: MarkovSwitchingStatement::checkPass" << endl; + exit(EXIT_FAILURE); + } + int num_regimes = lexical_cast< int >(it_num_regimes->second); + + vector<string> tokenizedRestrictions; + split(tokenizedRestrictions, it_num->second, is_any_of("["), token_compress_on); + for (vector<string>::iterator it = tokenizedRestrictions.begin(); + it != tokenizedRestrictions.end(); it++ ) + if (it->size() > 0) + { + vector<string> restriction; + split(restriction, *it, is_any_of("], ")); + for (vector<string>::iterator it1 = restriction.begin(); + it1 != restriction.end(); ) + if (it1->empty()) + restriction.erase(it1); + else + it1++; + + if (restriction.size() != 3) + { + cerr << "ERROR: restrictions in the subsample statement must be specified in the form " + << "[current_period_regime, next_period_regime, transition_probability]" << endl; + exit(EXIT_FAILURE); + } + + try + { + int from_regime = lexical_cast< int >(restriction[0]); + int to_regime = lexical_cast< int >(restriction[1]); + if (from_regime > num_regimes || to_regime > num_regimes) + { + cerr << "ERROR: the regimes specified in the restrictions option must be " + << "<= the number of regimes specified in the number_of_regimes option" << endl; + exit(EXIT_FAILURE); + } + + if (restriction_map.find(make_pair(from_regime, to_regime)) != + restriction_map.end()) + { + cerr << "ERROR: two restrictions were given for: " << from_regime << ", " + << to_regime << endl; + exit(EXIT_FAILURE); + } + + double transition_probability = lexical_cast< double >(restriction[2]); + if (transition_probability > 1.0) + { + cerr << "ERROR: the transition probability, " << transition_probability + << " must be less than 1" << endl; + exit(EXIT_FAILURE); + } + restriction_map[make_pair(from_regime, to_regime)] = transition_probability; + } + catch (const bad_lexical_cast &) + { + cerr << "ERROR: The first two arguments for a restriction must be integers " + << "specifying the regime and the last must be a double specifying the " + << "transition probability. You wrote [" << *it << endl; + exit(EXIT_FAILURE); + } + } + } +} + +void +MarkovSwitchingStatement::checkPass(ModFileStructure &mod_file_struct) +{ + OptionsList::num_options_t::const_iterator it_num = options_list.num_options.find("ms.restrictions"); + if (it_num != options_list.num_options.end()) + { + using namespace boost; + OptionsList::num_options_t::const_iterator it_num_regimes = + options_list.num_options.find("ms.number_of_regimes"); + int num_regimes = lexical_cast< int >(it_num_regimes->second); + vector<double> col_trans_prob_sum (num_regimes, 0); + vector<double> row_trans_prob_sum (num_regimes, 0); + vector<bool> all_restrictions_in_row (num_regimes, true); + vector<bool> all_restrictions_in_col (num_regimes, true); + for (int row=0; row<num_regimes; row++) + for (int col=0; col<num_regimes; col++) + if (restriction_map.find(make_pair(row+1, col+1)) != restriction_map.end()) + { + row_trans_prob_sum[row] += restriction_map[make_pair(row+1, col+1)]; + col_trans_prob_sum[col] += restriction_map[make_pair(row+1, col+1)]; + } + else + { + all_restrictions_in_row[row] = false; + all_restrictions_in_col[col] = false; + } + + for (int i=0; i<num_regimes; i++) + { + if (all_restrictions_in_row[i]) + { + if (row_trans_prob_sum[i] != 1.0) + { + cerr << "ERROR: When all transitions probabilities are specified for a certain " + << "regime, they must sum to 1" << endl; + exit(EXIT_FAILURE); + } + } + else + if (row_trans_prob_sum[i] >= 1.0) + { + cerr << "ERROR: When transition probabilites are not specified for every regime, " + << "their sum must be < 1" << endl; + exit(EXIT_FAILURE); + } + + if (all_restrictions_in_col[i]) + { + if (col_trans_prob_sum[i] != 1.0) + { + cerr << "ERROR: When all transitions probabilities are specified for a certain " + << "regime, they must sum to 1" << endl; + exit(EXIT_FAILURE); + } + } + else + if (col_trans_prob_sum[i] >= 1.0) + { + cerr << "ERROR: When transition probabilites are not specified for every regime, " + << "their sum must be < 1" << endl; + exit(EXIT_FAILURE); + } + } + } } void @@ -1353,18 +1496,21 @@ MarkovSwitchingStatement::writeOutput(ostream &output, const string &basename) c bool isDurationAVec = true; string infStr("Inf"); OptionsList::num_options_t::const_iterator itChain, itNOR, itDuration; + map<pair<int, int>, double >::const_iterator itR; itChain = options_list.num_options.find("ms.chain"); if (itChain == options_list.num_options.end()) { - cerr << "MarkovSwitchingStatement::writeOutput() Should not arrive here (1). Please report this to the Dynare Team." << endl; + cerr << "MarkovSwitchingStatement::writeOutput() Should not arrive here (1). " + << "Please report this to the Dynare Team." << endl; exit(EXIT_FAILURE); } itDuration = options_list.num_options.find("ms.duration"); if (itDuration == options_list.num_options.end()) { - cerr << "MarkovSwitchingStatement::writeOutput() Should not arrive here (2). Please report this to the Dynare Team." << endl; + cerr << "MarkovSwitchingStatement::writeOutput() Should not arrive here (2). " + << "Please report this to the Dynare Team." << endl; exit(EXIT_FAILURE); } else if (atof(itDuration->second.c_str()) || infStr.compare(itDuration->second) == 0) @@ -1383,9 +1529,16 @@ MarkovSwitchingStatement::writeOutput(ostream &output, const string &basename) c } else { - cerr << "MarkovSwitchingStatement::writeOutput() Should not arrive here (3). Please report this to the Dynare Team." << endl; + cerr << "MarkovSwitchingStatement::writeOutput() Should not arrive here (3). " + << "Please report this to the Dynare Team." << endl; exit(EXIT_FAILURE); } + + int restrictions_index = 0; + for (itR=restriction_map.begin(); itR != restriction_map.end(); itR++) + output << "options_.ms.ms_chain(" << itChain->second << ").restrictions(" + << ++restrictions_index << ") = {[" << itR->first.first << ", " + << itR->first.second << ", " << itR->second << "]};" << endl; } SvarStatement::SvarStatement(const OptionsList &options_list_arg) : diff --git a/ComputingTasks.hh b/ComputingTasks.hh index 397139aeb7483a173f9d3618e7cca6aca54c1336..bba0176e07903ebeaaa6f7a49b0e6f37dcfdbcc8 100644 --- a/ComputingTasks.hh +++ b/ComputingTasks.hh @@ -542,8 +542,10 @@ class MarkovSwitchingStatement : public Statement { private: const OptionsList options_list; + map <pair<int, int >, double > restriction_map; public: MarkovSwitchingStatement(const OptionsList &options_list_arg); + virtual void checkPass(ModFileStructure &mod_file_struct); virtual void writeOutput(ostream &output, const string &basename) const; }; diff --git a/DynareBison.yy b/DynareBison.yy index edbc812c8b2648e621128f4db5bd94ca6f2dd8bf..7df717480940bae01c6b73720cece444a760f527 100644 --- a/DynareBison.yy +++ b/DynareBison.yy @@ -151,7 +151,7 @@ class ParsingDriver; %token GSIG2_LMDM Q_DIAG FLAT_PRIOR NCSK NSTD %token INDXPARR INDXOVR INDXAP APBAND INDXIMF IMFBAND INDXFORE FOREBAND INDXGFOREHAT INDXGIMFHAT %token INDXESTIMA INDXGDLS EQ_MS FILTER_COVARIANCE FILTER_DECOMPOSITION -%token EQ_CMS TLINDX TLNUMBER BANACT +%token EQ_CMS TLINDX TLNUMBER BANACT RESTRICTIONS %token OUTPUT_FILE_TAG DRAWS_NBR_BURN_IN_1 DRAWS_NBR_BURN_IN_2 HORIZON %token SBVAR TREND_VAR DEFLATOR GROWTH_FACTOR MS_IRF MS_VARIANCE_DECOMPOSITION %token MS_ESTIMATION MS_SIMULATION MS_COMPUTE_MDD MS_COMPUTE_PROBABILITIES MS_FORECAST @@ -175,7 +175,7 @@ class ParsingDriver; %type <node_val> expression expression_or_empty %type <node_val> equation hand_side %type <string_val> non_negative_number signed_number signed_integer date_number -%type <string_val> filename symbol prior_distribution +%type <string_val> filename symbol prior_distribution vec_of_vec_value vec_value_list %type <string_val> vec_value_1 vec_value signed_inf signed_number_w_inf %type <string_val> range prior_pdf_string vec_value_w_inf vec_value_1_w_inf %type <symbol_type_val> change_type_arg @@ -741,6 +741,7 @@ ms_options_list : ms_options_list COMMA ms_options ms_options : o_chain | o_duration + | o_restrictions | o_number_of_regimes ; @@ -2219,6 +2220,9 @@ o_cnum : CNUM EQUAL INT_NUMBER {driver.option_num("ms.cnum",$3); }; o_k_order_solver : K_ORDER_SOLVER {driver.option_num("k_order_solver","1"); }; o_pruning : PRUNING { driver.option_num("pruning", "1"); }; o_chain : CHAIN EQUAL INT_NUMBER { driver.option_num("ms.chain",$3); }; +o_restrictions : RESTRICTIONS EQUAL vec_of_vec_value + { driver.option_num("ms.restrictions",$3); } + ; o_duration : DURATION EQUAL non_negative_number { driver.option_num("ms.duration",$3); } | DURATION EQUAL vec_value_w_inf @@ -2384,6 +2388,20 @@ vec_value : vec_value_1 ']' { $1->append("]"); $$ = $1; } | vec_value_1 COMMA ']' { $1->append("]"); $$ = $1; } ; +vec_value_list : vec_value_list COMMA vec_value + { + $1->append(","); + $1->append(*$3); + delete $3; + $$ = $1; + } + | vec_value + { $$ = $1; } + ; + +vec_of_vec_value : '[' vec_value_list ']' { $$ = $2; } + | vec_value { $$ = $1; }; + vec_value_1_w_inf : '[' signed_number_w_inf { $2->insert(0, "["); $$ = $2;} | vec_value_1_w_inf signed_number_w_inf diff --git a/DynareFlex.ll b/DynareFlex.ll index 824476d993e8709c151ba8c3e299d87a3f6c1c34..2d91d096e1330661937395ceac979b689a4cf6e0 100644 --- a/DynareFlex.ll +++ b/DynareFlex.ll @@ -282,6 +282,7 @@ string eofbuff; <DYNARE_STATEMENT>vlistper {return token::VLISTPER;} <DYNARE_STATEMENT>restriction_fname {return token::RESTRICTION_FNAME;} <DYNARE_STATEMENT>nlags {return token::NLAGS;} +<DYNARE_STATEMENT>restrictions {return token::RESTRICTIONS;} <DYNARE_STATEMENT>cross_restrictions {return token::CROSS_RESTRICTIONS;} <DYNARE_STATEMENT>contemp_reduced_form {return token::CONTEMP_REDUCED_FORM;} <DYNARE_STATEMENT>real_pseudo_forecast {return token::REAL_PSEUDO_FORECAST;}