From f85c43d8f04f07f25106c7196d4667d438e3a5ee Mon Sep 17 00:00:00 2001
From: Michel Juillard <michel.juillard@mjui.fr>
Date: Sun, 6 Nov 2011 17:44:50 +0100
Subject: [PATCH] ms-sbvar: fixing more bugs in linear restrictions

---
 preprocessor/DynareBison.yy   | 24 ++++++++++--------
 preprocessor/ParsingDriver.cc | 47 +++++++++++++++++++++++++++--------
 preprocessor/ParsingDriver.hh | 17 +++++++------
 3 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/preprocessor/DynareBison.yy b/preprocessor/DynareBison.yy
index 1105fb5de2..9b6cb7f94e 100644
--- a/preprocessor/DynareBison.yy
+++ b/preprocessor/DynareBison.yy
@@ -706,16 +706,20 @@ svar_var_list : svar_var_list COMMA symbol
                 { driver.add_in_svar_restriction_symbols($1); }
               ;
 
-restriction_expression : COEFF '(' symbol COMMA INT_NUMBER ')'
-                         { driver.add_positive_restriction_element($3,$5);}
-                       | expression
-                       | MINUS COEFF '(' symbol COMMA INT_NUMBER ')'
-		         { driver.add_negative_restriction_element($4,$6);}
-                       | expression TIMES COEFF '(' symbol COMMA INT_NUMBER ')'
-                          { driver.add_positive_restriction_element($1,$5,$7);}
-                       | MINUS expression COEFF TIMES '(' symbol COMMA INT_NUMBER ')'
-                          { driver.add_negative_restriction_element($2,$6,$8);}
-
+restriction_expression : expression {driver.check_restriction_expression_constant($1);}
+                       | restriction_elem_expression
+                       | restriction_expression restriction_elem_expression
+                       ;   
+
+restriction_elem_expression : COEFF '(' symbol COMMA INT_NUMBER ')'
+                                 { driver.add_positive_restriction_element($3,$5);}
+                            | MINUS COEFF '(' symbol COMMA INT_NUMBER ')'
+		                 { driver.add_negative_restriction_element($4,$6);}
+                            | expression TIMES COEFF '(' symbol COMMA INT_NUMBER ')'
+                                 { driver.add_positive_restriction_element($1,$5,$7);}
+                            | MINUS expression COEFF TIMES '(' symbol COMMA INT_NUMBER ')'
+                                 { driver.add_negative_restriction_element($2,$6,$8);}
+                            ;
 
 markov_switching : MARKOV_SWITCHING '(' ms_options_list ')' ';'
                    { driver.markov_switching(); }
diff --git a/preprocessor/ParsingDriver.cc b/preprocessor/ParsingDriver.cc
index ca9a1825e9..87a743a1a4 100644
--- a/preprocessor/ParsingDriver.cc
+++ b/preprocessor/ParsingDriver.cc
@@ -760,7 +760,8 @@ ParsingDriver::end_svar_identification()
   svar_restriction_symbols.clear();
   svar_equation_restrictions.clear();
   svar_ident_restrictions.clear();
-  svar_restriction_nbr.clear();
+  svar_Qi_restriction_nbr.clear();
+  svar_Ri_restriction_nbr.clear();
 }
 
 void
