From 712b11a04575e15f0a5080b469fcd4d7e02b597f 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.
---
 src/ExprNode.cc | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/ExprNode.cc b/src/ExprNode.cc
index c366b085..dc166264 100644
--- a/src/ExprNode.cc
+++ b/src/ExprNode.cc
@@ -6928,7 +6928,12 @@ AbstractExternalFunctionNode::decreaseLeadsLagsPredeterminedVariables() const
 expr_t
 AbstractExternalFunctionNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
 {
-  return recurseTransform(&ExprNode::substituteEndoLeadGreaterThanTwo, subst_table, neweqs, deterministic_model);
+  if (maxEndoLead() < 2)
+    return const_cast<AbstractExternalFunctionNode *>(this);
+  else if (deterministic_model)
+    return recurseTransform(&ExprNode::substituteEndoLeadGreaterThanTwo, subst_table, neweqs, deterministic_model);
+  else
+    return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
 }
 
 expr_t
@@ -6940,7 +6945,12 @@ AbstractExternalFunctionNode::substituteEndoLagGreaterThanTwo(subst_table_t &sub
 expr_t
 AbstractExternalFunctionNode::substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
 {
-  return recurseTransform(&ExprNode::substituteExoLead, subst_table, neweqs, deterministic_model);
+  if (maxExoLead() == 0)
+    return const_cast<AbstractExternalFunctionNode *>(this);
+  else if (deterministic_model)
+    return recurseTransform(&ExprNode::substituteExoLead, subst_table, neweqs, deterministic_model);
+  else
+    return createExoLeadAuxiliaryVarForMyself(subst_table, neweqs);
 }
 
 expr_t
-- 
GitLab