Design and performance improvement to solve_algo={12,14}
Use the new time-recursive block decomposition computed by the preprocessor for: - the simulation of backward models with “simul_backward” - the perfect foresight simulation of purely backward/forward/static models Also note that in this case, the preprocessor now defaults to “mfs=3” (i.e. it minimizes the set of feedback variables and tries to renormalize equations). This replaces the previous algorithm based on Dulmage-Mendelsohn (dmperm), plus an ad hoc identification of some equations that can be evaluated (those with a LHS equal to a variable, the log of a variable, or the diff-log of a variable). By the way, the block_trust_region MEX has been modified so that it accepts a boolean argument to decide whether it performs a Dulmage-Mendelsohn decomposition (if not, then it performs a simple trust region on the whole nonlinear system). This provides a significant performance improvement (of almost an order of magnitude for solve_algo=14 on a 700 equations model).unit-tests
parent
10fdc42516
commit
d574705b4a
|
@ -3011,27 +3011,27 @@ Finding the steady state with Dynare nonlinear solver
|
|||
|
||||
``12``
|
||||
|
||||
Specialized version of ``2`` for models where all the equations
|
||||
have one endogenous variable on the left hand side and where
|
||||
each equation determines a different endogenous variable. Only
|
||||
expressions allowed on the left hand side are the natural
|
||||
logarithm of an endogenous variable, the first difference of an
|
||||
endogenous variable (with the ``diff`` operator), or the first
|
||||
difference of the logarithm of an endogenous variable.
|
||||
Univariate blocks are solved by evaluating the expression on the
|
||||
right hand side.
|
||||
Computes a block decomposition and then applies a Newton-type
|
||||
solver on those smaller blocks rather than on the full
|
||||
nonlinear system. This is similar to ``2``, but is typically
|
||||
more efficient. The block decomposition is done at the
|
||||
preprocessor level, which brings two benefits: it identifies
|
||||
blocks that can be evaluated rather than solved; and evulations
|
||||
of the residual and Jacobian of the model are more efficient
|
||||
because only the relevant elements are recomputed at every
|
||||
iteration.
|
||||
|
||||
``14``
|
||||
|
||||
Specialized version of ``4`` for models where all the equations
|
||||
have one endogenous variable on the left hand side and where
|
||||
each equation determines a different endogenous variable. Only
|
||||
expressions allowed on the left hand side are the natural
|
||||
logarithm of an endogenous variable, the first difference of an
|
||||
endogenous variable (with the ``diff`` operator), or the first
|
||||
difference of the logarithm of an endogenous variable..
|
||||
Univariate blocks are solved by evaluating the expression on the
|
||||
right hand side.
|
||||
Computes a block decomposition and then applies a trust region
|
||||
solver with autoscaling on those smaller blocks rather than on
|
||||
the full nonlinear system. This is similar to ``4``, but is
|
||||
typically more efficient. The block decomposition is done at
|
||||
the preprocessor level, which brings two benefits: it
|
||||
identifies blocks that can be evaluated rather than solved; and
|
||||
evulations of the residual and Jacobian of the model are more
|
||||
efficient because only the relevant elements are recomputed at
|
||||
every iteration.
|
||||
|
||||
|br| Default value is ``4``.
|
||||
|
||||
|
|
|
@ -47,10 +47,6 @@ if ~M_.maximum_lag
|
|||
return
|
||||
end
|
||||
|
||||
if ismember(options_.solve_algo, [12,14]) && ~M_.possible_to_use_solve_algo_12_14
|
||||
error(M_.message_solve_algo_12_14)
|
||||
end
|
||||
|
||||
if nargin<3
|
||||
Innovations = [];
|
||||
else
|
||||
|
@ -100,4 +96,4 @@ if options_.linear
|
|||
simulation = simul_backward_linear_model(initialconditions, samplesize, options_, M_, oo_, Innovations);
|
||||
else
|
||||
simulation = simul_backward_nonlinear_model(initialconditions, samplesize, options_, M_, oo_, Innovations);
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,36 +40,64 @@ function [ysim, xsim] = simul_backward_nonlinear_model_(initialconditions, sampl
|
|||
|
||||
debug = false;
|
||||
|
||||
model_dynamic_s = str2func('dynamic_backward_model_for_simulation');
|
||||
|
||||
if ~isempty(innovations)
|
||||
DynareOutput.exo_simul(initialconditions.nobs+(1:samplesize),:) = innovations;
|
||||
end
|
||||
|
||||
if ismember(DynareOptions.solve_algo, [12,14])
|
||||
[funcs, feedback_vars_idxs] = setup_time_recursive_block_simul(DynareModel);
|
||||
end
|
||||
|
||||
function [r, J] = block_wrapper(z, feedback_vars_idx, func, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T)
|
||||
% NB: do as few computations as possible inside this function, since it is
|
||||
% called a very large number of times
|
||||
y_dynamic(feedback_vars_idx) = z;
|
||||
[~, ~, r, J] = feval(func, y_dynamic, x, DynareModel.params, DynareOutput.steady_state, ...
|
||||
sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
end
|
||||
|
||||
% Simulations (call a Newton-like algorithm for each period).
|
||||
for it = initialconditions.nobs+(1:samplesize)
|
||||
if debug
|
||||
dprintf('Period t = %s.', num2str(it-initialconditions.nobs));
|
||||
end
|
||||
y_ = DynareOutput.endo_simul(:,it-1);
|
||||
ylag = y_(iy1); % Set lagged variables.
|
||||
y = y_; % A good guess for the initial conditions is the previous values for the endogenous variables.
|
||||
try
|
||||
if ismember(DynareOptions.solve_algo, [12,14])
|
||||
[DynareOutput.endo_simul(:,it), errorflag, ~, ~, errorcode] = dynare_solve(model_dynamic_s, y, ...
|
||||
DynareOptions.simul.maxit, DynareOptions.dynatol.f, DynareOptions.dynatol.x, ...
|
||||
DynareOptions, ...
|
||||
DynareModel.isloggedlhs, DynareModel.isauxdiffloggedrhs, DynareModel.endo_names, DynareModel.lhs, ...
|
||||
model_dynamic, ylag, DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
|
||||
x = DynareOutput.exo_simul(it,:);
|
||||
T = NaN(DynareModel.block_structure.dyn_tmp_nbr);
|
||||
y_dynamic = [y_; y; NaN(DynareModel.endo_nbr, 1)];
|
||||
for blk = 1:length(DynareModel.block_structure.block)
|
||||
sparse_rowval = DynareModel.block_structure.block(blk).g1_sparse_rowval;
|
||||
sparse_colval = DynareModel.block_structure.block(blk).g1_sparse_colval;
|
||||
sparse_colptr = DynareModel.block_structure.block(blk).g1_sparse_colptr;
|
||||
if DynareModel.block_structure.block(blk).Simulation_Type ~= 1 % Not an evaluate forward block
|
||||
[z, errorflag, ~, ~, errorcode] = dynare_solve(@block_wrapper, y_dynamic(feedback_vars_idxs{blk}), ...
|
||||
DynareOptions.simul.maxit, DynareOptions.dynatol.f, ...
|
||||
DynareOptions.dynatol.x, DynareOptions, ...
|
||||
feedback_vars_idxs{blk}, funcs{blk}, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
if errorflag
|
||||
error('Nonlinear solver routine failed with errorcode=%i in block %i and period %i.', errorcode, blk, it)
|
||||
end
|
||||
y_dynamic(feedback_vars_idxs{blk}) = z;
|
||||
end
|
||||
%% Compute endogenous if the block is of type evaluate or if there are recursive variables in a solve block.
|
||||
%% Also update the temporary terms vector.
|
||||
[y_dynamic, T] = feval(funcs{blk}, y_dynamic, x, DynareModel.params, ...
|
||||
DynareOutput.steady_state, sparse_rowval, sparse_colval, ...
|
||||
sparse_colptr, T);
|
||||
end
|
||||
DynareOutput.endo_simul(:,it) = y_dynamic(DynareModel.endo_nbr+(1:DynareModel.endo_nbr));
|
||||
else
|
||||
[DynareOutput.endo_simul(:,it), errorflag, ~, ~, errorcode] = ...
|
||||
dynare_solve(model_dynamic_s, y, ...
|
||||
dynare_solve(@dynamic_backward_model_for_simulation, y, ...
|
||||
DynareOptions.simul.maxit, DynareOptions.dynatol.f, DynareOptions.dynatol.x, ...
|
||||
DynareOptions, ...
|
||||
model_dynamic, ylag, DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
|
||||
end
|
||||
if errorflag
|
||||
error('Nonlinear solver routine failed with errorcode=%i in period %i.', errorcode, it)
|
||||
model_dynamic, y_(iy1), DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
|
||||
if errorflag
|
||||
error('Nonlinear solver routine failed with errorcode=%i in period %i.', errorcode, it)
|
||||
end
|
||||
end
|
||||
catch
|
||||
DynareOutput.endo_simul = DynareOutput.endo_simul(:, 1:it-1);
|
||||
|
@ -111,7 +139,7 @@ for it = initialconditions.nobs+(1:samplesize)
|
|||
%
|
||||
% Evaluate and check the residuals
|
||||
%
|
||||
[r, J] = feval(model_dynamic_s, ytm, model_dynamic, ytm(iy1), DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
|
||||
[r, J] = feval(@dynamic_backward_model_for_simulation, ytm, model_dynamic, ytm(iy1), DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
|
||||
residuals_evaluating_to_nan = isnan(r);
|
||||
residuals_evaluating_to_inf = isinf(r);
|
||||
residuals_evaluating_to_complex = ~isreal(r);
|
||||
|
@ -142,6 +170,8 @@ end
|
|||
ysim = DynareOutput.endo_simul(1:DynareModel.orig_endo_nbr,:);
|
||||
xsim = DynareOutput.exo_simul;
|
||||
|
||||
end
|
||||
|
||||
function display_names_of_problematic_equations(DynareModel, eqtags, TruthTable)
|
||||
for i=1:DynareModel.orig_endo_nbr
|
||||
if TruthTable(i)
|
||||
|
@ -152,4 +182,5 @@ for i=DynareModel.orig_endo_nbr+1:DynareModel.endo_nbr
|
|||
if TruthTable(i)
|
||||
dprintf(' - Auxiliary equation for %s', DynareModel.endo_names{i})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,21 +58,10 @@ else
|
|||
in0 = nn;
|
||||
end
|
||||
|
||||
% Get first element of varargin if solve_algo ∈ {12,14} and rename varargin.
|
||||
if ismember(options.solve_algo, [12, 14])
|
||||
isloggedlhs = varargin{1};
|
||||
isauxdiffloggedrhs = varargin{2};
|
||||
endo_names = varargin{3};
|
||||
lhs = varargin{4};
|
||||
args = varargin(5:end);
|
||||
else
|
||||
args = varargin;
|
||||
end
|
||||
|
||||
% checking initial values
|
||||
% TODO We should have an option to deactivate the randomization.
|
||||
if jacobian_flag
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = false;
|
||||
if ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:)))) || any(~isreal(fvec)) || any(~isreal(fjac(:)))
|
||||
if ~ismember(options.solve_algo,[10,11]) && max(abs(fvec))< tolf
|
||||
|
@ -88,7 +77,7 @@ if jacobian_flag
|
|||
while wrong_initial_guess_flag && tentative_number<=in0*10
|
||||
tentative_number = tentative_number+1;
|
||||
x(idx) = rand(in0, 1)*10;
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:))));
|
||||
end
|
||||
% If all previous attempts failed, try with real numbers.
|
||||
|
@ -96,7 +85,7 @@ if jacobian_flag
|
|||
while wrong_initial_guess_flag && tentative_number<=in0*10
|
||||
tentative_number = tentative_number+1;
|
||||
x(idx) = randn(in0, 1)*10;
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:))));
|
||||
end
|
||||
% Last tentative, ff all previous attempts failed, try with negative numbers.
|
||||
|
@ -104,12 +93,12 @@ if jacobian_flag
|
|||
while wrong_initial_guess_flag && tentative_number<=in0*10
|
||||
tentative_number = tentative_number+1;
|
||||
x(idx) = -rand(in0, 1)*10;
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:))));
|
||||
end
|
||||
end
|
||||
else
|
||||
fvec = feval(f, x, args{:});
|
||||
fvec = feval(f, x, varargin{:});
|
||||
fjac = zeros(nn, nn);
|
||||
if ~ismember(options.solve_algo,[10,11]) && max(abs(fvec)) < tolf
|
||||
% return if initial value solves the problem except if a mixed complementarity problem is to be solved (complementarity conditions may not be satisfied)
|
||||
|
@ -125,7 +114,7 @@ else
|
|||
while wrong_initial_guess_flag && tentative_number<=in0*10
|
||||
tentative_number = tentative_number+1;
|
||||
x(idx) = rand(in0, 1)*10;
|
||||
fvec = feval(f, x, args{:});
|
||||
fvec = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = ~all(isfinite(fvec));
|
||||
end
|
||||
% If all previous attempts failed, try with real numbers.
|
||||
|
@ -133,7 +122,7 @@ else
|
|||
while wrong_initial_guess_flag && tentative_number<=in0*10
|
||||
tentative_number = tentative_number+1;
|
||||
x(idx) = randn(in0, 1)*10;
|
||||
fvec = feval(f, x, args{:});
|
||||
fvec = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = ~all(isfinite(fvec));
|
||||
end
|
||||
% Last tentative, ff all previous attempts failed, try with negative numbers.
|
||||
|
@ -141,7 +130,7 @@ else
|
|||
while wrong_initial_guess_flag && tentative_number<=in0*10
|
||||
tentative_number = tentative_number+1;
|
||||
x(idx) = -rand(in0, 1)*10;
|
||||
fvec = feval(f, x, args{:});
|
||||
fvec = feval(f, x, varargin{:});
|
||||
wrong_initial_guess_flag = ~all(isfinite(fvec));
|
||||
end
|
||||
end
|
||||
|
@ -199,7 +188,7 @@ if options.solve_algo == 0
|
|||
end
|
||||
|
||||
if ~isoctave
|
||||
[x, fvec, errorcode, ~, fjac] = fsolve(f, x, options4fsolve, args{:});
|
||||
[x, fvec, errorcode, ~, fjac] = fsolve(f, x, options4fsolve, varargin{:});
|
||||
else
|
||||
% Under Octave, use a wrapper, since fsolve() does not have a 4th arg
|
||||
if ischar(f)
|
||||
|
@ -207,7 +196,7 @@ if options.solve_algo == 0
|
|||
else
|
||||
f2 = f;
|
||||
end
|
||||
[x, fvec, errorcode, ~, fjac] = fsolve(@(x) f2(x, args{:}), x, options4fsolve);
|
||||
[x, fvec, errorcode, ~, fjac] = fsolve(@(x) f2(x, varargin{:}), x, options4fsolve);
|
||||
end
|
||||
if errorcode==1
|
||||
errorflag = false;
|
||||
|
@ -220,91 +209,42 @@ if options.solve_algo == 0
|
|||
else
|
||||
errorflag = true;
|
||||
end
|
||||
elseif options.solve_algo==1
|
||||
[x, errorflag, errorcode] = solve1(f, x, 1:nn, 1:nn, jacobian_flag, options.gstep, tolf, tolx, maxit, [], options.debug, args{:});
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
elseif ismember(options.solve_algo, [1, 12])
|
||||
%% NB: It is the responsibility of the caller to deal with the block decomposition if solve_algo=12
|
||||
[x, errorflag, errorcode] = solve1(f, x, 1:nn, 1:nn, jacobian_flag, options.gstep, tolf, tolx, maxit, [], options.debug, varargin{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
elseif options.solve_algo==9
|
||||
[x, errorflag, errorcode] = trust_region(f, x, 1:nn, 1:nn, jacobian_flag, options.gstep, tolf, tolx, maxit, options.trust_region_initial_step_bound_factor, options.debug, args{:});
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
elseif ismember(options.solve_algo, [2, 12, 4])
|
||||
if ismember(options.solve_algo, [2, 12])
|
||||
[x, errorflag, errorcode] = trust_region(f, x, 1:nn, 1:nn, jacobian_flag, options.gstep, tolf, tolx, maxit, options.trust_region_initial_step_bound_factor, options.debug, varargin{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
elseif ismember(options.solve_algo, [2, 4])
|
||||
if options.solve_algo == 2
|
||||
solver = @solve1;
|
||||
else
|
||||
solver = @trust_region;
|
||||
end
|
||||
specializedunivariateblocks = options.solve_algo == 12;
|
||||
if ~jacobian_flag
|
||||
fjac = zeros(nn,nn) ;
|
||||
dh = max(abs(x), options.gstep(1)*ones(nn,1))*eps^(1/3);
|
||||
for j = 1:nn
|
||||
xdh = x ;
|
||||
xdh(j) = xdh(j)+dh(j) ;
|
||||
fjac(:,j) = (feval(f, xdh, args{:})-fvec)./dh(j) ;
|
||||
fjac(:,j) = (feval(f, xdh, varargin{:})-fvec)./dh(j) ;
|
||||
end
|
||||
end
|
||||
[j1,j2,r,s] = dmperm(fjac);
|
||||
JAC = abs(fjac(j1,j2))>0;
|
||||
if options.debug
|
||||
disp(['DYNARE_SOLVE (solve_algo=2|4|12): number of blocks = ' num2str(length(r)-1)]);
|
||||
disp(['DYNARE_SOLVE (solve_algo=2|4): number of blocks = ' num2str(length(r)-1)]);
|
||||
end
|
||||
l = 0;
|
||||
fre = false;
|
||||
for i=length(r)-1:-1:1
|
||||
blocklength = r(i+1)-r(i);
|
||||
if options.debug
|
||||
dprintf('DYNARE_SOLVE (solve_algo=2|4|12): solving block %u of size %u.', i, blocklength);
|
||||
dprintf('DYNARE_SOLVE (solve_algo=2|4): solving block %u of size %u.', i, blocklength);
|
||||
end
|
||||
j = r(i):r(i+1)-1;
|
||||
if specializedunivariateblocks
|
||||
if options.debug
|
||||
dprintf('DYNARE_SOLVE (solve_algo=2|4|12): solving block %u by evaluating RHS.', i);
|
||||
end
|
||||
if isequal(blocklength, 1)
|
||||
if i<length(r)-1
|
||||
if fre || any(JAC(r(i), s(i)+(1:l)))
|
||||
% Reevaluation of the residuals is required because the current RHS depends on
|
||||
% variables that potentially have been updated previously.
|
||||
z = feval(f, x, args{:});
|
||||
l = 0;
|
||||
fre = false;
|
||||
end
|
||||
else
|
||||
% First iteration requires the evaluation of the residuals.
|
||||
z = feval(f, x, args{:});
|
||||
end
|
||||
l = l+1;
|
||||
if isequal(lhs{j1(j)}, endo_names{j2(j)}) || isequal(lhs{j1(j)}, sprintf('log(%s)', endo_names{j2(j)}))
|
||||
if isloggedlhs(j1(j))
|
||||
x(j2(j)) = exp(log(x(j2(j)))-z(j1(j)));
|
||||
else
|
||||
x(j2(j)) = x(j2(j))-z(j1(j));
|
||||
end
|
||||
else
|
||||
if options.debug
|
||||
dprintf('LHS variable is not determined by RHS expression (%u).', j1(j))
|
||||
dprintf('%s -> %s', lhs{j1(j)}, endo_names{j2(j)})
|
||||
end
|
||||
if ~isempty(regexp(lhs{j1(j)}, '\<AUX_DIFF_(\d*)\>', 'once'))
|
||||
if isauxdiffloggedrhs(j1(j))
|
||||
x(j2(j)) = exp(log(x(j2(j)))+z(j1(j)));
|
||||
else
|
||||
x(j2(j)) = x(j2(j))+z(j1(j));
|
||||
end
|
||||
else
|
||||
error('Algorithm solve_algo=%u cannot be used with this nonlinear problem.', options.solve_algo)
|
||||
end
|
||||
end
|
||||
continue
|
||||
end
|
||||
else
|
||||
if options.debug
|
||||
dprintf('DYNARE_SOLVE (solve_algo=2|4|12): solving block %u with trust_region routine.', i);
|
||||
end
|
||||
end
|
||||
blockcolumns=s(i+1)-s(i);
|
||||
if blockcolumns ~= blocklength
|
||||
%non-square-block in DM; check whether initial value is solution
|
||||
[fval_check, fjac] = feval(f, x, args{:});
|
||||
[fval_check, fjac] = feval(f, x, varargin{:});
|
||||
if norm(fval_check(j1(j))) < tolf
|
||||
errorflag = false;
|
||||
errorcode = 0;
|
||||
|
@ -317,10 +257,9 @@ elseif ismember(options.solve_algo, [2, 12, 4])
|
|||
options.gstep, ...
|
||||
tolf, options.solve_tolx, maxit, ...
|
||||
options.trust_region_initial_step_bound_factor, ...
|
||||
options.debug, args{:});
|
||||
fre = true;
|
||||
options.debug, varargin{:});
|
||||
else
|
||||
fprintf('\nDYNARE_SOLVE (solve_algo=2|4|12): the Dulmage-Mendelsohn decomposition returned a non-square block. This means that the Jacobian is singular. You may want to try another value for solve_algo.\n')
|
||||
fprintf('\nDYNARE_SOLVE (solve_algo=2|4): the Dulmage-Mendelsohn decomposition returned a non-square block. This means that the Jacobian is singular. You may want to try another value for solve_algo.\n')
|
||||
%overdetermined block
|
||||
errorflag = true;
|
||||
errorcode = 0;
|
||||
|
@ -329,31 +268,31 @@ elseif ismember(options.solve_algo, [2, 12, 4])
|
|||
return
|
||||
end
|
||||
end
|
||||
fvec = feval(f, x, args{:});
|
||||
fvec = feval(f, x, varargin{:});
|
||||
if max(abs(fvec))>tolf
|
||||
disp_verbose('Call solver on the full nonlinear problem.',options.verbosity)
|
||||
[x, errorflag, errorcode] = solver(f, x, 1:nn, 1:nn, jacobian_flag, ...
|
||||
options.gstep, tolf, options.solve_tolx, maxit, ...
|
||||
options.trust_region_initial_step_bound_factor, ...
|
||||
options.debug, args{:});
|
||||
options.debug, varargin{:});
|
||||
end
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
elseif options.solve_algo==3
|
||||
if jacobian_flag
|
||||
[x, errorcode] = csolve(f, x, f, tolf, maxit, args{:});
|
||||
[x, errorcode] = csolve(f, x, f, tolf, maxit, varargin{:});
|
||||
else
|
||||
[x, errorcode] = csolve(f, x, [], tolf, maxit, args{:});
|
||||
[x, errorcode] = csolve(f, x, [], tolf, maxit, varargin{:});
|
||||
end
|
||||
if errorcode==0
|
||||
errorflag = false;
|
||||
else
|
||||
errorflag = true;
|
||||
end
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
elseif options.solve_algo==10
|
||||
% LMMCP
|
||||
olmmcp = options.lmmcp;
|
||||
[x, fvec, errorcode, ~, fjac] = lmmcp(f, x, olmmcp.lb, olmmcp.ub, olmmcp, args{:});
|
||||
[x, fvec, errorcode, ~, fjac] = lmmcp(f, x, olmmcp.lb, olmmcp.ub, olmmcp, varargin{:});
|
||||
eq_to_check=find(isfinite(olmmcp.lb) | isfinite(olmmcp.ub));
|
||||
eq_to_ignore=eq_to_check(x(eq_to_check,:)<=olmmcp.lb(eq_to_check)+eps | x(eq_to_check,:)>=olmmcp.ub(eq_to_check)-eps);
|
||||
fvec(eq_to_ignore)=0;
|
||||
|
@ -373,7 +312,7 @@ elseif options.solve_algo == 11
|
|||
omcppath = options.mcppath;
|
||||
global mcp_data
|
||||
mcp_data.func = f;
|
||||
mcp_data.args = args;
|
||||
mcp_data.args = varargin;
|
||||
try
|
||||
[x, fval, jac, mu] = pathmcp(x,omcppath.lb,omcppath.ub,'mcp_func',omcppath.A,omcppath.b,omcppath.t,omcppath.mu0);
|
||||
catch
|
||||
|
@ -384,18 +323,15 @@ elseif options.solve_algo == 11
|
|||
eq_to_ignore=eq_to_check(x(eq_to_check,:)<=omcppath.lb(eq_to_check)+eps | x(eq_to_check,:)>=omcppath.ub(eq_to_check)-eps);
|
||||
fvec(eq_to_ignore)=0;
|
||||
elseif ismember(options.solve_algo, [13, 14])
|
||||
%% NB: It is the responsibility of the caller to deal with the block decomposition if solve_algo=14
|
||||
if ~jacobian_flag
|
||||
error('DYNARE_SOLVE: option solve_algo=13|14 needs computed Jacobian')
|
||||
error('DYNARE_SOLVE: option solve_algo=13 needs computed Jacobian')
|
||||
end
|
||||
auxstruct = struct();
|
||||
if options.solve_algo == 14
|
||||
auxstruct.lhs = lhs;
|
||||
auxstruct.endo_names = endo_names;
|
||||
auxstruct.isloggedlhs = isloggedlhs;
|
||||
auxstruct.isauxdiffloggedrhs = isauxdiffloggedrhs;
|
||||
end
|
||||
[x, errorflag, errorcode] = block_trust_region(f, x, tolf, options.solve_tolx, maxit, options.trust_region_initial_step_bound_factor, options.debug, auxstruct, args{:});
|
||||
[fvec, fjac] = feval(f, x, args{:});
|
||||
[x, errorflag, errorcode] = block_trust_region(f, x, tolf, options.solve_tolx, maxit, ...
|
||||
options.trust_region_initial_step_bound_factor, ...
|
||||
options.solve_algo == 13, ... % Only block-decompose with Dulmage-Mendelsohn for 13, not for 14
|
||||
options.debug, varargin{:});
|
||||
[fvec, fjac] = feval(f, x, varargin{:});
|
||||
else
|
||||
error('DYNARE_SOLVE: option solve_algo must be one of [0,1,2,3,4,9,10,11,12,13,14]')
|
||||
end
|
||||
|
|
|
@ -50,6 +50,9 @@ if options_.linear && (isequal(options_.stack_solve_algo, 0) || isequal(options_
|
|||
end
|
||||
|
||||
if options_.block
|
||||
if M_.block_structure.time_recursive
|
||||
error('Internal error: can''t perform stacked perfect foresight simulation with time-recursive block decomposition')
|
||||
end
|
||||
if options_.bytecode
|
||||
try
|
||||
oo_.endo_simul = bytecode('dynamic', oo_.endo_simul, oo_.exo_simul, M_.params, repmat(oo_.steady_state,1, periods+2), periods);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
function [funcs, feedback_vars_idxs] = setup_time_recursive_block_simul(M_)
|
||||
%function [funcs, feedback_vars_idxs] = setup_time_recursive_block_simul(M_)
|
||||
%
|
||||
% For solve_algo={12,14}, precompute the function handles for per-block dynamic files
|
||||
% (it is surprisingly costly to recompute them within simulation loops).
|
||||
% Also precompute indices of feedback variables (also brings some performance gains).
|
||||
% By the way, do other sanity checks on block decomposition.
|
||||
|
||||
% Copyright © 2022 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/>.
|
||||
|
||||
if ~isfield(M_, 'block_structure')
|
||||
error('Can''t use solve_algo=12 nor solve_algo=14, because the block decomposition of the dynamic model failed')
|
||||
end
|
||||
if ~M_.block_structure.time_recursive
|
||||
error('Can''t use solve_algo=12 nor solve_algo=14, because the model is not purely backward/static/forward or you gave the ''block'' option to the ''model'' block')
|
||||
end
|
||||
|
||||
funcs = cell(length(M_.block_structure.block), 1);
|
||||
feedback_vars_idxs = cell(length(M_.block_structure.block), 1);
|
||||
for blk = 1:length(M_.block_structure.block)
|
||||
funcs{blk} = str2func(sprintf('%s.sparse.block.dynamic_%d', M_.fname, blk));
|
||||
feedback_vars_idxs{blk} = M_.endo_nbr+M_.block_structure.block(blk).variable((M_.block_structure.block(blk).endo_nbr-M_.block_structure.block(blk).mfs+1):end); % Indices of feedback variables in the dynamic y vector (of size 3n)
|
||||
end
|
||||
|
||||
end
|
|
@ -20,38 +20,71 @@ function [endogenousvariables, info] = sim1_purely_backward(endogenousvariables,
|
|||
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
ny0 = nnz(M.lead_lag_incidence(2,:)); % Number of variables at current period
|
||||
iyb = M.lead_lag_incidence(1,:)>0; % Logical vector (for lagged variables)
|
||||
|
||||
if ny0 ~= M.endo_nbr
|
||||
error('All endogenous variables must appear at the current period!')
|
||||
end
|
||||
|
||||
if ismember(options.solve_algo, [12,14]) && ~M.possible_to_use_solve_algo_12_14
|
||||
error(M.message_solve_algo_12_14)
|
||||
if ismember(options.solve_algo, [12,14])
|
||||
[funcs, feedback_vars_idxs] = setup_time_recursive_block_simul(M);
|
||||
else
|
||||
iyb = M.lead_lag_incidence(1,:)>0; % Logical vector (for lagged variables)
|
||||
dynamicmodel = str2func(sprintf('%s.%s', M.fname, 'dynamic'));
|
||||
dynamicmodel_s = str2func('dynamic_backward_model_for_simulation');
|
||||
end
|
||||
|
||||
dynamicmodel = str2func(sprintf('%s.%s', M.fname, 'dynamic'));
|
||||
dynamicmodel_s = str2func('dynamic_backward_model_for_simulation');
|
||||
function [r, J] = block_wrapper(z, feedback_vars_idx, func, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T)
|
||||
% NB: do as few computations as possible inside this function, since it is
|
||||
% called a very large number of times
|
||||
y_dynamic(feedback_vars_idx) = z;
|
||||
[~, ~, r, J] = feval(func, y_dynamic, x, M.params, steadystate, ...
|
||||
sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
end
|
||||
|
||||
info.status = true;
|
||||
|
||||
for it = M.maximum_lag + (1:options.periods)
|
||||
y = endogenousvariables(:,it-1); % Values at previous period, also used as guess value for current period
|
||||
ylag = y(iyb);
|
||||
if ismember(options.solve_algo, [12,14])
|
||||
[tmp, check, ~, ~, errorcode] = dynare_solve(dynamicmodel_s, y, ...
|
||||
options.simul.maxit, options.dynatol.f, options.dynatol.x, ...
|
||||
options, M.isloggedlhs, M.isauxdiffloggedrhs, M.endo_names, M.lhs, ...
|
||||
dynamicmodel, ylag, exogenousvariables, M.params, steadystate, it);
|
||||
x = exogenousvariables(it,:);
|
||||
T = NaN(M.block_structure.dyn_tmp_nbr);
|
||||
y_dynamic = [y; y; NaN(M.endo_nbr, 1)];
|
||||
for blk = 1:length(M.block_structure.block)
|
||||
sparse_rowval = M.block_structure.block(blk).g1_sparse_rowval;
|
||||
sparse_colval = M.block_structure.block(blk).g1_sparse_colval;
|
||||
sparse_colptr = M.block_structure.block(blk).g1_sparse_colptr;
|
||||
if M.block_structure.block(blk).Simulation_Type ~= 1 % Not an evaluate forward block
|
||||
[z, check, ~, ~, errorcode] = dynare_solve(@block_wrapper, y_dynamic(feedback_vars_idxs{blk}), ...
|
||||
options.simul.maxit, options.dynatol.f, ...
|
||||
options.dynatol.x, options, ...
|
||||
feedback_vars_idxs{blk}, funcs{blk}, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
if check
|
||||
info.status = false;
|
||||
if options.debug
|
||||
dprintf('sim1_purely_backward: Nonlinear solver routine failed with errorcode=%i in block %i and period %i.', errorcode, blk, it)
|
||||
end
|
||||
end
|
||||
y_dynamic(feedback_vars_idxs{blk}) = z;
|
||||
end
|
||||
%% Compute endogenous if the block is of type evaluate or if there are recursive variables in a solve block.
|
||||
%% Also update the temporary terms vector.
|
||||
[y_dynamic, T] = feval(funcs{blk}, y_dynamic, x, M.params, ...
|
||||
steadystate, sparse_rowval, sparse_colval, ...
|
||||
sparse_colptr, T);
|
||||
end
|
||||
endogenousvariables(:,it) = y_dynamic(M.endo_nbr+(1:M.endo_nbr));
|
||||
else
|
||||
ylag = y(iyb);
|
||||
[tmp, check, ~, ~, errorcode] = dynare_solve(dynamicmodel_s, y, ...
|
||||
options.simul.maxit, options.dynatol.f, options.dynatol.x, ...
|
||||
options, dynamicmodel, ylag, exogenousvariables, M.params, steadystate, it);
|
||||
if check
|
||||
info.status = false;
|
||||
dprintf('sim1_purely_backward: Nonlinear solver routine failed with errorcode=%i in period %i', errorcode, it)
|
||||
break
|
||||
end
|
||||
endogenousvariables(:,it) = tmp;
|
||||
end
|
||||
if check
|
||||
info.status = false;
|
||||
dprintf('sim1_purely_backward: Nonlinear solver routine failed with errorcode=%i in period %i', errorcode, it)
|
||||
break
|
||||
end
|
||||
endogenousvariables(:,it) = tmp;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -19,34 +19,71 @@ function [endogenousvariables, info] = sim1_purely_forward(endogenousvariables,
|
|||
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
ny0 = nnz(M.lead_lag_incidence(1,:)); % Number of variables at current period
|
||||
iyf = find(M.lead_lag_incidence(2,:)>0); % Indices of variables at next period
|
||||
|
||||
if ny0 ~= M.endo_nbr
|
||||
error('All endogenous variables must appear at the current period!')
|
||||
end
|
||||
|
||||
dynamicmodel = str2func(sprintf('%s.%s', M.fname, 'dynamic'));
|
||||
dynamicmodel_s = str2func('dynamic_forward_model_for_simulation');
|
||||
if ismember(options.solve_algo, [12,14])
|
||||
[funcs, feedback_vars_idxs] = setup_time_recursive_block_simul(M);
|
||||
else
|
||||
iyf = find(M.lead_lag_incidence(2,:)>0); % Indices of variables at next period
|
||||
dynamicmodel = str2func(sprintf('%s.%s', M.fname, 'dynamic'));
|
||||
dynamicmodel_s = str2func('dynamic_forward_model_for_simulation');
|
||||
end
|
||||
|
||||
function [r, J] = block_wrapper(z, feedback_vars_idx, func, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T)
|
||||
% NB: do as few computations as possible inside this function, since it is
|
||||
% called a very large number of times
|
||||
y_dynamic(feedback_vars_idx) = z;
|
||||
[~, ~, r, J] = feval(func, y_dynamic, x, M.params, steadystate, ...
|
||||
sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
end
|
||||
|
||||
info.status = true;
|
||||
|
||||
for it = options.periods:-1:1
|
||||
yf = endogenousvariables(:,it+1); % Values at next period, also used as guess value for current period
|
||||
if ismember(options.solve_algo, [12,14])
|
||||
[tmp, check, ~, ~, errorcode] = dynare_solve(dynamicmodel_s, yf, ...
|
||||
options.simul.maxit, options.dynatol.f, options.dynatol.x, ...
|
||||
options, M.isloggedlhs, M.isauxdiffloggedrhs, M.endo_names, M.lhs, ...
|
||||
dynamicmodel, yf(iyf), exogenousvariables, M.params, steadystate, it);
|
||||
x = exogenousvariables(it,:);
|
||||
T = NaN(M.block_structure.dyn_tmp_nbr);
|
||||
y_dynamic = [NaN(M.endo_nbr, 1); yf; yf];
|
||||
for blk = 1:length(M.block_structure.block)
|
||||
sparse_rowval = M.block_structure.block(blk).g1_sparse_rowval;
|
||||
sparse_colval = M.block_structure.block(blk).g1_sparse_colval;
|
||||
sparse_colptr = M.block_structure.block(blk).g1_sparse_colptr;
|
||||
if M.block_structure.block(blk).Simulation_Type ~= 2 % Not an evaluate backward block
|
||||
[z, check, ~, ~, errorcode] = dynare_solve(@block_wrapper, y_dynamic(feedback_vars_idxs{blk}), ...
|
||||
options.simul.maxit, options.dynatol.f, ...
|
||||
options.dynatol.x, options, ...
|
||||
feedback_vars_idxs{blk}, funcs{blk}, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
if check
|
||||
info.status = false;
|
||||
if options.debug
|
||||
dprintf('sim1_purely_forward: Nonlinear solver routine failed with errorcode=%i in block %i and period %i.', errorcode, blk, it)
|
||||
end
|
||||
end
|
||||
y_dynamic(feedback_vars_idxs{blk}) = z;
|
||||
end
|
||||
%% Compute endogenous if the block is of type evaluate or if there are recursive variables in a solve block.
|
||||
%% Also update the temporary terms vector.
|
||||
[y_dynamic, T] = feval(funcs{blk}, y_dynamic, x, M.params, ...
|
||||
steadystate, sparse_rowval, sparse_colval, ...
|
||||
sparse_colptr, T);
|
||||
end
|
||||
endogenousvariables(:,it) = y_dynamic(M.endo_nbr+(1:M.endo_nbr));
|
||||
else
|
||||
[tmp, check, ~, ~, errorcode] = dynare_solve(dynamicmodel_s, yf, ...
|
||||
options.simul.maxit, options.dynatol.f, options.dynatol.x, ...
|
||||
options, ...
|
||||
dynamicmodel, yf(iyf), exogenousvariables, M.params, steadystate, it);
|
||||
if check
|
||||
info.status = false;
|
||||
dprintf('sim1_purely_forward: Nonlinear solver routine failed with errorcode=%i in period %i.', errorcode, it)
|
||||
break
|
||||
end
|
||||
endogenousvariables(:,it) = tmp(1:M.endo_nbr);
|
||||
end
|
||||
if check
|
||||
info.status = false;
|
||||
dprintf('sim1_purely_forward: Nonlinear solver routine failed with errorcode=%i in period %i.', errorcode, it)
|
||||
break
|
||||
end
|
||||
endogenousvariables(:,it) = tmp(1:M.endo_nbr);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -23,12 +23,20 @@ if nnz(M.lead_lag_incidence(1,:)) ~= M.endo_nbr
|
|||
error('All endogenous variables must appear at the current period!')
|
||||
end
|
||||
|
||||
if ismember(options.solve_algo, [12,14]) && ~M.possible_to_use_solve_algo_12_14
|
||||
error(M.message_solve_algo_12_14)
|
||||
if ismember(options.solve_algo, [12,14])
|
||||
[funcs, feedback_vars_idxs] = setup_time_recursive_block_simul(M);
|
||||
else
|
||||
dynamicmodel = str2func(sprintf('%s.%s', M.fname, 'dynamic'));
|
||||
dynamicmodel_s = str2func('dynamic_static_model_for_simulation');
|
||||
end
|
||||
|
||||
dynamicmodel = str2func(sprintf('%s.%s', M.fname, 'dynamic'));
|
||||
dynamicmodel_s = str2func('dynamic_static_model_for_simulation');
|
||||
function [r, J] = block_wrapper(z, feedback_vars_idx, func, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T)
|
||||
% NB: do as few computations as possible inside this function, since it is
|
||||
% called a very large number of times
|
||||
y_dynamic(feedback_vars_idx) = z;
|
||||
[~, ~, r, J] = feval(func, y_dynamic, x, M.params, steadystate, ...
|
||||
sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
end
|
||||
|
||||
info.status = true;
|
||||
|
||||
|
@ -36,21 +44,46 @@ y = endogenousvariables(:,1);
|
|||
|
||||
for it = 1:options.periods
|
||||
if ismember(options.solve_algo, [12,14])
|
||||
[tmp, check, ~, ~, errorcode] = dynare_solve(dynamicmodel_s, y, ...
|
||||
options.simul.maxit, options.dynatol.f, options.dynatol.x, ...
|
||||
options, M.isloggedlhs, M.isauxdiffloggedrhs, M.endo_names, M.lhs, ...
|
||||
dynamicmodel, exogenousvariables, M.params, steadystate, it);
|
||||
x = exogenousvariables(it,:);
|
||||
T = NaN(M.block_structure.dyn_tmp_nbr);
|
||||
y_dynamic = [NaN(M.endo_nbr, 1); y; NaN(M.endo_nbr, 1)];
|
||||
for blk = 1:length(M.block_structure.block)
|
||||
sparse_rowval = M.block_structure.block(blk).g1_sparse_rowval;
|
||||
sparse_colval = M.block_structure.block(blk).g1_sparse_colval;
|
||||
sparse_colptr = M.block_structure.block(blk).g1_sparse_colptr;
|
||||
if M.block_structure.block(blk).Simulation_Type ~= 1 % Not an evaluate forward block
|
||||
[z, check, ~, ~, errorcode] = dynare_solve(@block_wrapper, y_dynamic(feedback_vars_idxs{blk}), ...
|
||||
options.simul.maxit, options.dynatol.f, ...
|
||||
options.dynatol.x, options, ...
|
||||
feedback_vars_idxs{blk}, funcs{blk}, y_dynamic, x, sparse_rowval, sparse_colval, sparse_colptr, T);
|
||||
if check
|
||||
info.status = false;
|
||||
if options.debug
|
||||
dprintf('sim1_purely_static: Nonlinear solver routine failed with errorcode=%i in block %i and period %i.', errorcode, blk, it)
|
||||
end
|
||||
end
|
||||
y_dynamic(feedback_vars_idxs{blk}) = z;
|
||||
end
|
||||
%% Compute endogenous if the block is of type evaluate or if there are recursive variables in a solve block.
|
||||
%% Also update the temporary terms vector.
|
||||
[y_dynamic, T] = feval(funcs{blk}, y_dynamic, x, M.params, ...
|
||||
steadystate, sparse_rowval, sparse_colval, ...
|
||||
sparse_colptr, T);
|
||||
end
|
||||
endogenousvariables(:,it) = y_dynamic(M.endo_nbr+(1:M.endo_nbr));
|
||||
else
|
||||
[tmp, check, ~, ~, errorcode] = dynare_solve(dynamicmodel_s, y, ...
|
||||
options.simul.maxit, options.dynatol.f, options.dynatol.x, ...
|
||||
options, dynamicmodel, exogenousvariables, M.params, steadystate, it);
|
||||
end
|
||||
if check
|
||||
info.status = false;
|
||||
if options.debug
|
||||
dprintf('sim1_purely_static: Nonlinear solver routine failed with errorcode=%i in period %i.', errorcode, it)
|
||||
if check
|
||||
info.status = false;
|
||||
if options.debug
|
||||
dprintf('sim1_purely_static: Nonlinear solver routine failed with errorcode=%i in period %i.', errorcode, it)
|
||||
end
|
||||
end
|
||||
endogenousvariables(:,it) = tmp;
|
||||
end
|
||||
endogenousvariables(:,it) = tmp;
|
||||
y = endogenousvariables(:,it);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
function Model = setup_solvers(Model)
|
||||
|
||||
% Setup solve_algo={12,14} by identifying equations with a log on the left hand side.
|
||||
%
|
||||
% INPUTS
|
||||
% - Model [struct] Model description, aka M_.
|
||||
% - Options [struct] Dynare's options, aka options_.
|
||||
%
|
||||
% OUTPUTS
|
||||
% - Model [struct] Updated model description.
|
||||
|
||||
% Copyright © 2020 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/>.
|
||||
|
||||
cannot_use_solve_algo_12_14 = false;
|
||||
|
||||
try
|
||||
json = loadjson_(sprintf('%s/model/json/modfile.json', Model.fname));
|
||||
catch
|
||||
cannot_use_solve_algo_12_14 = true;
|
||||
message = 'Algorithms solve_algo={12,14} require json output of the model (use json=compute option)';
|
||||
end
|
||||
|
||||
if ~cannot_use_solve_algo_12_14
|
||||
|
||||
lhs = cell(length(json.model),1);
|
||||
isauxdiffloggedrhs = false(length(json.model), 1);
|
||||
|
||||
for i = 1:length(json.model)
|
||||
if length(json.model)>1
|
||||
lhs{i} = json.model{i}.lhs;
|
||||
else
|
||||
lhs{i} = json.model.lhs;
|
||||
end
|
||||
if isempty(regexp(lhs{i}, '^\w+$|^log\(\w+\)$'))
|
||||
cannot_use_solve_algo_12_14 = true;
|
||||
message = sprintf('With solve_algo={12,14}, each equation must have on the left hand side a single variable or logged variable (equation %d does not satisfy this condition).', i);
|
||||
break
|
||||
end
|
||||
if length(json.model)>1
|
||||
rhs = json.model{i}.rhs;
|
||||
else
|
||||
rhs = json.model.lhs;
|
||||
end
|
||||
if i>Model.orig_endo_nbr && ~isempty(regexp(lhs{i}, '\<AUX_DIFF_(\d*)\>', 'once')) && ismember(lhs{i}, lhs(1:i-1)) && ...
|
||||
~isempty(regexp(rhs, 'log\(\w*\)-log\(\w*\(-1\)\)', 'once'))
|
||||
isauxdiffloggedrhs(i) = true;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ~cannot_use_solve_algo_12_14
|
||||
|
||||
islog = @(x) ~isempty(regexp(x, 'log\(\w*\)', 'once'));
|
||||
|
||||
lhs0 = lhs;
|
||||
for i=1:length(json.model)
|
||||
if islog(lhs{i})
|
||||
lhs0{i} = strrep(strrep(lhs{i}, 'log(', ''), ')', '');
|
||||
end
|
||||
end
|
||||
|
||||
if ~isequal(length(unique(lhs0(1:Model.orig_endo_nbr))), length(lhs0(1:Model.orig_endo_nbr)))
|
||||
cannot_use_solve_algo_12_14 = true;
|
||||
message = sprintf('With solve_algo={12,14}, each equation must determine a different endogenous variable.')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if cannot_use_solve_algo_12_14
|
||||
Model.isloggedlhs = {};
|
||||
Model.lhs = {};
|
||||
Model.isauxdiffloggedrhs = [];
|
||||
Model.possible_to_use_solve_algo_12_14 = false;
|
||||
Model.message_solve_algo_12_14 = message;
|
||||
else
|
||||
Model.isloggedlhs = cellfun(islog, lhs);
|
||||
Model.lhs = lhs;
|
||||
Model.isauxdiffloggedrhs = isauxdiffloggedrhs;
|
||||
Model.possible_to_use_solve_algo_12_14 = true;
|
||||
Model.message_solve_algo_12_14 = '';
|
||||
end
|
|
@ -35,16 +35,11 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
|
|||
integer :: maxiter
|
||||
real(real64), dimension(:), allocatable :: fvec
|
||||
real(real64), dimension(:,:), allocatable :: fjac
|
||||
logical :: debug, specializedunivariateblocks
|
||||
logical :: debug, block_decompose
|
||||
character(len=80) :: debug_msg
|
||||
logical(mxLogical), dimension(:), pointer :: isloggedlhs => null(), &
|
||||
isauxdiffloggedrhs => null()
|
||||
type(c_ptr) :: endo_names, lhs
|
||||
logical :: fre ! True if the last block has been solved (i.e. not evaluated), so that residuals must be updated
|
||||
integer, dimension(:), allocatable :: evaled_cols ! If fre=.false., lists the columns that have been evaluated so far without updating the residuals
|
||||
|
||||
if (nrhs < 4 .or. nlhs /= 3) then
|
||||
call mexErrMsgTxt("Must have at least 7 inputs and exactly 3 outputs")
|
||||
if (nrhs < 8 .or. nlhs /= 3) then
|
||||
call mexErrMsgTxt("Must have at least 8 inputs and exactly 3 outputs")
|
||||
end if
|
||||
|
||||
if (.not. ((mxIsChar(prhs(1)) .and. mxGetM(prhs(1)) == 1) .or. mxIsClass(prhs(1), "function_handle"))) then
|
||||
|
@ -73,178 +68,96 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
|
|||
end if
|
||||
|
||||
if (.not. (mxIsLogicalScalar(prhs(7)))) then
|
||||
call mexErrMsgTxt("Seventh argument (debug) should be a logical scalar")
|
||||
call mexErrMsgTxt("Seventh argument (block_decompose) should be a logical scalar")
|
||||
end if
|
||||
|
||||
if (.not. (mxIsStruct(prhs(8)) .and. &
|
||||
(mxGetNumberOfFields(prhs(8)) == 0 .or. mxGetNumberOfFields(prhs(8)) == 4))) then
|
||||
call mexErrMsgTxt("Eighth argument should be a struct with either 0 or 4 fields")
|
||||
if (.not. (mxIsLogicalScalar(prhs(8)))) then
|
||||
call mexErrMsgTxt("Eigth argument (debug) should be a logical scalar")
|
||||
end if
|
||||
|
||||
specializedunivariateblocks = (mxGetNumberOfFields(prhs(8)) == 4)
|
||||
|
||||
func => prhs(1)
|
||||
tolf = mxGetScalar(prhs(3))
|
||||
tolx = mxGetScalar(prhs(4))
|
||||
maxiter = int(mxGetScalar(prhs(5)))
|
||||
factor = mxGetScalar(prhs(6))
|
||||
debug = mxGetScalar(prhs(7)) == 1._c_double
|
||||
extra_args => prhs(9:nrhs) ! Extra arguments to func are in argument 9 and subsequent ones
|
||||
block_decompose = mxGetScalar(prhs(7)) == 1._c_double
|
||||
debug = mxGetScalar(prhs(8)) == 1._c_double
|
||||
extra_args => prhs(9:nrhs) ! Extra arguments to func are in argument 8 and subsequent ones
|
||||
associate (x_mat => mxGetPr(prhs(2)))
|
||||
allocate(x(size(x_mat)))
|
||||
x = x_mat
|
||||
end associate
|
||||
if (specializedunivariateblocks) then
|
||||
block
|
||||
type(c_ptr) :: tmp
|
||||
tmp = mxGetField(prhs(8), 1_mwIndex, "isloggedlhs")
|
||||
if (.not. (c_associated(tmp) .and. mxIsLogical(tmp) .and. mxGetNumberOfElements(tmp) == size(x))) then
|
||||
call mexErrMsgTxt("Seventh argument must have a 'isloggedlhs' field of type logical, of same size as second argument")
|
||||
end if
|
||||
isloggedlhs => mxGetLogicals(tmp)
|
||||
|
||||
tmp = mxGetField(prhs(8), 1_mwIndex, "isauxdiffloggedrhs")
|
||||
if (.not. (c_associated(tmp) .and. mxIsLogical(tmp) .and. mxGetNumberOfElements(tmp) == size(x))) then
|
||||
call mexErrMsgTxt("Seventh argument must have a 'isauxdiffloggedrhs' field of type &
|
||||
&logical, of same size as second argument")
|
||||
end if
|
||||
isauxdiffloggedrhs => mxGetLogicals(tmp)
|
||||
|
||||
lhs = mxGetField(prhs(8), 1_mwIndex, "lhs")
|
||||
if (.not. (c_associated(lhs) .and. mxIsCell(lhs) .and. mxGetNumberOfElements(lhs) == size(x))) then
|
||||
call mexErrMsgTxt("Seventh argument must have a 'lhs' field of type cell, of same size as second argument")
|
||||
end if
|
||||
|
||||
endo_names = mxGetField(prhs(8), 1_mwIndex, "endo_names")
|
||||
if (.not. (c_associated(endo_names) .and. mxIsCell(endo_names) .and. mxGetNumberOfElements(endo_names) == size(x))) then
|
||||
call mexErrMsgTxt("Seventh argument must have a 'endo_names' field of type cell, of same size as second argument")
|
||||
end if
|
||||
end block
|
||||
|
||||
allocate(evaled_cols(0))
|
||||
fre = .false.
|
||||
end if
|
||||
|
||||
allocate(fvec(size(x)))
|
||||
allocate(fjac(size(x), size(x)))
|
||||
|
||||
! Compute block decomposition
|
||||
nullify(x_indices, f_indices, x_all)
|
||||
call matlab_fcn(x, fvec, fjac)
|
||||
call dm_blocks(fjac, blocks)
|
||||
if (block_decompose) then
|
||||
! Compute block decomposition
|
||||
nullify(x_indices, f_indices, x_all)
|
||||
call matlab_fcn(x, fvec, fjac)
|
||||
call dm_blocks(fjac, blocks)
|
||||
|
||||
if (debug) then
|
||||
write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): number of blocks = ', i0)") size(blocks)
|
||||
call mexPrintf_trim_newline(debug_msg)
|
||||
end if
|
||||
|
||||
! Solve the system, starting from bottom-rightmost block
|
||||
do i = size(blocks),1,-1
|
||||
if (debug) then
|
||||
write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): solving block ', i0, ' of size ', i0)") &
|
||||
i, size(blocks(i)%col_indices)
|
||||
write (debug_msg, "('DYNARE_SOLVE (solve_algo=13): number of blocks = ', i0)") size(blocks)
|
||||
call mexPrintf_trim_newline(debug_msg)
|
||||
end if
|
||||
|
||||
if (specializedunivariateblocks .and. size(blocks(i)%col_indices) == 1) then
|
||||
! Solve the system, starting from bottom-rightmost block
|
||||
do i = size(blocks),1,-1
|
||||
if (debug) then
|
||||
write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): solving block ', i0, ' by evaluating RHS')") i
|
||||
write (debug_msg, "('DYNARE_SOLVE (solve_algo=13): solving block ', &
|
||||
&i0, ' of size ', i0)") &
|
||||
i, size(blocks(i)%col_indices)
|
||||
call mexPrintf_trim_newline(debug_msg)
|
||||
end if
|
||||
associate (eq => blocks(i)%row_indices(1), var => blocks(i)%col_indices(1))
|
||||
if (fre .or. any(abs(fjac(eq, evaled_cols)) > 0._real64)) then
|
||||
! Reevaluation of the residuals is required because the current RHS depends on
|
||||
! variables that potentially have been updated previously.
|
||||
nullify(x_indices, f_indices, x_all)
|
||||
call matlab_fcn(x, fvec)
|
||||
deallocate(evaled_cols) ! This shouldn’t be necessary, but it crashes otherwise with gfortran 8
|
||||
allocate(evaled_cols(0))
|
||||
fre = .false.
|
||||
end if
|
||||
evaled_cols = [ evaled_cols, var]
|
||||
block
|
||||
! An associate() construct for lhs_eq and endo_name_var makes the
|
||||
! code crash (with double free) using gfortran 8. Hence use a block
|
||||
character(kind=c_char, len=:), allocatable :: lhs_eq, endo_name_var
|
||||
lhs_eq = mxArrayToString(mxGetCell(lhs, int(eq, mwIndex)))
|
||||
endo_name_var = mxArrayToString(mxGetCell(endo_names, int(var, mwIndex)))
|
||||
if (lhs_eq == endo_name_var .or. lhs_eq == "log(" // endo_name_var // ")") then
|
||||
if (isloggedlhs(eq)) then
|
||||
x(var) = exp(log(x(var)) - fvec(eq))
|
||||
else
|
||||
x(var) = x(var) - fvec(eq)
|
||||
end if
|
||||
else
|
||||
if (debug) then
|
||||
write (debug_msg, "('LHS variable is not determined by RHS expression (', i0, ')')") eq
|
||||
call mexPrintf_trim_newline(debug_msg)
|
||||
write (debug_msg, "(a, ' -> ', a)") lhs_eq, endo_name_var
|
||||
call mexPrintf_trim_newline(debug_msg)
|
||||
end if
|
||||
if (lhs_eq(1:9) == "AUX_DIFF_" .or. lhs_eq(1:13) == "log(AUX_DIFF_") then
|
||||
if (isauxdiffloggedrhs(eq)) then
|
||||
x(var) = exp(log(x(var)) + fvec(eq))
|
||||
else
|
||||
x(var) = x(var) + fvec(eq)
|
||||
end if
|
||||
else
|
||||
call mexErrMsgTxt("Algorithm solve_algo=14 cannot be used with this nonlinear problem")
|
||||
end if
|
||||
end if
|
||||
end block
|
||||
end associate
|
||||
cycle
|
||||
|
||||
if (size(blocks(i)%col_indices) /= size(blocks(i)%row_indices)) then
|
||||
! Non-square block in DM decomposition
|
||||
! Before erroring out, check whether we are not already at the solution for this block
|
||||
! See also #1851
|
||||
if (norm2(fvec(blocks(i)%row_indices)) < tolf) then
|
||||
cycle
|
||||
else
|
||||
call mexErrMsgTxt("DYNARE_SOLVE (solve_algo=13): the Dulmage-Mendelsohn &
|
||||
&decomposition returned a non-square block. This means that the &
|
||||
&Jacobian is singular. You may want to try another value for solve_algo.")
|
||||
end if
|
||||
end if
|
||||
|
||||
block
|
||||
real(real64), dimension(size(blocks(i)%col_indices)) :: x_block
|
||||
x_indices => blocks(i)%col_indices
|
||||
f_indices => blocks(i)%row_indices
|
||||
x_all => x
|
||||
x_block = x(x_indices)
|
||||
call trust_region_solve(x_block, matlab_fcn, info, tolx, tolf, maxiter, factor)
|
||||
x(x_indices) = x_block
|
||||
end block
|
||||
end do
|
||||
|
||||
! Verify that we have a solution
|
||||
! Note that here we use the ∞-norm, while trust region uses 2-norm; otherwise
|
||||
! this check would almost always fail (because the 2-norm of the full fvec is
|
||||
! larger than the 2-norm of its sub-vectors)
|
||||
! If the check fails, this normally means that the block decomposition was
|
||||
! incorrect (because some element of the Jacobian was numerically zero at the
|
||||
! guess value while not being symbolically zero)
|
||||
nullify(x_indices, f_indices, x_all)
|
||||
call matlab_fcn(x, fvec)
|
||||
if (maxval(abs(fvec)) > tolf) then
|
||||
if (debug) &
|
||||
call mexPrintf_trim_newline("DYNARE_SOLVE (solve_algo=13): residuals&
|
||||
& still too large, solving for the whole model")
|
||||
call trust_region_solve(x, matlab_fcn, info, tolx, tolf, maxiter, factor)
|
||||
else
|
||||
if (debug) then
|
||||
write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): solving block ', i0, ' with trust region routine')") i
|
||||
call mexPrintf_trim_newline(debug_msg)
|
||||
if (size(blocks) > 1) then
|
||||
! Note that the value of info may be different across blocks
|
||||
info = 1
|
||||
end if
|
||||
end if
|
||||
|
||||
if (size(blocks(i)%col_indices) /= size(blocks(i)%row_indices)) then
|
||||
! Non-square block in DM decomposition
|
||||
! Before erroring out, check whether we are not already at the solution for this block
|
||||
! See also #1851
|
||||
if (norm2(fvec(blocks(i)%row_indices)) < tolf) then
|
||||
cycle
|
||||
else
|
||||
call mexErrMsgTxt("DYNARE_SOLVE (solve_algo=13|14): the Dulmage-Mendelsohn &
|
||||
&decomposition returned a non-square block. This means that the &
|
||||
&Jacobian is singular. You may want to try another value for solve_algo.")
|
||||
end if
|
||||
end if
|
||||
|
||||
block
|
||||
real(real64), dimension(size(blocks(i)%col_indices)) :: x_block
|
||||
x_indices => blocks(i)%col_indices
|
||||
f_indices => blocks(i)%row_indices
|
||||
x_all => x
|
||||
x_block = x(x_indices)
|
||||
call trust_region_solve(x_block, matlab_fcn, info, tolx, tolf, maxiter, factor)
|
||||
x(x_indices) = x_block
|
||||
end block
|
||||
|
||||
fre = .true.
|
||||
end do
|
||||
|
||||
! Verify that we have a solution
|
||||
! Note that here we use the ∞-norm, while trust region uses 2-norm; otherwise
|
||||
! this check would almost always fail (because the 2-norm of the full fvec is
|
||||
! larger than the 2-norm of its sub-vectors)
|
||||
! If the check fails, this normally means that the block decomposition was
|
||||
! incorrect (because some element of the Jacobian was numerically zero at the
|
||||
! guess value while not being symbolically zero)
|
||||
nullify(x_indices, f_indices, x_all)
|
||||
call matlab_fcn(x, fvec)
|
||||
if (maxval(abs(fvec)) > tolf) then
|
||||
if (debug) &
|
||||
call mexPrintf_trim_newline("DYNARE_SOLVE (solve_algo=13|14): residuals still too large, solving for the whole model")
|
||||
else ! No block decomposition
|
||||
nullify(x_indices, f_indices, x_all)
|
||||
call trust_region_solve(x, matlab_fcn, info, tolx, tolf, maxiter, factor)
|
||||
else
|
||||
if (size(blocks) > 1) then
|
||||
! Note that the value of info may be different across blocks
|
||||
info = 1
|
||||
end if
|
||||
end if
|
||||
|
||||
plhs(1) = mxCreateDoubleMatrix(int(size(x, 1), mwSize), 1_mwSize, mxREAL)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f725c534ef1344813421c2404de2cb4f3774d113
|
||||
Subproject commit c48248fc0d65ed70fb13dd508ed0254f113cbcb6
|
|
@ -498,7 +498,19 @@ MODFILES = \
|
|||
log_transform/example1.mod \
|
||||
log_transform/ramst.mod \
|
||||
log_transform/fs2000_nonstationary.mod \
|
||||
log_transform/nk_ramsey.mod
|
||||
log_transform/nk_ramsey.mod \
|
||||
solve_algo_12_14/simul_backward_reference.mod \
|
||||
solve_algo_12_14/simul_backward_12.mod \
|
||||
solve_algo_12_14/simul_backward_14.mod \
|
||||
solve_algo_12_14/purely_backward_reference.mod \
|
||||
solve_algo_12_14/purely_backward_12.mod \
|
||||
solve_algo_12_14/purely_backward_14.mod \
|
||||
solve_algo_12_14/purely_static_reference.mod \
|
||||
solve_algo_12_14/purely_static_12.mod \
|
||||
solve_algo_12_14/purely_static_14.mod \
|
||||
solve_algo_12_14/purely_forward_reference.mod \
|
||||
solve_algo_12_14/purely_forward_12.mod \
|
||||
solve_algo_12_14/purely_forward_14.mod
|
||||
|
||||
ECB_MODFILES = \
|
||||
var-expectations/1/example1.mod \
|
||||
|
@ -994,6 +1006,27 @@ model-inversion/nk-2/z_check_inversion.o.trs: model-inversion/nk-2/invert.o.trs
|
|||
ep/rbcii_MCP.m.trs: ep/rbcii.m.trs
|
||||
ep/rbcii_MCP.o.trs: ep/rbcii.o.trs
|
||||
|
||||
solve_algo_12_14/simul_backward_12.m.trs: solve_algo_12_14/simul_backward_reference.m.trs
|
||||
solve_algo_12_14/simul_backward_12.o.trs: solve_algo_12_14/simul_backward_reference.o.trs
|
||||
solve_algo_12_14/simul_backward_14.m.trs: solve_algo_12_14/simul_backward_reference.m.trs
|
||||
solve_algo_12_14/simul_backward_14.o.trs: solve_algo_12_14/simul_backward_reference.o.trs
|
||||
|
||||
solve_algo_12_14/purely_backward_12.m.trs: solve_algo_12_14/purely_backward_reference.m.trs
|
||||
solve_algo_12_14/purely_backward_12.o.trs: solve_algo_12_14/purely_backward_reference.o.trs
|
||||
solve_algo_12_14/purely_backward_14.m.trs: solve_algo_12_14/purely_backward_reference.m.trs
|
||||
solve_algo_12_14/purely_backward_14.o.trs: solve_algo_12_14/purely_backward_reference.o.trs
|
||||
|
||||
solve_algo_12_14/purely_static_12.m.trs: solve_algo_12_14/purely_static_reference.m.trs
|
||||
solve_algo_12_14/purely_static_12.o.trs: solve_algo_12_14/purely_static_reference.o.trs
|
||||
solve_algo_12_14/purely_static_14.m.trs: solve_algo_12_14/purely_static_reference.m.trs
|
||||
solve_algo_12_14/purely_static_14.o.trs: solve_algo_12_14/purely_static_reference.o.trs
|
||||
|
||||
solve_algo_12_14/purely_forward_12.m.trs: solve_algo_12_14/purely_forward_reference.m.trs
|
||||
solve_algo_12_14/purely_forward_12.o.trs: solve_algo_12_14/purely_forward_reference.o.trs
|
||||
solve_algo_12_14/purely_forward_14.m.trs: solve_algo_12_14/purely_forward_reference.m.trs
|
||||
solve_algo_12_14/purely_forward_14.o.trs: solve_algo_12_14/purely_forward_reference.o.trs
|
||||
|
||||
|
||||
observation_trends_and_prefiltering/MCMC: m/observation_trends_and_prefiltering/MCMC o/observation_trends_and_prefiltering/MCMC
|
||||
m/observation_trends_and_prefiltering/MCMC: $(patsubst %.mod, %.m.trs, $(filter observation_trends_and_prefiltering/MCMC/%.mod, $(MODFILES)))
|
||||
o/observation_trends_and_prefiltering/MCMC: $(patsubst %.mod, %.o.trs, $(filter observation_trends_and_prefiltering/MCMC/%.mod, $(MODFILES)))
|
||||
|
@ -1210,6 +1243,11 @@ model-inversion: m/model-inversion o/model-inversion
|
|||
m/model-inversion: $(patsubst %.mod, %.m.trs, $(filter model-inversion/%.mod, $(MODFILES)))
|
||||
o/model-inversion: $(patsubst %.mod, %.o.trs, $(filter model-inversion/%.mod, $(MODFILES)))
|
||||
|
||||
solve_algo_12_14: m/solve_algo_12_14 o/solve_algo_12_14
|
||||
m/solve_algo_12_14: $(patsubst %.mod, %.m.trs, $(filter solve_algo_12_14/%.mod, $(MODFILES)))
|
||||
o/solve_algo_12_14: $(patsubst %.mod, %.o.trs, $(filter solve_algo_12_14/%.mod, $(MODFILES)))
|
||||
|
||||
|
||||
# ECB files
|
||||
M_ECB_TRS_FILES = $(patsubst %.mod, %.m.trs, $(ECB_MODFILES))
|
||||
|
||||
|
@ -1448,7 +1486,12 @@ EXTRA_DIST = \
|
|||
solver-test-functions/variablydimensioned.m \
|
||||
solver-test-functions/watson.m \
|
||||
solver-test-functions/wood.m \
|
||||
ramst_normcdf_and_friends.inc
|
||||
ramst_normcdf_and_friends.inc \
|
||||
solve_algo_12_14/backward_model.inc \
|
||||
solve_algo_12_14/simul_backward_common.inc \
|
||||
solve_algo_12_14/purely_backward_common.inc \
|
||||
solve_algo_12_14/purely_static_common.inc \
|
||||
solve_algo_12_14/purely_forward_common.inc
|
||||
|
||||
if ENABLE_MATLAB
|
||||
check-local: check-matlab
|
||||
|
@ -1639,6 +1682,8 @@ clean-local:
|
|||
|
||||
rm -rf tests/pac/var-12/toto
|
||||
|
||||
rm -f solve_algo_12_14/simul_backward_ref.mat
|
||||
|
||||
find . -name "*.tex" -type f -delete
|
||||
find . -name "*.aux" -type f -delete
|
||||
find . -name "*.log" -type f -delete
|
||||
|
|
|
@ -31,8 +31,6 @@ tolx = 1e-6;
|
|||
maxit = 50;
|
||||
factor = 10;
|
||||
|
||||
auxstruct = struct();
|
||||
|
||||
% List of function handles
|
||||
objfun = { @rosenbrock,
|
||||
@powell1,
|
||||
|
@ -73,7 +71,7 @@ for i=1:length(objfun)
|
|||
x = objfun{i}();
|
||||
end
|
||||
try
|
||||
[x, errorflag, exitflag] = block_trust_region(objfun{i}, x, tolf, tolx, maxit, factor, false, auxstruct);
|
||||
[x, errorflag, exitflag] = block_trust_region(objfun{i}, x, tolf, tolx, maxit, factor, true, false);
|
||||
if isequal(func2str(objfun{i}), 'powell2')
|
||||
if ~errorflag
|
||||
testFailed = testFailed+1;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* A simple purely backward model, used for testing both “simul_backward” and
|
||||
perfect foresight simulations, consisting of:
|
||||
- a VAR(3) with one variable in level, one in log and one log-differentiated;
|
||||
- two other variables that depend on the contemporaneous values of the VAR(3),
|
||||
and which together for a simultaneous block.
|
||||
Those five equations are repeated an arbitrary number of times (n). */
|
||||
|
||||
@#define n = 10
|
||||
|
||||
@#for i in 1:n
|
||||
var x@{i}, y@{i}, z@{i}, t@{i}, s@{i};
|
||||
varexo e_x@{i}, e_y@{i}, e_z@{i}, e_t@{i}, e_s@{i};
|
||||
@#endfor
|
||||
|
||||
model(use_dll);
|
||||
@#for i in 1:n
|
||||
x@{i} = 0.1*x@{i}(-1) + 0.2*log(y@{i}(-1)) + 0.3*diff(log(z@{i}(-1))) + e_x@{i};
|
||||
[name = 'y']
|
||||
log(y@{i}) = 0.4*x@{i}(-1) + 0.5*log(y@{i}(-1)) + 0.6*diff(log(z@{i}(-1))) + e_y@{i};
|
||||
[name = 'z']
|
||||
/* NB: we choose 0.5 as steady state for z, since initial value is drawn from
|
||||
[0,1] (in the “simul_backward” case) */
|
||||
diff(log(z@{i})) = -0.8*(log(z@{i}(-1)) - log(0.5)) + 0.1*x@{i}(-1) + 0.2*log(y@{i}(-1)) - 0.3*diff(log(z@{i}(-1))) + e_z@{i};
|
||||
|
||||
t@{i} = x@{i} + 2*log(y@{i}) + 3*diff(log(z@{i})) + s@{i} + e_t@{i};
|
||||
s@{i} = 4*x@{i}(-1) + 3*t@{i} + e_s@{i};
|
||||
@#endfor
|
||||
end;
|
|
@ -0,0 +1,13 @@
|
|||
// Check the correctedness of perfect foresight simulation of a purely backward model with “solve_algo=12”
|
||||
|
||||
@#include "purely_backward_common.inc"
|
||||
|
||||
perfect_foresight_solver(solve_algo = 12);
|
||||
|
||||
ref = load('purely_backward_reference/Output/purely_backward_reference_results.mat');
|
||||
|
||||
if max(max(abs(oo_.endo_simul - ref.oo_.endo_simul))) > 5e-5
|
||||
error('Incorrect results for perfect foresight with solve_algo=12')
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Check the correctedness of perfect foresight simulation of a purely backward model with “solve_algo=14”
|
||||
|
||||
@#include "purely_backward_common.inc"
|
||||
|
||||
perfect_foresight_solver(solve_algo = 14);
|
||||
|
||||
ref = load('purely_backward_reference/Output/purely_backward_reference_results.mat');
|
||||
|
||||
if max(max(abs(oo_.endo_simul - ref.oo_.endo_simul))) > 5e-5
|
||||
error('Incorrect results for perfect foresight with solve_algo=14')
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
@#include "backward_model.inc"
|
||||
|
||||
initval;
|
||||
@#for i in 1:n
|
||||
y@{i} = 1;
|
||||
z@{i} = 0.5;
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
shocks;
|
||||
@#for i in 1:n
|
||||
var e_x@{i};
|
||||
periods 1;
|
||||
values @{0.1/n};
|
||||
|
||||
var e_y@{i};
|
||||
periods 2;
|
||||
values @{0.05+0.1/n};
|
||||
|
||||
var e_z@{i};
|
||||
periods 3;
|
||||
values @{0.1+0.1/n};
|
||||
|
||||
var e_t@{i};
|
||||
periods 4;
|
||||
values @{0.15+0.1/n};
|
||||
|
||||
var e_s@{i};
|
||||
periods 5;
|
||||
values @{0.2+0.1/n};
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
perfect_foresight_setup(periods = 100);
|
|
@ -0,0 +1,5 @@
|
|||
// Reference perfect foresight simulation of a purely backward model with default “solve_algo” value
|
||||
|
||||
@#include "purely_backward_common.inc"
|
||||
|
||||
perfect_foresight_solver;
|
|
@ -0,0 +1,13 @@
|
|||
// Check the correctedness of perfect foresight simulation of a purely forward model with “solve_algo=12”
|
||||
|
||||
@#include "purely_forward_common.inc"
|
||||
|
||||
perfect_foresight_solver(solve_algo = 12);
|
||||
|
||||
ref = load('purely_forward_reference/Output/purely_forward_reference_results.mat');
|
||||
|
||||
if max(max(abs(oo_.endo_simul - ref.oo_.endo_simul))) > 2e-4
|
||||
error('Incorrect results for perfect foresight with solve_algo=12')
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Check the correctedness of perfect foresight simulation of a purely forward model with “solve_algo=14”
|
||||
|
||||
@#include "purely_forward_common.inc"
|
||||
|
||||
perfect_foresight_solver(solve_algo = 14);
|
||||
|
||||
ref = load('purely_forward_reference/Output/purely_forward_reference_results.mat');
|
||||
|
||||
if max(max(abs(oo_.endo_simul - ref.oo_.endo_simul))) > 2e-4
|
||||
error('Incorrect results for perfect foresight with solve_algo=14')
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* A simple purely forward model, consisting of:
|
||||
- a forward VAR(3) with one variable in level, one in log and one log-forward-differentiated;
|
||||
- two other variables that depend on the contemporaneous values of the VAR(3),
|
||||
and which together for a simultaneous block.
|
||||
Those five equations are repeated an arbitrary number of times (n). */
|
||||
|
||||
@#define n = 10
|
||||
|
||||
@#for i in 1:n
|
||||
var x@{i}, y@{i}, z@{i}, t@{i}, s@{i};
|
||||
varexo e_x@{i}, e_y@{i}, e_z@{i}, e_t@{i}, e_s@{i};
|
||||
@#endfor
|
||||
|
||||
model;
|
||||
@#for i in 1:n
|
||||
x@{i} = 0.1*x@{i}(+1) + 0.2*log(y@{i}(+1)) + 0.3*(log(z@{i})-log(z@{i}(+1))) + e_x@{i};
|
||||
[name = 'y']
|
||||
log(y@{i}) = 0.4*x@{i}(+1) + 0.5*log(y@{i}(+1)) + 0.6*(log(z@{i})-log(z@{i}(+1))) + e_y@{i};
|
||||
[name = 'z']
|
||||
/* NB: we choose 0.5 as steady state for z, since initial value is drawn from
|
||||
[0,1] (in the “simul_backward” case) */
|
||||
log(z@{i})-log(z@{i}(+1)) = -0.8*(log(z@{i}(+1)) - log(0.5)) + 0.1*x@{i}(+1) + 0.2*log(y@{i}(+1)) - 0.3*(log(z@{i}) - log(z@{i}(+1))) + e_z@{i};
|
||||
|
||||
t@{i} = x@{i} + 2*log(y@{i}) + 3*(log(z@{i})-log(z@{i}(+1))) + s@{i} + e_t@{i};
|
||||
s@{i} = 4*x@{i}(+1) + 3*t@{i} + e_s@{i};
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
initval;
|
||||
@#for i in 1:n
|
||||
y@{i} = 1;
|
||||
z@{i} = 0.5;
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
shocks;
|
||||
@#for i in 1:n
|
||||
var e_x@{i};
|
||||
periods 99;
|
||||
values @{0.1/n};
|
||||
|
||||
var e_y@{i};
|
||||
periods 98;
|
||||
values @{0.05+0.1/n};
|
||||
|
||||
var e_z@{i};
|
||||
periods 97;
|
||||
values @{0.1+0.1/n};
|
||||
|
||||
var e_t@{i};
|
||||
periods 96;
|
||||
values @{0.15+0.1/n};
|
||||
|
||||
var e_s@{i};
|
||||
periods 95;
|
||||
values @{0.2+0.1/n};
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
perfect_foresight_setup(periods = 100);
|
|
@ -0,0 +1,5 @@
|
|||
// Reference perfect foresight simulation of a purely forward model with default “solve_algo” value
|
||||
|
||||
@#include "purely_forward_common.inc"
|
||||
|
||||
perfect_foresight_solver;
|
|
@ -0,0 +1,11 @@
|
|||
// Check the correctedness of perfect foresight simulation of a purely static model with “solve_algo=12”
|
||||
|
||||
@#include "purely_static_common.inc"
|
||||
|
||||
perfect_foresight_solver(solve_algo = 12);
|
||||
|
||||
ref = load('purely_static_reference/Output/purely_static_reference_results.mat');
|
||||
|
||||
if max(max(abs(oo_.endo_simul - ref.oo_.endo_simul))) > 1e-16
|
||||
error('Incorrect results for perfect foresight with solve_algo=12')
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
// Check the correctedness of perfect foresight simulation of a purely static model with “solve_algo=14”
|
||||
|
||||
@#include "purely_static_common.inc"
|
||||
|
||||
perfect_foresight_solver(solve_algo = 14);
|
||||
|
||||
ref = load('purely_static_reference/Output/purely_static_reference_results.mat');
|
||||
|
||||
if max(max(abs(oo_.endo_simul - ref.oo_.endo_simul))) > 1e-16
|
||||
error('Incorrect results for perfect foresight with solve_algo=14')
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
@#define n = 10
|
||||
|
||||
@#for i in 1:n
|
||||
var x@{i}, t@{i}, s@{i};
|
||||
varexo e_x@{i}, e_t@{i}, e_s@{i};
|
||||
@#endfor
|
||||
|
||||
model;
|
||||
@#for i in 1:n
|
||||
x@{i} = e_x@{i};
|
||||
t@{i} = x@{i} + s@{i} + e_t@{i};
|
||||
s@{i} = 3*t@{i} + e_s@{i};
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
shocks;
|
||||
@#for i in 1:n
|
||||
var e_x@{i};
|
||||
periods 1;
|
||||
values @{0.1/n};
|
||||
|
||||
var e_t@{i};
|
||||
periods 2;
|
||||
values @{0.05+0.1/n};
|
||||
|
||||
var e_s@{i};
|
||||
periods 3;
|
||||
values @{0.1+0.1/n};
|
||||
@#endfor
|
||||
end;
|
||||
|
||||
perfect_foresight_setup(periods = 100);
|
|
@ -0,0 +1,5 @@
|
|||
// Reference perfect foresight simulation of a purely static model with default “solve_algo” value
|
||||
|
||||
@#include "purely_static_common.inc"
|
||||
|
||||
perfect_foresight_solver;
|
|
@ -0,0 +1,12 @@
|
|||
// Check the correctedness of “simul_backward” with “solve_algo=12”
|
||||
|
||||
@#include "simul_backward_common.inc"
|
||||
|
||||
options_.solve_algo = 12;
|
||||
s = simul_backward_model(initialconditions, @{simlength}, innovations);
|
||||
|
||||
ref = load('simul_backward_ref.mat');
|
||||
|
||||
if max(max(abs(s.data - ref.s.data))) > 5e-4
|
||||
error('Incorrect results for simul_backward with solve_algo=12')
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
// Check the correctedness of “simul_backward” with “solve_algo=14”
|
||||
|
||||
@#include "simul_backward_common.inc"
|
||||
|
||||
options_.solve_algo = 14;
|
||||
s = simul_backward_model(initialconditions, @{simlength}, innovations);
|
||||
|
||||
ref = load('simul_backward_ref.mat');
|
||||
|
||||
if max(max(abs(s.data - ref.s.data))) > 5e-4
|
||||
error('Incorrect results for simul_backward with solve_algo=14')
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
@#include "backward_model.inc"
|
||||
|
||||
@#define simlength = 100
|
||||
|
||||
initialconditions = dseries(rand(2, @{5*n}), '2021Q3', { ...
|
||||
@#for i in 1:n
|
||||
'x@{i}', 'y@{i}', 'z@{i}', 't@{i}', 's@{i}', ...
|
||||
@#endfor
|
||||
});
|
||||
|
||||
innovations = dseries(randn(@{simlength}, @{5*n}), '2022Q1', { ...
|
||||
@#for i in 1:n
|
||||
'e_x@{i}', 'e_y@{i}', 'e_z@{i}', 'e_t@{i}', 'e_s@{i}', ...
|
||||
@#endfor
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
// Reference simulation with “simul_backward” and default “solve_algo” value
|
||||
|
||||
@#include "simul_backward_common.inc"
|
||||
|
||||
s = simul_backward_model(initialconditions, @{simlength}, innovations);
|
||||
|
||||
save simul_backward_ref.mat s
|
Loading…
Reference in New Issue