Make perfect foresight hotomopy loop more readable
Only modify oo_ when the homotopy procedure is finished, now that oo_ is no longer an input to perfect_foresight_solver_core. By the way, fix the treatment of the exogenous steady state (it is now set in a consistent way with the endogenous steady state, if the shock is not simulated up to 100%). Also fix the initial guess when doing a second attempt at recomputing the terminal steady state and failing (in the absence of a permanent shock). It was supposed to use the initial steady state as an initial guess for that second attempt (through oo_.steady_state), but since that latter variable was modified in the loop, it would actually correspond to the same initial guess as in the first attempt.kalman-mex
parent
e26f3f5d06
commit
9ebd8a8372
|
@ -120,6 +120,12 @@ end
|
|||
exoorig = oo_.exo_simul;
|
||||
endoorig = oo_.endo_simul;
|
||||
|
||||
% Initialize paths for endogenous and exogenous, and final steady state that will be modified during homotopy
|
||||
endo_simul = oo_.endo_simul;
|
||||
exo_simul = oo_.exo_simul;
|
||||
steady_state = oo_.steady_state;
|
||||
exo_steady_state = oo_.exo_steady_state;
|
||||
|
||||
current_share = 0; % Share of shock successfully completed so far
|
||||
step = min(options_.simul.homotopy_initial_step_size, options_.simul.homotopy_max_completion_share);
|
||||
success_counter = 0;
|
||||
|
@ -131,12 +137,12 @@ function local_success = create_scenario(share)
|
|||
% guess for endogenous)
|
||||
|
||||
% Compute convex combination for the path of exogenous
|
||||
oo_.exo_simul = exoorig*share + exobase*(1-share);
|
||||
exo_simul = exoorig*share + exobase*(1-share);
|
||||
|
||||
% Compute convex combination for the initial condition
|
||||
% In most cases, the initial condition is a steady state and this does nothing
|
||||
% This is for cases when the initial condition is out of equilibrium
|
||||
oo_.endo_simul(:, initperiods) = share*endoorig(:, initperiods)+(1-share)*endobase(:, initperiods);
|
||||
endo_simul(:, initperiods) = share*endoorig(:, initperiods)+(1-share)*endobase(:, initperiods);
|
||||
|
||||
% If there is a permanent shock, ensure that the rescaled terminal condition is
|
||||
% a steady state (if the user asked for this recomputation, or if the original
|
||||
|
@ -156,11 +162,11 @@ function local_success = create_scenario(share)
|
|||
saved_steady_markowitz = options_.markowitz;
|
||||
options_.markowitz = options_.simul.steady_markowitz;
|
||||
|
||||
saved_ss = oo_.endo_simul(:, lastperiods);
|
||||
saved_ss = endo_simul(:, lastperiods);
|
||||
% Effectively compute the terminal steady state
|
||||
for j = lastperiods
|
||||
% First use the terminal steady of the previous homotopy iteration as guess value (or the contents of the endval block if this is the first iteration)
|
||||
[oo_.endo_simul(:, j), ~, info] = evaluate_steady_state(oo_.endo_simul(:, j), oo_.exo_simul(j, :)', M_, options_, true);
|
||||
[endo_simul(:, j), ~, info] = evaluate_steady_state(endo_simul(:, j), exo_simul(j, :)', M_, options_, true);
|
||||
if info(1)
|
||||
% If this fails, then try again using the initial steady state as guess value
|
||||
if isempty(ys0_)
|
||||
|
@ -168,10 +174,10 @@ function local_success = create_scenario(share)
|
|||
else
|
||||
guess_value = ys0_;
|
||||
end
|
||||
[oo_.endo_simul(:, j), ~, info] = evaluate_steady_state(guess_value, oo_.exo_simul(j, :)', M_, options_, true);
|
||||
[endo_simul(:, j), ~, info] = evaluate_steady_state(guess_value, exo_simul(j, :)', M_, options_, true);
|
||||
if info(1)
|
||||
% If this fails again, give up and restore last periods in oo_.endo_simul
|
||||
oo_.endo_simul(:, lastperiods) = saved_ss;
|
||||
% If this fails again, give up and restore last periods in endo_simul
|
||||
endo_simul(:, lastperiods) = saved_ss;
|
||||
local_success = false;
|
||||
break;
|
||||
end
|
||||
|
@ -179,7 +185,9 @@ function local_success = create_scenario(share)
|
|||
end
|
||||
|
||||
% The following is needed for the STEADY_STATE() operator to work properly
|
||||
oo_.steady_state = oo_.endo_simul(:, end);
|
||||
steady_state = endo_simul(:, end);
|
||||
|
||||
exo_steady_state = exo_simul(end, :)';
|
||||
|
||||
options_.solve_algo = saved_steady_solve_algo;
|
||||
options_.steady.maxit = saved_steady_maxit;
|
||||
|
@ -188,7 +196,7 @@ function local_success = create_scenario(share)
|
|||
options_.markowitz = saved_steady_markowitz;
|
||||
else
|
||||
% The terminal condition is not a steady state, compute a convex combination
|
||||
oo_.endo_simul(:, lastperiods) = share*endoorig(:, lastperiods)+(1-share)*endobase(:, lastperiods);
|
||||
endo_simul(:, lastperiods) = share*endoorig(:, lastperiods)+(1-share)*endobase(:, lastperiods);
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -196,7 +204,7 @@ while step > options_.simul.homotopy_min_step_size
|
|||
|
||||
iteration = iteration+1;
|
||||
|
||||
saved_endo_simul = oo_.endo_simul;
|
||||
saved_endo_simul = endo_simul;
|
||||
|
||||
new_share = current_share + step; % Try this share, and see if it succeeds
|
||||
|
||||
|
@ -217,16 +225,16 @@ while step > options_.simul.homotopy_min_step_size
|
|||
% scenario / initial steady state).
|
||||
if current_share == 0
|
||||
if iteration == 1 && new_share == 1
|
||||
oo_.endo_simul(:, simperiods) = endoorig(:, simperiods);
|
||||
endo_simul(:, simperiods) = endoorig(:, simperiods);
|
||||
elseif M_.maximum_lead > 0
|
||||
oo_.endo_simul(:, simperiods) = repmat(oo_.endo_simul(:, lastperiods(1)), 1, options_.periods);
|
||||
endo_simul(:, simperiods) = repmat(endo_simul(:, lastperiods(1)), 1, options_.periods);
|
||||
else
|
||||
oo_.endo_simul(:, simperiods) = endobase(:, simperiods);
|
||||
endo_simul(:, simperiods) = endobase(:, simperiods);
|
||||
end
|
||||
end
|
||||
|
||||
% Solve for the paths of the endogenous variables.
|
||||
[oo_.endo_simul, success, maxerror, solver_iter, per_block_status] = perfect_foresight_solver_core(oo_.endo_simul, oo_.exo_simul, oo_.steady_state, oo_.exo_steady_state, M_, options_);
|
||||
[endo_simul, success, maxerror, solver_iter, per_block_status] = perfect_foresight_solver_core(endo_simul, exo_simul, steady_state, exo_steady_state, M_, options_);
|
||||
else
|
||||
success = false;
|
||||
maxerror = NaN;
|
||||
|
@ -279,7 +287,7 @@ while step > options_.simul.homotopy_min_step_size
|
|||
step = step * 2;
|
||||
end
|
||||
else
|
||||
oo_.endo_simul = saved_endo_simul;
|
||||
endo_simul = saved_endo_simul;
|
||||
success_counter = 0;
|
||||
step = step / 2;
|
||||
if ~options_.noprint
|
||||
|
@ -299,11 +307,11 @@ if did_homotopy && ~options_.noprint
|
|||
end
|
||||
|
||||
%If simulated paths are complex, take real part and recompute the residuals to check whether this is actually a solution
|
||||
if ~isreal(oo_.endo_simul(:)) % cannot happen with bytecode or the perfect_foresight_problem DLL
|
||||
real_simul = real(oo_.endo_simul);
|
||||
real_maxerror = recompute_maxerror(real_simul, oo_, M_, options_);
|
||||
if ~isreal(endo_simul(:)) % cannot happen with bytecode or the perfect_foresight_problem DLL
|
||||
real_simul = real(endo_simul);
|
||||
real_maxerror = recompute_maxerror(real_simul, exo_simul, steady_state, M_, options_);
|
||||
if real_maxerror <= options_.dynatol.f
|
||||
oo_.endo_simul = real_simul;
|
||||
endo_simul = real_simul;
|
||||
maxerror = real_maxerror;
|
||||
else
|
||||
current_share = 0;
|
||||
|
@ -311,22 +319,29 @@ if ~isreal(oo_.endo_simul(:)) % cannot happen with bytecode or the perfect_fores
|
|||
end
|
||||
end
|
||||
|
||||
% Put solver status information in oo_, and do linearization if needed and requested
|
||||
% Do linearization if needed and requested, and put results and solver status information in oo_
|
||||
if current_share == 1
|
||||
oo_.endo_simul = endo_simul;
|
||||
if options_.simul.endval_steady
|
||||
oo_.steady_state = steady_state;
|
||||
end
|
||||
% NB: no need to modify oo_.exo_simul and oo_.exo_steady_state, since we simulated 100% of the shock
|
||||
|
||||
if ~options_.noprint
|
||||
fprintf('Perfect foresight solution found.\n\n')
|
||||
end
|
||||
oo_.deterministic_simulation.status = true;
|
||||
elseif options_.simul.homotopy_linearization_fallback && current_share > 0
|
||||
oo_.endo_simul = endobase + (oo_.endo_simul - endobase)/current_share;
|
||||
oo_.exo_simul = exoorig;
|
||||
oo_.endo_simul = endobase + (endo_simul - endobase)/current_share;
|
||||
if options_.simul.endval_steady
|
||||
% The following is needed for the STEADY_STATE() operator to work properly,
|
||||
% and thus must come before computing the maximum error.
|
||||
% This is not a true steady state, but it is the closest we can get to
|
||||
oo_.steady_state = oo_.endo_simul(:, end);
|
||||
end
|
||||
maxerror = recompute_maxerror(oo_.endo_simul, oo_, M_, options_);
|
||||
% NB: no need to modify oo_.exo_simul and oo_.exo_steady_state, since we simulated 100% of the shock (although with an approximation)
|
||||
|
||||
maxerror = recompute_maxerror(oo_.endo_simul, oo_.exo_simul, oo_.steady_state, M_, options_);
|
||||
|
||||
if ~options_.noprint
|
||||
fprintf('Perfect foresight solution found for %.1f%% of the shock, then extrapolation was performed using linearization\n\n', current_share*100)
|
||||
|
@ -334,34 +349,49 @@ elseif options_.simul.homotopy_linearization_fallback && current_share > 0
|
|||
oo_.deterministic_simulation.status = true;
|
||||
oo_.deterministic_simulation.homotopy_linearization = true;
|
||||
elseif options_.simul.homotopy_marginal_linearization_fallback > 0 && current_share > options_.simul.homotopy_marginal_linearization_fallback
|
||||
saved_endo_simul = oo_.endo_simul;
|
||||
saved_endo_simul = endo_simul;
|
||||
saved_exo_simul = exo_simul;
|
||||
saved_steady_state = steady_state;
|
||||
saved_exo_steady_state = exo_steady_state;
|
||||
|
||||
new_share = current_share - options_.simul.homotopy_marginal_linearization_fallback;
|
||||
extra_simul_time_counter = tic;
|
||||
new_success = create_scenario(new_share);
|
||||
if new_success
|
||||
[oo_.endo_simul, new_success] = perfect_foresight_solver_core(oo_.endo_simul, oo_.exo_simul, oo_.steady_state, oo_.exo_steady_state, M_, options_);
|
||||
[endo_simul, new_success] = perfect_foresight_solver_core(endo_simul, exo_simul, steady_state, exo_steady_state, M_, options_);
|
||||
end
|
||||
extra_simul_time_elapsed = toc(extra_simul_time_counter);
|
||||
if new_success
|
||||
oo_.endo_simul = saved_endo_simul + (saved_endo_simul - oo_.endo_simul)*(1-current_share)/options_.simul.homotopy_marginal_linearization_fallback;
|
||||
oo_.exo_simul = exoorig;
|
||||
oo_.endo_simul = saved_endo_simul + (saved_endo_simul - endo_simul)*(1-current_share)/options_.simul.homotopy_marginal_linearization_fallback;
|
||||
if options_.simul.endval_steady
|
||||
% The following is needed for the STEADY_STATE() operator to work properly,
|
||||
% and thus must come before computing the maximum error.
|
||||
% This is not a true steady state, but it is the closest we can get to
|
||||
oo_.steady_state = oo_.endo_simul(:, end);
|
||||
end
|
||||
maxerror = recompute_maxerror(oo_.endo_simul, oo_, M_, options_);
|
||||
% NB: no need to modify oo_.exo_simul and oo_.exo_steady_state, since we simulated 100% of the shock (although with an approximation)
|
||||
|
||||
maxerror = recompute_maxerror(oo_.endo_simul, oo_.exo_simul, oo_.steady_state, M_, options_);
|
||||
|
||||
if ~options_.noprint
|
||||
fprintf('Perfect foresight solution found for %.1f%% of the shock, then extrapolation was performed using marginal linearization (extra simulation took %.1f seconds)\n\n', current_share*100, extra_simul_time_elapsed)
|
||||
end
|
||||
oo_.deterministic_simulation.homotopy_marginal_linearization = true;
|
||||
else
|
||||
% Set oo_ values to the partial simulation
|
||||
oo_.endo_simul = saved_endo_simul;
|
||||
oo_.exo_simul = saved_exo_simul;
|
||||
oo_.steady_state = saved_steady_state;
|
||||
oo_.exo_steady_state = saved_exo_steady_state;
|
||||
fprintf('perfect_foresight_solver: marginal linearization failed, unable to find solution for %.1f%% of the shock (extra simulation took %.1f seconds). Try to modify the value of homotopy_marginal_linearization_fallback option\n\n', new_share*100, extra_simul_time_elapsed)
|
||||
end
|
||||
oo_.deterministic_simulation.status = new_success;
|
||||
else
|
||||
% Set oo_ values to the partial simulation
|
||||
oo_.endo_simul = endo_simul;
|
||||
oo_.exo_simul = exo_simul;
|
||||
oo_.steady_state = steady_state;
|
||||
oo_.exo_steady_state = exo_steady_state;
|
||||
fprintf('Failed to solve perfect foresight model\n\n')
|
||||
oo_.deterministic_simulation.status = false;
|
||||
end
|
||||
|
@ -407,11 +437,11 @@ end
|
|||
|
||||
end
|
||||
|
||||
function maxerror = recompute_maxerror(endo_simul, oo_, M_, options_)
|
||||
function maxerror = recompute_maxerror(endo_simul, exo_simul, steady_state, M_, options_)
|
||||
% Computes ∞-norm of residuals for a given path of endogenous,
|
||||
% given the exogenous path and parameters in oo_ and M_
|
||||
% given the exogenous path, steady state and parameters in M_
|
||||
if options_.bytecode
|
||||
residuals = bytecode('dynamic', 'evaluate', M_, options_, endo_simul, oo_.exo_simul, M_.params, oo_.steady_state, 1);
|
||||
residuals = bytecode('dynamic', 'evaluate', M_, options_, endo_simul, exo_simul, M_.params, steady_state, 1);
|
||||
else
|
||||
ny = size(endo_simul, 1);
|
||||
periods = size(endo_simul, 2) - M_.maximum_lag - M_.maximum_lead;
|
||||
|
@ -426,7 +456,7 @@ function maxerror = recompute_maxerror(endo_simul, oo_, M_, options_)
|
|||
yT = NaN(ny, 1);
|
||||
end
|
||||
yy = endo_simul(:,M_.maximum_lag+(1:periods));
|
||||
residuals = perfect_foresight_problem(yy(:), y0, yT, oo_.exo_simul, M_.params, oo_.steady_state, periods, M_, options_);
|
||||
residuals = perfect_foresight_problem(yy(:), y0, yT, exo_simul, M_.params, steady_state, periods, M_, options_);
|
||||
end
|
||||
maxerror = norm(vec(residuals), 'Inf');
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue