File: newton_solve.m

package info (click to toggle)
dynare 7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 79,248 kB
  • sloc: cpp: 82,011; ansic: 28,583; objc: 12,573; yacc: 5,105; pascal: 2,374; lex: 1,502; python: 1,118; sh: 1,116; makefile: 605; lisp: 162; xml: 18
file content (131 lines) | stat: -rw-r--r-- 3,862 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
function [x, errorflag, errorcode] = newton_solve(func, x, jacobian_flag, gstep, tolf, tolx, maxit, solve_algo, incomplete_lu_opts, varargin)

% Solves systems of non linear equations of several variables using a Newton solver, with three
% variants for the inner linear solver:
%  solve_algo = 6: use a sparse LU
%  solve_algo = 7: use GMRES
%  solve_algo = 8: use BiCGStab
%
% INPUTS
%    func:            name of the function to be solved
%    x:               guess values
%    jacobian_flag=true: jacobian given by the 'func' function
%    jacobian_flag=false: jacobian obtained numerically
%    gstep            increment multiplier in numerical derivative
%                     computation
%    tolf             tolerance for residuals
%    tolx             tolerance for solution variation
%    maxit            maximum number of iterations
%    solve_algo       from options_
%    incomplete_lu_opts    structure of options for ilu function
%    varargin:        list of extra arguments to the function
%
% OUTPUTS
%    x:               results
%    errorflag=true:  the model can not be solved

% Copyright © 2024-2025 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/>.

nn = length(x);

errorflag = false;

% Declaration needed for sharing with nested function
fvec = NaN(nn);
fjac = NaN(nn, nn);

function update_fvec_fjac
    if jacobian_flag
        [fvec, fjac] = feval(func, x, varargin{:});
    else
        fvec = feval(func, x, varargin{:});
        dh = max(abs(x),gstep(1)*ones(nn,1))*eps^(1/3);
        for j = 1:nn
            xdh = x;
            xdh(j) = xdh(j)+dh(j);
            t = feval(func, xdh, varargin{:});
            fjac(:, j) = (t - fvec) ./ dh(j);
        end
    end
end

update_fvec_fjac;

idInf = isinf(fvec);
idNan = isnan(fvec);
idCpx = ~isreal(fvec);

if any(idInf)
    disp('newton_solve: during the resolution of the non-linear system, the evaluation of the following equation(s) resulted in a non-finite number:')
    disp(idInf')
    errorcode = 0;
    errorflag = true;
    return
end

if any(idNan)
    disp('newton_solve: during the resolution of the non-linear system, the evaluation of the following equation(s) resulted in a nan:')
    disp(idNan')
    errorcode = 0;
    errorflag = true;
    return
end

if any(idNan)
    disp('newton_solve: during the resolution of the non-linear system, the evaluation of the following equation(s) resulted in a complex number:')
    disp(idCpx')
    errorcode = 0;
    errorflag = true;
    return
end

if norm(fvec, 'Inf') < tolf
    % Initial guess is a solution
    errorcode = -1;
    return
end

for it = 1:maxit
    if solve_algo == 6
        p = fjac\fvec;
    else
        % Should be the same options as in solve_one_boundary.m and bytecode/Interpreter.cc (static case)
        [L1, U1] = ilu(fjac, incomplete_lu_opts);
        if solve_algo == 7
            p = gmres(fjac, fvec, [], [], [], L1, U1);
        elseif solve_algo == 8
            p = bicgstab(fjac, fvec, [], [], L1, U1);
        else
            error('newton_solve: invalid value for solve_algo')
        end
    end

    x = x - p;

    update_fvec_fjac;

    if norm(fvec, 'Inf') < tolf
        errorcode = 1;
        return
    end
end

errorflag = true;
errorcode = 2;

end