From 2ba5a2605a4eaf2b70c8d3ea39b25718f7b5e75a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Tue, 20 Jun 2023 15:32:37 +0200
Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20dynare=5Fsolve=20would=20incorre?=
 =?UTF-8?q?ctly=20accept=20some=20guess=20values=20leading=20to=20NaN=20re?=
 =?UTF-8?q?siduals?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If the guess value passed to dynare_solve was such that the residuals were all
below tolerance, except some that were NaN, then this guess value would be
incorrectly accepted as a solution.

(manually cherry picked from commit 3a789ca7804c2ff6693dd6179c0ca7bd6c54cec6)
---
 matlab/dynare_solve.m | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/matlab/dynare_solve.m b/matlab/dynare_solve.m
index 21513dc0a0..b594c081ae 100644
--- a/matlab/dynare_solve.m
+++ b/matlab/dynare_solve.m
@@ -15,7 +15,7 @@ function [x, errorflag, fvec, fjac] = dynare_solve(f, x, options, varargin)
 % - fvec         [double]           n×1 vector, function value at x (f(x), used for debugging when errorflag is true).
 % - fjac         [double]           n×n matrix, Jacobian value at x (J(x), used for debugging when errorflag is true).
 
-% Copyright © 2001-2021 Dynare Team
+% Copyright © 2001-2023 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -91,8 +91,10 @@ if jacobian_flag
     wrong_initial_guess_flag = false;
     if ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:)))) ...
             || any(~isreal(fvec)) || any(~isreal(fjac(:)))
-        if max(abs(fvec)) < tolf %return if initial value solves problem
+        if ~any(isnan(fvec)) && max(abs(fvec)) < tolf %return if initial value solves problem
+            % max([NaN, 0])=0, so explicitly exclude the case where fvec contains a NaN
             info = 0;
+)
             return;
         end
         disp_verbose('Randomize initial guess...',options.verbosity)
@@ -166,7 +168,8 @@ end
 
 % this test doesn't check complementarity conditions and is not used for
 % mixed complementarity problems
-if (~ismember(options.solve_algo,[10,11])) && (max(abs(fvec)) < tolf)
+if (~ismember(options.solve_algo,[10,11])) && ~any(isnan(fvec)) && (max(abs(fvec)) < tolf)
+    % max([NaN, 0])=0, so explicitly exclude the case where fvec contains a NaN
     return ;
 end
 
-- 
GitLab