From 08c710676ae4c94c06c9350e1950f9c29fc5295e Mon Sep 17 00:00:00 2001
From: Willi Mutschler <willi@mutschler.eu>
Date: Sat, 30 Sep 2023 11:13:21 +0200
Subject: [PATCH] irf matching: add perfect-foresight option

---
 src/ComputingTasks.cc |  7 ++++++-
 src/DynareBison.yy    |  6 ++++--
 src/DynareFlex.ll     |  1 +
 src/ModFile.cc        | 22 +++++++++++++---------
 src/ParsingDriver.hh  |  2 +-
 src/Statement.hh      |  6 ++++--
 6 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc
index d77f040d..3625f3b9 100644
--- a/src/ComputingTasks.cc
+++ b/src/ComputingTasks.cc
@@ -5096,7 +5096,12 @@ void
 MethodOfMomentsStatement::checkPass(ModFileStructure &mod_file_struct,
                                     [[maybe_unused]] WarningConsolidation &warnings)
 {
-  mod_file_struct.mom_estimation_present = true;
+  if (auto opt = options_list.get_if<OptionsList::StringVal>("mom.simulation_method");
+      opt && *opt == "PERFECT_FORESIGHT")
+    mod_file_struct.mom_estimation_perfect_foresight_present = true;
+  else
+    mod_file_struct.mom_estimation_stochastic_present = true;
+    
   // Fill in option_order of mod_file_struct
   if (auto opt = options_list.get_if<OptionsList::NumVal>("order"))
     {
diff --git a/src/DynareBison.yy b/src/DynareBison.yy
index ba6c3d73..f51cf5fc 100644
--- a/src/DynareBison.yy
+++ b/src/DynareBison.yy
@@ -180,7 +180,7 @@ class ParsingDriver;
 %token PAC_TARGET_INFO COMPONENT TARGET AUXNAME AUXNAME_TARGET_NONSTATIONARY PAC_TARGET_NONSTATIONARY
 %token <string> KIND LL DL DD ADD MULTIPLY
 /* Method of Moments */
-%token GMM SMM IRF_MATCHING
+%token GMM SMM IRF_MATCHING PERFECT_FORESIGHT
 %token METHOD_OF_MOMENTS MOM_METHOD SIMULATION_METHOD
 %token BARTLETT_KERNEL_LAG WEIGHTING_MATRIX WEIGHTING_MATRIX_SCALING_FACTOR ANALYTIC_STANDARD_ERRORS ANALYTIC_JACOBIAN PENALIZED_ESTIMATOR VERBOSE
 %token SIMULATION_MULTIPLE MOM_SEED SEED BOUNDED_SHOCK_SUPPORT ADDITIONAL_OPTIMIZER_STEPS MOM_SE_TOLX SE_TOLX MOM_BURNIN BURNIN
@@ -4149,7 +4149,9 @@ o_mom_method : MOM_METHOD EQUAL GMM
              | MOM_METHOD EQUAL IRF_MATCHING
                { driver.option_str("mom.mom_method", "IRF_MATCHING"); };
 o_simulation_method : SIMULATION_METHOD EQUAL STOCH_SIMUL
-               { driver.option_str("mom.simulation_method", "STOCH_SIMUL"); };
+               { driver.option_str("mom.simulation_method", "STOCH_SIMUL"); }
+             | SIMULATION_METHOD EQUAL PERFECT_FORESIGHT
+               { driver.option_str("mom.simulation_method", "PERFECT_FORESIGHT"); };
 o_penalized_estimator : PENALIZED_ESTIMATOR { driver.option_num("mom.penalized_estimator", "true"); };
 o_verbose : VERBOSE { driver.option_num("mom.verbose", "true"); };
 o_simulation_multiple : SIMULATION_MULTIPLE EQUAL INT_NUMBER { driver.option_num("mom.simulation_multiple", $3); };
diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll
index 921d716f..57078599 100644
--- a/src/DynareFlex.ll
+++ b/src/DynareFlex.ll
@@ -736,6 +736,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <DYNARE_STATEMENT>smm {return token::SMM;}
 <DYNARE_STATEMENT>irf_matching {return token::IRF_MATCHING;}
 <DYNARE_STATEMENT>stoch_simul {return token::STOCH_SIMUL;}
+<DYNARE_STATEMENT>perfect_foresight {return token::PERFECT_FORESIGHT;}
 <DYNARE_STATEMENT>weighting_matrix {return token::WEIGHTING_MATRIX; }
 <DYNARE_STATEMENT>weighting_matrix_scaling_factor {return token::WEIGHTING_MATRIX_SCALING_FACTOR; }
 <DYNARE_STATEMENT>analytic_standard_errors {return token::ANALYTIC_STANDARD_ERRORS; }
diff --git a/src/ModFile.cc b/src/ModFile.cc
index ab261c46..b6a96b2f 100644
--- a/src/ModFile.cc
+++ b/src/ModFile.cc
@@ -135,7 +135,7 @@ ModFile::checkPass(bool nostrict, bool stochastic)
     || mod_file_struct.discretionary_policy_present
     || mod_file_struct.calib_smoother_present
     || mod_file_struct.identification_present
-    || mod_file_struct.mom_estimation_present
+    || mod_file_struct.mom_estimation_stochastic_present
     || mod_file_struct.sensitivity_present
     || stochastic;
 
@@ -144,6 +144,7 @@ ModFile::checkPass(bool nostrict, bool stochastic)
       && (mod_file_struct.check_present
           || mod_file_struct.perfect_foresight_solver_present
           || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present
+          || mod_file_struct.mom_estimation_perfect_foresight_present
           || stochastic_statement_present))
     {
       cerr << "ERROR: At least one model equation must be declared!" << endl;
@@ -179,7 +180,7 @@ ModFile::checkPass(bool nostrict, bool stochastic)
       exit(EXIT_FAILURE);
     }
 
-  if ((mod_file_struct.perfect_foresight_solver_present || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present)
+  if ((mod_file_struct.perfect_foresight_solver_present || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present || mod_file_struct.mom_estimation_perfect_foresight_present)
       && stochastic_statement_present)
     {
       cerr << "ERROR: A .mod file cannot contain both one of {perfect_foresight_solver, simul, perfect_foresight_with_expectation_errors_solver} and one of {stoch_simul, estimation, osr, ramsey_policy, discretionary_policy}. This is not possible: one cannot mix perfect foresight context with stochastic context in the same file." << endl;
@@ -307,6 +308,7 @@ ModFile::checkPass(bool nostrict, bool stochastic)
   if (linear
       && !mod_file_struct.perfect_foresight_solver_present
       && !mod_file_struct.perfect_foresight_with_expectation_errors_solver_present
+      && !mod_file_struct.mom_estimation_perfect_foresight_present
       && (dynamic_model.isUnaryOpUsedOnType(SymbolType::exogenous, UnaryOpcode::sign)
           || dynamic_model.isUnaryOpUsedOnType(SymbolType::exogenous, UnaryOpcode::abs)
           || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::max)
@@ -518,7 +520,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool
                                || mod_file_struct.discretionary_policy_present
                                || mod_file_struct.calib_smoother_present
                                || mod_file_struct.identification_present
-                               || mod_file_struct.mom_estimation_present
+                               || mod_file_struct.mom_estimation_stochastic_present
                                || mod_file_struct.sensitivity_present
                                || stochastic);
   dynamic_model.substituteEndoLeadGreaterThanTwo(deterministic_model);
@@ -570,7 +572,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool
     }
 
   if (symbol_table.exo_det_nbr() > 0
-      && (mod_file_struct.perfect_foresight_solver_present || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present))
+      && (mod_file_struct.perfect_foresight_solver_present || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present || mod_file_struct.mom_estimation_perfect_foresight_present))
     {
       cerr << "ERROR: A .mod file cannot contain both one of {perfect_foresight_solver, simul, perfect_foresight_with_expectation_errors_solver} and varexo_det declaration (all exogenous variables are deterministic in this case)" << endl;
       exit(EXIT_FAILURE);
@@ -589,7 +591,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool
     }
 
   if (mod_file_struct.occbin_constraints_present
-      && (mod_file_struct.osr_present || mod_file_struct.mom_estimation_present
+      && (mod_file_struct.osr_present || mod_file_struct.mom_estimation_perfect_foresight_present || mod_file_struct.mom_estimation_stochastic_present
           || mod_file_struct.ramsey_model_present
           || mod_file_struct.discretionary_policy_present || mod_file_struct.extended_path_present
           || mod_file_struct.identification_present || mod_file_struct.sensitivity_present))
@@ -660,7 +662,7 @@ ModFile::computingPass(bool no_tmp_terms, OutputType output, int params_derivs_o
           if (mod_file_struct.stoch_simul_present
               || mod_file_struct.estimation_present || mod_file_struct.osr_present
               || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present
-              || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present)
+              || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_stochastic_present)
             static_model.set_cutoff_to_zero();
 
           int derivsOrder = 1;
@@ -686,10 +688,12 @@ ModFile::computingPass(bool no_tmp_terms, OutputType output, int params_derivs_o
           || mod_file_struct.stoch_simul_present
           || mod_file_struct.estimation_present || mod_file_struct.osr_present
           || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present
-          || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present)
+          || mod_file_struct.calib_smoother_present
+          || mod_file_struct.mom_estimation_perfect_foresight_present || mod_file_struct.mom_estimation_stochastic_present)
         {
           if (mod_file_struct.perfect_foresight_solver_present
-              || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present)
+              || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present
+              || mod_file_struct.mom_estimation_perfect_foresight_present)
             {
               int derivsOrder = 1;
               if (output == OutputType::second)
@@ -703,7 +707,7 @@ ModFile::computingPass(bool no_tmp_terms, OutputType output, int params_derivs_o
               if (mod_file_struct.stoch_simul_present
                   || mod_file_struct.estimation_present || mod_file_struct.osr_present
                   || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present
-                  || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present)
+                  || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_stochastic_present)
                 dynamic_model.set_cutoff_to_zero();
               if (mod_file_struct.order_option < 1)
                 {
diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh
index 7ccee5e3..a6d0282c 100644
--- a/src/ParsingDriver.hh
+++ b/src/ParsingDriver.hh
@@ -507,7 +507,7 @@ public:
   void linear();
   //! Writes a rplot() command
   void rplot(vector<string> symbol_list);
-  //! Writes a stock_simul command
+  //! Writes a stoch_simul command
   void stoch_simul(SymbolList symbol_list);
   //! Writes a trend component command
   void trend_component_model();
diff --git a/src/Statement.hh b/src/Statement.hh
index 6a8bdc7f..913a0cab 100644
--- a/src/Statement.hh
+++ b/src/Statement.hh
@@ -80,8 +80,10 @@ struct ModFileStructure
   bool partial_information{false};
   //! Whether the "k_order_solver" option is used (explictly, or implicitly if order >= 3)
   bool k_order_solver{false};
-  //! Whether an method_of_moments statement is present
-  bool mom_estimation_present{false};
+  //! Whether a method_of_moments statement that relies on the stochastic model is present
+  bool mom_estimation_perfect_foresight_present{false};
+  //! Whether a method_of_moments statement that relies on the deterministic model is present
+  bool mom_estimation_stochastic_present{false};
   //! Whether an GMM-option is present
   bool GMM_present{false};
   //! Whether an analytic_standard_errors-option is present
-- 
GitLab