From 08ac455fcddd032058738669ed6a84fda9c76e05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Thu, 15 Jul 2021 16:24:21 +0200
Subject: [PATCH] =?UTF-8?q?Implement=20=E2=80=9Coccbin=5Fconstraints?=
 =?UTF-8?q?=E2=80=9D=20block?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Consequently drop “occbin” option to “model”.

Incidentally, allow more values in equation tag names (previously some keywords
such as “alpha” were disallowed).

Ref. #68
---
 src/ComputingTasks.cc | 67 +++++++++++++++++++++++++++++++++++++++++++
 src/ComputingTasks.hh | 14 +++++++++
 src/DynamicModel.cc   |  4 ---
 src/DynareBison.yy    | 57 ++++++++++++++++++++++++++++++++----
 src/DynareFlex.ll     | 18 +++++++++++-
 src/EquationTags.cc   | 37 ------------------------
 src/EquationTags.hh   |  5 ----
 src/ModFile.cc        | 19 ++++--------
 src/ModFile.hh        |  3 --
 src/ModelTree.cc      |  6 ----
 src/ModelTree.hh      |  4 ---
 src/ParsingDriver.cc  | 28 ++++++++++++++----
 src/ParsingDriver.hh  |  6 ++--
 src/Statement.hh      |  2 ++
 14 files changed, 182 insertions(+), 88 deletions(-)

diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc
index d57356c9..14618870 100644
--- a/src/ComputingTasks.cc
+++ b/src/ComputingTasks.cc
@@ -5233,3 +5233,70 @@ MatchedMomentsStatement::writeJsonOutput(ostream &output) const
     }
   output << "]}" << endl;
 }
+
+OccbinConstraintsStatement::OccbinConstraintsStatement(const SymbolTable &symbol_table_arg,
+                                                       const vector<tuple<string, expr_t, expr_t, expr_t, expr_t>> constraints_arg)
+  : symbol_table{symbol_table_arg}, constraints{constraints_arg}
+{
+}
+
+void
+OccbinConstraintsStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings)
+{
+  if (mod_file_struct.occbin_constraints_present)
+    {
+      cerr << "ERROR: Multiple 'occbin_constraints' blocks are not allowed" << endl;
+      exit(EXIT_FAILURE);
+    }
+  mod_file_struct.occbin_constraints_present = true;
+}
+
+void
+OccbinConstraintsStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
+{
+  output << "M_.occbin.constraint = [" << endl;
+  for (const auto &[name, bind, relax, error_bind, error_relax] : constraints)
+    {
+      output << "struct('pswitch','" << name << "','bind','";
+      bind->writeJsonOutput(output, {}, {});
+      output << "','relax','";
+      if (relax)
+        relax->writeJsonOutput(output, {}, {});
+      output << "','error_bind','";
+      if (error_bind)
+        error_bind->writeJsonOutput(output, {}, {});
+      output << "','error_relax','";
+      if (error_relax)
+        error_relax->writeJsonOutput(output, {}, {});
+      output << "');" << endl;
+    }
+  output << "];" << endl
+         << "[M_, oo_, options_] = occbin.initialize(M_, oo_, options_);" << endl;
+}
+
+void
+OccbinConstraintsStatement::writeJsonOutput(ostream &output) const
+{
+  output << R"({"statementName": "occbin_constraints", "constraints": [)" << endl;
+  for (auto it = constraints.begin(); it != constraints.end(); ++it)
+    {
+      auto [name, bind, relax, error_bind, error_relax] = *it;
+
+      output << R"({ "name": ")" << name << R"(", "bind": ")";
+      bind->writeJsonOutput(output, {}, {});
+      output << R"(", "relax": ")";
+      if (relax)
+        relax->writeJsonOutput(output, {}, {});
+      output << R"(", "error_bind": ")";
+      if (error_bind)
+        error_bind->writeJsonOutput(output, {}, {});
+      output << R"(", "error_relax": ")";
+      if (error_relax)
+        error_relax->writeJsonOutput(output, {}, {});
+      output << R"(" })";
+      if (next(it) != constraints.end())
+        output << ',';
+      output << endl;
+    }
+  output << "]}" << endl;
+}
diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh
index dbf99d4e..46e6e390 100644
--- a/src/ComputingTasks.hh
+++ b/src/ComputingTasks.hh
@@ -1254,4 +1254,18 @@ public:
   void writeJsonOutput(ostream &output) const override;
 };
 
