From d18138e410faa6e5663d291af07743d00f787918 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Thu, 23 Mar 2023 17:58:20 +0100
Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Incorrect=20stochastic=20transfo?=
 =?UTF-8?q?rmation=20with=20endo=20lead=20=E2=A9=BE=202=20or=20exo=20lead?=
 =?UTF-8?q?=20=E2=A9=BE=201=20in=20external=20functions?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If an endogenous with a lead ⩾ 2 or an exogenous with a lead ⩾ 1 appeared in
the argument(s) of a call to an external function, the auxiliary variable
transformation was incorrect (the variable was replaced inside the function
call, while it is the whole function call that has to be replaced).

This could lead to incorrect results in stochastic contexts, when the external
function is nonlinear.

(manually cherry picked from commit 712b11a04575e15f0a5080b469fcd4d7e02b597f)
---
 src/ExprNode.cc | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/src/ExprNode.cc b/src/ExprNode.cc
index a697f645..d1ab8690 100644
--- a/src/ExprNode.cc
+++ b/src/ExprNode.cc
@@ -6600,10 +6600,17 @@ AbstractExternalFunctionNode::decreaseLeadsLagsPredeterminedVariables() const
 expr_t
 AbstractExternalFunctionNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
 {
-  vector<expr_t> arguments_subst;
-  for (auto argument : arguments)
-    arguments_subst.push_back(argument->substituteEndoLeadGreaterThanTwo(subst_table, neweqs, deterministic_model));
-  return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+  if (maxEndoLead() < 2)
+    return const_cast<AbstractExternalFunctionNode *>(this);
+  else if (deterministic_model)
+    {
+      vector<expr_t> arguments_subst;
+      for (auto argument : arguments)
+        arguments_subst.push_back(argument->substituteEndoLeadGreaterThanTwo(subst_table, neweqs, deterministic_model));
+      return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+    }
+  else
+    return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
 }
 
 expr_t
@@ -6618,10 +6625,17 @@ AbstractExternalFunctionNode::substituteEndoLagGreaterThanTwo(subst_table_t &sub
 expr_t
 AbstractExternalFunctionNode::substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
 {
-  vector<expr_t> arguments_subst;
-  for (auto argument : arguments)
-    arguments_subst.push_back(argument->substituteExoLead(subst_table, neweqs, deterministic_model));
-  return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+  if (maxExoLead() == 0)
+    return const_cast<AbstractExternalFunctionNode *>(this);
+  else if (deterministic_model)
+    {
+      vector<expr_t> arguments_subst;
+      for (auto argument : arguments)
+        arguments_subst.push_back(argument->substituteExoLead(subst_table, neweqs, deterministic_model));
+      return buildSimilarExternalFunctionNode(arguments_subst, datatree);
+    }
+  else
+    return createExoLeadAuxiliaryVarForMyself(subst_table, neweqs);
 }
 
 expr_t
-- 
GitLab