From 92c8d89cee160ec1c2bc06598db348b5430fcee9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Fri, 28 Mar 2025 14:56:51 +0100
Subject: [PATCH] Perfect foresight: improve sanity checks for
 linear_approximation and endogenous_terminal_period options

---
 doc/manual/source/the-model-file.rst          |  6 +--
 .../perfect_foresight_solver_core.m           | 44 +++++++++++++------
 2 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/doc/manual/source/the-model-file.rst b/doc/manual/source/the-model-file.rst
index 8be7dda09c..c52076ca1d 100644
--- a/doc/manual/source/the-model-file.rst
+++ b/doc/manual/source/the-model-file.rst
@@ -4015,7 +4015,7 @@ speed-up on large models.
        shooting and relaxation approaches. Note that round off errors
        are more important with this mixed strategy (user should check
        the reported value of the maximum absolute error). Only
-       available with option ``stack_solve_algo==0``.
+       available with ``stack_solve_algo`` option equal to ``0``.
 
 
     .. option:: linear_approximation
@@ -4024,8 +4024,8 @@ speed-up on large models.
        model. The model must be stationary and a steady state 
        needs to be provided. Linearization is conducted about the 
        last defined steady state, which can derive from ``initval``,
-       ``endval`` or a subsequent ``steady``. Only available with option
-       ``stack_solve_algo==0`` or ``stack_solve_algo==7``.
+       ``endval`` or a subsequent ``steady``. Only available with
+       ``stack_solve_algo`` option equal to ``0`` or ``7``.
 
     .. option:: steady_solve_algo = INTEGER
 
diff --git a/matlab/perfect-foresight-models/perfect_foresight_solver_core.m b/matlab/perfect-foresight-models/perfect_foresight_solver_core.m
index 05d20af691..c561e59be8 100644
--- a/matlab/perfect-foresight-models/perfect_foresight_solver_core.m
+++ b/matlab/perfect-foresight-models/perfect_foresight_solver_core.m
@@ -17,7 +17,7 @@ function [y, success, maxerror, iter, per_block_status] = perfect_foresight_solv
 % - iter                [integer] Number of iterations of the underlying nonlinear solver (empty for non-iterative methods)
 % - per_block_status    [struct] In the case of block decomposition, provides per-block solver status information (empty if no block decomposition)
 
-% Copyright © 2015-2024 Dynare Team
+% Copyright © 2015-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -43,15 +43,39 @@ end
 
 periods = get_simulation_periods(options_);
 
-if options_.linear_approximation && ~(isequal(options_.stack_solve_algo,0) || isequal(options_.stack_solve_algo,7))
-    error('perfect_foresight_solver: Option linear_approximation is only available with option stack_solve_algo equal to 0 or 7.')
+if options_.linear_approximation
+    if ~ismember(options_.stack_solve_algo, [0 7])
+        error('perfect_foresight_solver: option linear_approximation is only available with stack_solve_algo option equal to 0 or 7')
+    end
+    if options_.block
+        error('perfect_foresight_solver: option linear_approximation is not available with the block option')
+    end
+    if options_.bytecode
+        error('perfect_foresight_solver: option linear_approximation is not available with the bytecode option')
+    end
+    if M_.maximum_endo_lead == 0 || M_.maximum_endo_lag == 0
+        error('perfect_foresight_solver: option linear_approximation is not available with purely backward, purely forward or static models')
+    end
 end
 
-if options_.endogenous_terminal_period && options_.stack_solve_algo ~= 0
-    error('perfect_foresight_solver: option endogenous_terminal_period is only available with option stack_solve_algo equal to 0')
+if options_.endogenous_terminal_period
+    if options_.stack_solve_algo ~= 0
+        error('perfect_foresight_solver: option endogenous_terminal_period is only available with stack_solve_algo option equal to 0')
+    end
+    if options_.block
+        error('perfect_foresight_solver: option endogenous_terminal_period is not available with the block option')
+    end
+    if options_.bytecode
+        error('perfect_foresight_solver: option endogenous_terminal_period is not available with the bytecode option')
+    end
+    if M_.maximum_endo_lead == 0 || M_.maximum_endo_lag == 0
+        error('perfect_foresight_solver: option endogenous_terminal_period is not available with purely backward, purely forward or static models')
+    end
 end
 
-if options_.linear && (isequal(options_.stack_solve_algo, 0) || isequal(options_.stack_solve_algo, 7))
+
+if options_.linear && ismember(options_.stack_solve_algo, [0 7]) && ~options_.block ...
+        && ~options_.bytecode && M_.maximum_endo_lead > 0 && M_.maximum_endo_lag > 0
     options_.linear_approximation = true;
 end
 
@@ -98,22 +122,16 @@ else
             switch options_.stack_solve_algo
               case {0 2 3}
                 if options_.linear_approximation
-                    if ismember(options_.stack_solve_algo, [2 3])
-                        error('Invalid value of stack_solve_algo option!')
-                    end
                     [y, success, maxerror] = sim1_linear(y, exo_simul, steady_state, exo_steady_state, M_, options_);
                 else
                     [y, success, maxerror, iter] = sim1(y, exo_simul, steady_state, M_, options_);
                 end
               case {1 6}
-                if options_.linear_approximation
-                    error('Invalid value of stack_solve_algo option!')
-                end
                 [y, success, maxerror, iter] = sim1_lbj(y, exo_simul, steady_state, M_, options_);
               case 7
                 if options_.linear_approximation
                     if options_.solve_algo == 10 || options_.solve_algo == 11
-                        warning('Since you are requesting an MCP solver, you should not specify your model as model(linear)!')
+                        warning('Since you are requesting an MCP solver, you should not specify your model as model(linear) or use the linear_approximation option!')
                     end
                     [y, success] = solve_stacked_linear_problem(y, exo_simul, steady_state, exo_steady_state, M_, options_);
                 else
-- 
GitLab