+class OccbinConstraintsStatement : public Statement
+{
+private:
+  const SymbolTable &symbol_table;
+public:
+  // The tuple is (name, bind, relax, error_bind, error_relax) (where relax and error_{bind,relax} can be nullptr)
+  const vector<tuple<string, expr_t, expr_t, expr_t, expr_t>> constraints;
+  OccbinConstraintsStatement(const SymbolTable &symbol_table_arg,
+                             const vector<tuple<string, expr_t, expr_t, expr_t, expr_t>> constraints_arg);
+  void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
+  void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override;
+  void writeJsonOutput(ostream &output) const override;
+};
+
 #endif
diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc
index 7beab035..da888776 100644
--- a/src/DynamicModel.cc
+++ b/src/DynamicModel.cc
@@ -2894,10 +2894,6 @@ DynamicModel::writeDriverOutput(ostream &output, const string &basename, bool bl
   // Write equation tags
   equation_tags.writeOutput(output);
 
-  // Write Occbin tags
-  if (occbin)
-    equation_tags.writeOccbinOutput(output);
-
   // Write mapping for variables and equations they are present in
   for (const auto &variable : variableMapping)
     {
diff --git a/src/DynareBison.yy b/src/DynareBison.yy
index ddcb24d8..6396a717 100644
--- a/src/DynareBison.yy
+++ b/src/DynareBison.yy
@@ -107,7 +107,7 @@ class ParsingDriver;
 %token USE_PENALIZED_OBJECTIVE_FOR_HESSIAN INIT_STATE FAST_REALTIME RESCALE_PREDICTION_ERROR_COVARIANCE GENERATE_IRFS
 %token NAN_CONSTANT NO_STATIC NOBS NOCONSTANT NODISPLAY NOCORR NODIAGNOSTIC NOFUNCTIONS NO_HOMOTOPY
 %token NOGRAPH POSTERIOR_NOGRAPH POSTERIOR_GRAPH NOMOMENTS NOPRINT NORMAL_PDF SAVE_DRAWS MODEL_NAME STDERR_MULTIPLES DIAGONAL_ONLY
-%token DETERMINISTIC_TRENDS OBSERVATION_TRENDS OPTIM OPTIM_WEIGHTS ORDER OSR OSR_PARAMS MAX_DIM_COVA_GROUP ADVANCED OUTFILE OUTVARS OVERWRITE DISCOUNT OCCBIN
+%token DETERMINISTIC_TRENDS OBSERVATION_TRENDS OPTIM OPTIM_WEIGHTS ORDER OSR OSR_PARAMS MAX_DIM_COVA_GROUP ADVANCED OUTFILE OUTVARS OVERWRITE DISCOUNT
 %token PARALLEL_LOCAL_FILES PARAMETERS PARAMETER_SET PARTIAL_INFORMATION PERIODS PERIOD PLANNER_OBJECTIVE PLOT_CONDITIONAL_FORECAST PLOT_PRIORS PREFILTER PRESAMPLE
 %token PERFECT_FORESIGHT_SETUP PERFECT_FORESIGHT_SOLVER NO_POSTERIOR_KERNEL_DENSITY FUNCTION
 %token PERFECT_FORESIGHT_WITH_EXPECTATION_ERRORS_SETUP PERFECT_FORESIGHT_WITH_EXPECTATION_ERRORS_SOLVER
@@ -124,7 +124,7 @@ class ParsingDriver;
 %token SIMUL_DEBUG SMOOTHER_DEBUG
 %token LIKELIHOOD_INVERSION_FILTER SMOOTHER_INVERSION_FILTER FILTER_USE_RELEXATION
 %token LIKELIHOOD_PIECEWISE_KALMAN_FILTER SMOOTHER_PIECEWISE_KALMAN_FILTER
-%token <string> TEX_NAME TRUE
+%token <string> TEX_NAME TRUE BIND RELAX ERROR_BIND ERROR_RELAX
 %token UNIFORM_PDF UNIT_ROOT_VARS USE_DLL USEAUTOCORR GSA_SAMPLE_FILE USE_UNIVARIATE_FILTERS_IF_SINGULARITY_IS_DETECTED
 %token VALUES SCALES VAR VAREXO VAREXO_DET VARIABLE VAROBS VAREXOBS PREDETERMINED_VARIABLES VAR_EXPECTATION VAR_EXPECTATION_MODEL PLOT_SHOCK_DECOMPOSITION MODEL_LOCAL_VARIABLE
 %token WRITE_LATEX_DYNAMIC_MODEL WRITE_LATEX_STATIC_MODEL WRITE_LATEX_ORIGINAL_MODEL WRITE_LATEX_STEADY_STATE_MODEL
@@ -172,7 +172,7 @@ class ParsingDriver;
 %token NUMBER_OF_POSTERIOR_DRAWS_AFTER_PERTURBATION MAX_NUMBER_OF_STAGES
 %token RANDOM_FUNCTION_CONVERGENCE_CRITERION RANDOM_PARAMETER_CONVERGENCE_CRITERION NO_INIT_ESTIMATION_CHECK_FIRST_OBS
 %token HETEROSKEDASTIC_FILTER TIME_SHIFT STRUCTURAL TERMINAL_STEADY_STATE_AS_GUESS_VALUE
-%token SURPRISE
+%token SURPRISE OCCBIN_CONSTRAINTS
 /* Method of Moments */
 %token METHOD_OF_MOMENTS MOM_METHOD
 %token BARTLETT_KERNEL_LAG WEIGHTING_MATRIX WEIGHTING_MATRIX_SCALING_FACTOR ANALYTIC_STANDARD_ERRORS ANALYTIC_JACOBIAN PENALIZED_ESTIMATOR VERBOSE 
@@ -208,6 +208,10 @@ class ParsingDriver;
 %type <tuple<string,string,string,string>> prior_eq_opt options_eq_opt
 %type <vector<pair<int, int>>> period_list
 %type <vector<expr_t>> matched_moments_list value_list
+%type <tuple<string, expr_t, expr_t, expr_t, expr_t>> occbin_constraints_regime
+%type <vector<tuple<string, expr_t, expr_t, expr_t, expr_t>>> occbin_constraints_regimes_list
+%type <map<string, expr_t>> occbin_constraints_regime_options_list
+%type <pair<string, expr_t>> occbin_constraints_regime_option
 %%
 
 %start statement_list;
@@ -336,6 +340,7 @@ statement : parameters
           | var_expectation_model
           | compilation_setup
           | matched_moments
+          | occbin_constraints
           ;
 
 dsample : DSAMPLE INT_NUMBER ';'
@@ -867,6 +872,43 @@ matched_moments_list : hand_side ';'
                        }
                      ;
 
+occbin_constraints : OCCBIN_CONSTRAINTS ';' { driver.begin_occbin_constraints(); }
+                     occbin_constraints_regimes_list END ';' { driver.end_occbin_constraints($4); }
+                   ;
+
+
+occbin_constraints_regimes_list : occbin_constraints_regime
+                                  { $$ = { $1 }; }
+                                | occbin_constraints_regimes_list occbin_constraints_regime
+                                  {
+                                    $$ = $1;
+                                    $$.push_back($2);
+                                  }
+                                ;
+
+occbin_constraints_regime : NAME QUOTED_STRING ';' occbin_constraints_regime_options_list
+                            { $$ = { $2, $4["bind"], $4["relax"], $4["error_bind"], $4["error_relax"] }; }
+                          ;
+
+occbin_constraints_regime_options_list : occbin_constraints_regime_option
+                                         { $$ = { $1 }; }
+                                       | occbin_constraints_regime_options_list occbin_constraints_regime_option
+                                         {
+                                           $$ = $1;
+                                           $$.insert($2);
+                                         }
+                                       ;
+
+occbin_constraints_regime_option : BIND hand_side ';'
+                                   { $$ = { "bind", $2 }; }
+                                 | RELAX hand_side ';'
+                                   { $$ = { "relax", $2 }; }
+                                 | ERROR_BIND hand_side ';'
+                                   { $$ = { "error_bind", $2 }; }
+                                 | ERROR_RELAX hand_side ';'
+                                   { $$ = { "error_relax", $2 }; }
+                                 ;
+
 model_options : BLOCK { driver.block(); }
               | o_cutoff
               | o_mfs
@@ -878,7 +920,6 @@ model_options : BLOCK { driver.block(); }
               | o_linear
               | PARALLEL_LOCAL_FILES EQUAL '(' parallel_local_filename_list ')'
               | BALANCED_GROWTH_TEST_TOL EQUAL non_negative_number { driver.balanced_growth_test_tol($3); }
-              | OCCBIN { driver.occbin(); }
               ;
 
 model_options_list : model_options_list COMMA model_options
@@ -911,9 +952,9 @@ tags_list : tags_list COMMA tag_pair
           | tag_pair
           ;
 
-tag_pair : NAME EQUAL QUOTED_STRING
+tag_pair : symbol EQUAL QUOTED_STRING
            { driver.add_equation_tags($1, $3); }
-         | NAME
+         | symbol
            { driver.add_equation_tags($1, ""); }
          ;
 
@@ -4126,6 +4167,10 @@ symbol : NAME
        | PRIOR
        | TRUE
        | FALSE
+       | BIND
+       | RELAX
+       | ERROR_BIND
+       | ERROR_RELAX
        ;
 
 %%
diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll
index fec10ec5..ef319001 100644
--- a/src/DynareFlex.ll
+++ b/src/DynareFlex.ll
@@ -230,6 +230,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <INITIAL>ramsey_constraints {BEGIN DYNARE_BLOCK; return token::RAMSEY_CONSTRAINTS;}
 <INITIAL>generate_irfs {BEGIN DYNARE_BLOCK; return token::GENERATE_IRFS;}
 <INITIAL>matched_moments {BEGIN DYNARE_BLOCK; return token::MATCHED_MOMENTS;}
+<INITIAL>occbin_constraints {BEGIN DYNARE_BLOCK; return token::OCCBIN_CONSTRAINTS;}
 
  /* For the semicolon after an "end" keyword */
 <INITIAL>; {return Dynare::parser::token_type (yytext[0]);}
@@ -762,6 +763,22 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <DYNARE_BLOCK>weibull_pdf {return token::WEIBULL_PDF;}
 <DYNARE_BLOCK>dsge_prior_weight {return token::DSGE_PRIOR_WEIGHT;}
 <DYNARE_BLOCK>surprise {return token::SURPRISE;}
+<DYNARE_BLOCK>bind {
+    yylval->build<string>(yytext);
+    return token::BIND;
+}
+<DYNARE_BLOCK>relax {
+  yylval->build<string>(yytext);
+  return token::RELAX;
+}
+<DYNARE_BLOCK>error_bind {
+  yylval->build<string>(yytext);
+  return token::ERROR_BIND;
+}
+<DYNARE_BLOCK>error_relax {
+  yylval->build<string>(yytext);
+  return token::ERROR_RELAX;
+}
 
 <DYNARE_BLOCK>; {return Dynare::parser::token_type (yytext[0]);}
 <DYNARE_BLOCK># {return Dynare::parser::token_type (yytext[0]);}
@@ -858,7 +875,6 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <DYNARE_BLOCK>no_static {return token::NO_STATIC;}
 <DYNARE_BLOCK>differentiate_forward_vars {return token::DIFFERENTIATE_FORWARD_VARS;}
 <DYNARE_BLOCK>parallel_local_files {return token::PARALLEL_LOCAL_FILES;}
-<DYNARE_BLOCK>occbin {return token::OCCBIN;}
 
 <DYNARE_STATEMENT,DYNARE_BLOCK>linear {return token::LINEAR;}
 
diff --git a/src/EquationTags.cc b/src/EquationTags.cc
index 2d271375..42621546 100644
--- a/src/EquationTags.cc
+++ b/src/EquationTags.cc
@@ -86,30 +86,6 @@ EquationTags::writeOutput(ostream &output) const
   output << "};" << endl;
 }
 
