function [x,f,fvec,check]=lnsrch1(xold, fold, g, p, stpmax, func, j1, j2, tolx, varargin)
% function [x,f,fvec,check]=lnsrch1(xold,fold,g,p,stpmax,func,j1,j2,tolx,varargin)
% Computes the optimal step by minimizing the residual sum of squares
%
% INPUTS
%   xold:     actual point
%   fold:     residual sum of squares at the point xold
%   g:        gradient
%   p:        Newton direction
%   stpmax:   maximum step
%   func:     name of the function
%   j1:       equations index to be solved
%   j2:       unknowns index
%   tolx:     tolerance parameter
%   varargin: list of arguments following j2
%
% OUTPUTS
%   x:        chosen point
%   f:        residual sum of squares value for a given x
%   fvec:     residuals vector
%   check=1:  problem of the looping which continues indefinitely
%
%
% SPECIAL REQUIREMENTS
%   none

% Copyright © 2001-2023 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare.  If not, see <https://www.gnu.org/licenses/>.

alf = 1e-4 ;
alam = 1;

x = xold;
nn = length(j2);
summ = sqrt(p'*p);

if ~isfinite(summ)
    if ~isequal(func,@perfect_foresight_problem)
        eq_number_string=[];
        for ii=1:length(j1)-1
            eq_number_string=[eq_number_string, num2str(j1(ii)), ', '];
        end
        eq_number_string=[eq_number_string, num2str(j1(end))];
        var_string=[];
        M_=evalin('base','M_');
        for ii=1:length(j2)-1
            var_string=[var_string, M_.endo_names{j2(ii)}, ', '];
        end
        var_string=[var_string, M_.endo_names{j2(end)}];
        fprintf('\nAn infinite element was encountered when trying to solve equation(s) %s \n',eq_number_string)
        fprintf('with respect to the variable(s): %s.\n',var_string)
        fprintf('The values of the endogenous variables when the problem was encountered were:\n')
        label_width=size(char(M_.endo_names),2)+2;
        label_string=sprintf('%%-%us %%8.4g \\n',label_width);
        for ii=1:length(xold)
            fprintf(label_string, M_.endo_names{ii}, xold(ii));
        end
        skipline();
    end
    error(['Some element of Newton direction isn''t finite. Jacobian maybe' ...
           ' singular or there is a problem with initial values'])
end

if summ > stpmax
    p = p*stpmax/summ ;
end

slope = g'*p ;

test = max(abs(p)'./max([abs(xold(j2))';ones(1,nn)])) ;
alamin = tolx/test ;

if alamin > 0.1
    alamin = 0.1;
end

while 1
    if alam < alamin
        check = 1 ;
        return
    end
    x(j2) = xold(j2) + (alam*p) ;
    fvec = feval(func,x,varargin{:}) ;
    fvec = fvec(j1);
    f = 0.5*(fvec'*fvec) ;
    if any(isnan(fvec))
        alam = alam/2 ;
        alam2 = alam ;
        f2 = f ;
        fold2 = fold ;
    else
        if f <= fold+alf*alam*slope
            check = 0;
            break
        else
            if alam == 1
                tmplam = -slope/(2*(f-fold-slope)) ;
            else
                rhs1 = f-fold-alam*slope ;
                rhs2 = f2-fold2-alam2*slope ;
                a = (rhs1/(alam^2)-rhs2/(alam2^2))/(alam-alam2) ;
                b = (-alam2*rhs1/(alam^2)+alam*rhs2/(alam2^2))/(alam-alam2) ;
                if a == 0
                    tmplam = -slope/(2*b) ;
                else
                    disc = (b^2)-3*a*slope ;

                    if disc < 0
                        error ('Roundoff problem in nlsearch') ;
                    else
                        tmplam = (-b+sqrt(disc))/(3*a) ;
                    end
                end
                if tmplam > 0.5*alam
                    tmplam = 0.5*alam;
                end
            end
            alam2 = alam ;
            f2 = f ;
            fold2 = fold ;
            alam = max([tmplam;(0.1*alam)]) ;
        end
    end
end

% 01/14/01 MJ lnsearch is now a separate function
% 01/12/03 MJ check for finite summ to avoid infinite loop when Jacobian
%             is singular or model is denormalized