@@ -780,7 +781,10 @@ ParsingDriver::combine_lag_and_restriction(string *lag)
       {
 	SvarIdentificationStatement::svar_identification_restriction new_restriction;
 	new_restriction.equation = it->first;
-	new_restriction.restriction_nbr = ++svar_restriction_nbr[it->first];
+	if (current_lag > 0)
+	  new_restriction.restriction_nbr = ++svar_Ri_restriction_nbr[it->first];
+	else
+	  new_restriction.restriction_nbr = ++svar_Qi_restriction_nbr[it->first];
 	new_restriction.lag = current_lag;
 	new_restriction.variable = *it1;
 	new_restriction.value = data_tree->One;
@@ -829,7 +833,6 @@ void
 ParsingDriver::add_restriction_equation_nbr(string *eq_nbr)
 {
   svar_equation_nbr = atoi(eq_nbr->c_str());
-  ++svar_restriction_nbr[svar_equation_nbr];
   svar_left_handside = true;
 }
 
@@ -852,10 +855,14 @@ ParsingDriver::add_positive_restriction_element(expr_t value, string *variable,
   if (!svar_left_handside)
     value = add_uminus(value);
 
+  int current_lag = atoi(lag->c_str());
   SvarIdentificationStatement::svar_identification_restriction new_restriction;
   new_restriction.equation = svar_equation_nbr;
-  new_restriction.restriction_nbr = svar_restriction_nbr[svar_equation_nbr];
-  new_restriction.lag = atoi(lag->c_str());
+  if (current_lag > 0)
+    new_restriction.restriction_nbr = ++svar_Ri_restriction_nbr[svar_equation_nbr];
+  else
+    new_restriction.restriction_nbr = ++svar_Qi_restriction_nbr[svar_equation_nbr];
+  new_restriction.lag = current_lag;
   new_restriction.variable = symb_id;
   new_restriction.value = value;
 
@@ -873,10 +880,14 @@ ParsingDriver::add_positive_restriction_element(string *variable, string *lag)
   if (!svar_left_handside)
     value = add_uminus(value);
 
+  int current_lag = atoi(lag->c_str());
   SvarIdentificationStatement::svar_identification_restriction new_restriction;
   new_restriction.equation = svar_equation_nbr;
-  new_restriction.restriction_nbr = svar_restriction_nbr[svar_equation_nbr];
-  new_restriction.lag = atoi(lag->c_str());
+  if (current_lag > 0)
+    new_restriction.restriction_nbr = ++svar_Ri_restriction_nbr[svar_equation_nbr];
+  else
+    new_restriction.restriction_nbr = ++svar_Qi_restriction_nbr[svar_equation_nbr];
+  new_restriction.lag = current_lag;
   new_restriction.variable = symb_id;
   new_restriction.value = value;
 
@@ -893,10 +904,14 @@ ParsingDriver::add_negative_restriction_element(expr_t value, string *variable,
   if (svar_left_handside)
     value = add_uminus(value);
 
+  int current_lag = atoi(lag->c_str());
   SvarIdentificationStatement::svar_identification_restriction new_restriction;
   new_restriction.equation = svar_equation_nbr;
-  new_restriction.restriction_nbr = svar_restriction_nbr[svar_equation_nbr];
-  new_restriction.lag = atoi(lag->c_str());
+  if (current_lag > 0)
+    new_restriction.restriction_nbr = ++svar_Ri_restriction_nbr[svar_equation_nbr];
+  else
+    new_restriction.restriction_nbr = ++svar_Qi_restriction_nbr[svar_equation_nbr];
+  new_restriction.lag = current_lag;
   new_restriction.variable = symb_id;
   new_restriction.value = value;
 
@@ -914,15 +929,27 @@ ParsingDriver::add_negative_restriction_element(string *variable, string *lag)
   if (svar_left_handside)
     value = add_uminus(value);
 
+  int current_lag = atoi(lag->c_str());
   SvarIdentificationStatement::svar_identification_restriction new_restriction;
   new_restriction.equation = svar_equation_nbr;
-  new_restriction.lag = atoi(lag->c_str());
+  if (current_lag > 0)
+    new_restriction.restriction_nbr = ++svar_Ri_restriction_nbr[svar_equation_nbr];
+  else
+    new_restriction.restriction_nbr = ++svar_Qi_restriction_nbr[svar_equation_nbr];
+  new_restriction.lag = current_lag;
   new_restriction.variable = symb_id;
   new_restriction.value = value;
 
   svar_ident_restrictions.push_back(new_restriction);
 }
 
+void
+ParsingDriver::check_restriction_expression_constant(expr_t value)
+{
+  if (value->eval(eval_context_t()) != 0)
+    error("SVAR_INDENTIFICATION restrictions must be homogenous");
+}
+
 void
 ParsingDriver::add_upper_cholesky()
 {
diff --git a/preprocessor/ParsingDriver.hh b/preprocessor/ParsingDriver.hh
index 1dfaf163c5..d646450767 100644
--- a/preprocessor/ParsingDriver.hh
+++ b/preprocessor/ParsingDriver.hh
@@ -157,7 +157,8 @@ private:
   //! Temporary storage for left/right handside of a restriction equation within an svar_identificaton block
   bool svar_left_handside;
   //! Temporary storage for current restriction number in svar_identification block
-  map<int,int> svar_restriction_nbr;
+  map<int,int> svar_Qi_restriction_nbr;
+  map<int,int> svar_Ri_restriction_nbr;
 
   //! Temporary storage for argument list of external function
   stack<vector<expr_t> >  stack_external_function_args;
@@ -365,18 +366,20 @@ public:
   void add_in_svar_restriction_symbols(string *name);
   //! Svar_Identification Statement: add exclusions of constants
   void add_constants_exclusion();
-  //! Svar_Identification Statment: add equation number for following restriction equations
+  //! Svar_Identification Statement: add equation number for following restriction equations
   void add_restriction_equation_nbr(string *eq_nbr);
-  //! Svar_Identification Statment: record presence of equal sign
+  //! Svar_Identification Statement: record presence of equal sign
   void add_restriction_equal();
-  //! Svar_Idenditification Statmenet: add coefficient of a linear restriction (positive value) 
+  //! Svar_Idenditification Statement: add coefficient of a linear restriction (positive value) 
   void add_positive_restriction_element(expr_t value, string *variable, string *lag);
-  //! Svar_Idenditification Statmenet: add unit coefficient of a linear restriction 
+  //! Svar_Idenditification Statement: add unit coefficient of a linear restriction 
   void add_positive_restriction_element(string *variable, string *lag);
-  //! Svar_Idenditification Statmenet: add coefficient of a linear restriction (negative value) 
+  //! Svar_Idenditification Statement: add coefficient of a linear restriction (negative value) 
   void add_negative_restriction_element(expr_t value, string *variable, string *lag);
-  //! Svar_Idenditification Statmenet: add negative unit coefficient of a linear restriction
+  //! Svar_Idenditification Statement: add negative unit coefficient of a linear restriction
   void add_negative_restriction_element(string *variable, string *lag);
+  //! Svar_Identification Statement: check that restriction is homogenous
+  void check_restriction_expression_constant(expr_t value);
   //! Svar_Identification Statement: restriction of form upper cholesky
   void add_upper_cholesky();
   //! Svar_Identification Statement: restriction of form lower cholesky
-- 
GitLab