-void
-EquationTags::writeOccbinOutput(ostream &output) const
-{
-  map<int, map<string, string>> occbin_options;
-  for (const auto & [eqn, tags] : eqn_tags)
-    for (const auto & [key, value] : tags)
-      if (key == "pswitch"
-          || key == "bind"
-          || key == "relax"
-          || key == "pcrit")
-        occbin_options[eqn][key] = value;
-
-  int idx = 0;
-  for (const auto & [eqn, tags] : occbin_options)
-    {
-      idx++;
-      for (const auto & [key, value] : tags)
-        output << "M_.occbin.constraint(" << idx << ")."
-               << key << " = '" << value << "';" << endl;
-      output << "M_.occbin.constraint(" << idx << ").equation = "
-             << eqn+1 << ";" << endl;
-    }
-}
-
 void
 EquationTags::writeLatexOutput(ostream &output, int eqn) const
 {
@@ -165,16 +141,3 @@ EquationTags::writeJsonAST(ostream &output, const int eqn) const
     }
   output << "}";
 }
-
-bool
-EquationTags::hasOccbinTags() const
-{
-  for (const auto & [eqn, tags] : eqn_tags)
-    for (const auto & [key, value] : tags)
-      if (key == "pswitch"
-          || key == "bind"
-          || key == "relax"
-          || key == "pcrit")
-        return true;
-  return false;
-}
diff --git a/src/EquationTags.hh b/src/EquationTags.hh
index a8024eea..34277bae 100644
--- a/src/EquationTags.hh
+++ b/src/EquationTags.hh
@@ -130,13 +130,8 @@ public:
   //! Various functions to write equation tags
   void writeCheckSumInfo(ostream &output) const;
   void writeOutput(ostream &output) const;
-  void writeOccbinOutput(ostream &output) const;
   void writeLatexOutput(ostream &output, int eqn) const;
   void writeJsonAST(ostream &output, const int eq) const;
-
-  /* Returns true if at least one equation has a tag associated to occbin
-     (bind/relax/pswitch/pcrit) */
-  bool hasOccbinTags() const;
 };
 
 #endif
diff --git a/src/ModFile.cc b/src/ModFile.cc
index 6c8b6b6e..2892fbfc 100644
--- a/src/ModFile.cc
+++ b/src/ModFile.cc
@@ -684,25 +684,19 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool
       exit(EXIT_FAILURE);
     }
 
-  if (occbin && !dynamic_model.hasOccbinTags())
-    {
-      cerr << "ERROR: the 'occbin' option is present, but there is no equation with the associated tags (bind/relax/pswitch/pcrit)" << endl;
-      exit(EXIT_FAILURE);
-    }
-
-  if (occbin
+  if (mod_file_struct.occbin_constraints_present
       && (mod_file_struct.osr_present || mod_file_struct.mom_estimation_present
           || mod_file_struct.ramsey_model_present || mod_file_struct.ramsey_policy_present
           || mod_file_struct.discretionary_policy_present || mod_file_struct.extended_path_present
           || mod_file_struct.identification_present || mod_file_struct.sensitivity_present))
     {
-      cerr << "ERROR: the 'occbin' option is not compatible with commands other than 'estimation', 'stoch_simul', and 'calib_smoother'." << endl;
+      cerr << "ERROR: the 'occbin_constraints' block is not compatible with commands other than 'estimation', 'stoch_simul', and 'calib_smoother'." << endl;
       exit(EXIT_FAILURE);
     }
 
-  if (mod_file_struct.shocks_surprise_present && !occbin)
+  if (mod_file_struct.shocks_surprise_present && !mod_file_struct.occbin_constraints_present)
     {
-      cerr << "ERROR: the 'shocks(surprise)' block can only be used in conjunction with occbin commands." << endl;
+      cerr << "ERROR: the 'shocks(surprise)' block can only be used in conjunction with the 'occbin_constraints' block." << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -1044,14 +1038,11 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
 
   if (dynamic_model.equation_number() > 0)
     {
-      dynamic_model.writeDriverOutput(mOutputFile, basename, block, use_dll, occbin, mod_file_struct.estimation_present, compute_xrefs);
+      dynamic_model.writeDriverOutput(mOutputFile, basename, block, use_dll, mod_file_struct.occbin_constraints_present, mod_file_struct.estimation_present, compute_xrefs);
       if (!no_static)
         static_model.writeDriverOutput(mOutputFile, block);
     }
 
-  if (occbin)
-    mOutputFile << "[M_, oo_, options_] = occbin.initialize(M_, oo_, options_);" << endl;
-
   if (onlymodel || gui)
     for (const auto &statement : statements)
       {
diff --git a/src/ModFile.hh b/src/ModFile.hh
index 7839adfd..e2f31264 100644
--- a/src/ModFile.hh
+++ b/src/ModFile.hh
@@ -99,9 +99,6 @@ public:
     with a lead */
   vector<string> differentiate_forward_vars_subset;
 
-  //! Whether “occbin” option is used
-  bool occbin{false};
-
   //! Are nonstationary variables present ?
   bool nonstationary_variables{false};
 
diff --git a/src/ModelTree.cc b/src/ModelTree.cc
index aeafc23a..6d000438 100644
--- a/src/ModelTree.cc
+++ b/src/ModelTree.cc
@@ -2120,9 +2120,3 @@ ModelTree::updateReverseVariableEquationOrderings()
       eq_idx_orig2block[eq_idx_block2orig[i]] = i;
     }
 }
-
-bool
-ModelTree::hasOccbinTags() const
-{
-  return equation_tags.hasOccbinTags();
-}
diff --git a/src/ModelTree.hh b/src/ModelTree.hh
index 467c0c94..546fc6e9 100644
--- a/src/ModelTree.hh
+++ b/src/ModelTree.hh
@@ -501,10 +501,6 @@ public:
         return "UNKNOWN                      ";
       }
   }
-
-  /* Returns true if at least one equation has a tag associated to occbin
-     (bind/relax/pswitch/pcrit) */
-  bool hasOccbinTags() const;
 };
 
 #endif
diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc
index 2674f8f2..60d05907 100644
--- a/src/ParsingDriver.cc
+++ b/src/ParsingDriver.cc
@@ -617,12 +617,6 @@ ParsingDriver::bytecode()
   mod_file->bytecode = true;
 }
 
-void
-ParsingDriver::occbin()
-{
-  mod_file->occbin = true;
-}
-
 void
 ParsingDriver::differentiate_forward_vars_all()
 {
@@ -3423,3 +3417,25 @@ ParsingDriver::end_matched_moments(const vector<expr_t> &moments)
 
   reset_data_tree();
 }
+
+void
+ParsingDriver::begin_occbin_constraints()
+{
+  set_current_data_tree(&mod_file->dynamic_model);
+}
+
+void
+ParsingDriver::end_occbin_constraints(const vector<tuple<string, expr_t, expr_t, expr_t, expr_t>> &constraints)
+{
+  // Perform a few checks
+  for (const auto &[name, bind, relax, error_bind, error_relax] : constraints)
+    {
+      check_symbol_is_parameter(name);
+      if (!bind)
+        error("The 'bind' expression is missing in constraint '" + name + "'");
+    }
+
+  mod_file->addStatement(make_unique<OccbinConstraintsStatement>(mod_file->symbol_table, constraints));
+
+  reset_data_tree();
+}
diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh
index 324883b4..88582079 100644
--- a/src/ParsingDriver.hh
+++ b/src/ParsingDriver.hh
@@ -326,8 +326,6 @@ public:
 
   //! the model is stored in a binary file
   void bytecode();
-  //! the model has occasional binding constraints
-  void occbin();
   //! the static model is not computed
   void no_static();
   //! the differentiate_forward_vars option is enabled (for all vars)
@@ -886,6 +884,10 @@ public:
   void begin_matched_moments();
   //! Add a matched_moments block
   void end_matched_moments(const vector<expr_t> &moments);
+  //! Start parsing an occbin_constraints block
+  void begin_occbin_constraints();
+  //! Add an occbin_constraints block
+  void end_occbin_constraints(const vector<tuple<string, expr_t, expr_t, expr_t, expr_t>> &constraints);
 };
 
 #endif // ! PARSING_DRIVER_HH
diff --git a/src/Statement.hh b/src/Statement.hh
index 0b23aad6..24d0d463 100644
--- a/src/Statement.hh
+++ b/src/Statement.hh
@@ -147,6 +147,8 @@ public:
   set<int> parameters_in_planner_discount;
   // Whether a shocks(surprise) block appears
   bool shocks_surprise_present{false};
+  // Whether an occbin_constraints block appears
+  bool occbin_constraints_present{false};
 };
 
 class Statement
-- 
GitLab