diff --git a/matlab/+pac/+mce/parameters.m b/matlab/+pac/+mce/parameters.m index 6098a9fdfc1bbec96f12b3c6acfb25953ebc1b4d..f424909c7516d24a5f6e8a1b0fc6f1177a720801 100644 --- a/matlab/+pac/+mce/parameters.m +++ b/matlab/+pac/+mce/parameters.m @@ -11,7 +11,7 @@ function parameters(pacname) % SPECIAL REQUIREMENTS % none -% Copyright © 2019-2021 Dynare Team +% Copyright © 2019-2024 Dynare Team % % This file is part of Dynare. % @@ -59,7 +59,9 @@ params(1+(1:pacmodel.max_lag)) = M_.params(pacmodel.ar.params); params(end) = M_.params(pacmodel.discount_index); [G, alpha, beta] = buildGmatrixWithAlphaAndBeta(params); M_.params(pacmodel.mce.alpha) = flip(alpha); -if isfield(pacmodel, 'growth_neutrality_param_index') + +if isfield(pacmodel, 'growth_neutrality_param_index') || ... + (isfield(pacmodel, 'components') && isfield(pacmodel.components, 'growth_neutrality_param_index') && any(~cellfun(@isempty, {pacmodel.components.growth_neutrality_param_index}))) if isfield(pacmodel, 'non_optimizing_behaviour') gamma = M_.params(pacmodel.share_of_optimizing_agents_index); else @@ -124,5 +126,14 @@ if isfield(pacmodel, 'growth_neutrality_param_index') cc = cc - tmp0/gamma; ll = ll - tmp1/gamma; % TODO: ll should be added as a constant in the PAC equation (under the λ part) when unrolling pac_expectation. end - M_.params(pacmodel.growth_neutrality_param_index) = cc; % Multiplies the variable or expression provided though the growth option in command pac_model. -end \ No newline at end of file + if isfield(pacmodel, 'growth_neutrality_param_index') + M_.params(pacmodel.growth_neutrality_param_index) = cc; % Multiplies the variable or expression provided though the growth option in command pac_model. + else + % TODO: We do not need one parameter per non stationary component, since they all have the same value. + for i=1:length(pacmodel.components) + if ~isempty(pacmodel.components(i).growth_neutrality_param_index) + M_.params(pacmodel.components(i).growth_neutrality_param_index) = cc; + end + end + end +end diff --git a/matlab/cherrypick.m b/matlab/cherrypick.m index 9a6efb46e82fb49aac39114622ede5d4ef424c1a..935b901e28e179900b53eab90bbeda31e3f23567 100644 --- a/matlab/cherrypick.m +++ b/matlab/cherrypick.m @@ -17,7 +17,7 @@ function json = cherrypick(infile, outfold, eqtags, noresids, json) % It is expected that the file infile.mod has already been run, and % that the associated JSON output is available. -% Copyright © 2019-2021 Dynare Team +% Copyright © 2019-2024 Dynare Team % % This file is part of Dynare. % @@ -188,17 +188,57 @@ try end else % MCE version of the PAC equation. - auxlhs = M_.endo_names{M_.pac.(ispac.name).mce.z1}; - [rhs, growthneutralitycorrection] = write_pac_mce_expectations(eqtags{i}, ispac.name, auxlhs); - if isempty(growthneutralitycorrection) - RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), auxlhs); + if ~isfield(M_.pac.(ispac.name), 'components') + auxlhs = M_.endo_names{M_.pac.(ispac.name).mce.z}; + [rhs, growthneutralitycorrection] = write_pac_mce_expectations(eqtags{i}, ispac.name, auxlhs); + if isempty(growthneutralitycorrection) + RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), auxlhs); + else + RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), sprintf('%s+%s', auxlhs, growthneutralitycorrection)); + end else - RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), sprintf('%s+%s', auxlhs, growthneutralitycorrection)); + n = length(M_.pac.(ispac.name).components); + auxlhs = cell(n, 1); + rhs = cell(n, 1); + growthneutralitycorrection = cell(n, 1); + for c=1:n + auxlhs{c} = M_.endo_names{M_.pac.(ispac.name).mce.z(c)}; + [rhs{c}, growthneutralitycorrection{c}] = write_pac_mce_expectations(eqtags{i}, ispac.name, auxlhs{c}, c); + end + if isempty(growthneutralitycorrection{1}) + if strcmp(M_.pac.(ispac.name).components(1).coeff_str, '1') + RHS__ = auxlhs{1}; + else + RHS__ = sprintf('%s*%s', M_.pac.(ispac.name).components(1).coeff_str, auxlhs{1}); + end + else + if strcmp(M_.pac.(ispac.name).components(1).coeff_str, '1') + RHS__ = sprintf('%s+%s', auxlhs{1}, growthneutralitycorrection{1}); + else + RHS__ = sprintf('%s*(%s+%s)', M_.pac.(ispac.name).components(1).coeff_str, auxlhs{1}, growthneutralitycorrection{1}); + end + end + for c=2:n + if isempty(growthneutralitycorrection{c}) + if strcmp(M_.pac.(ispac.name).components(c).coeff_str, '1') + RHS__ = sprintf('%s+%s', RHS__, auxlhs{c}); + else + RHS__ = sprintf('%s+%s*%s', RHS__, M_.pac.(ispac.name).components(c).coeff_str, auxlhs{c}); + end + else + if strcmp(M_.pac.(ispac.name).components(c).coeff_str, '1') + RHS__ = sprintf('%s+%s+%s', RHS__, auxlhs{c}, growthneutralitycorrection{c}); + else + RHS__ = sprintf('%s+%s*(%s+%s)', RHS__, M_.pac.(ispac.name).components(c).coeff_str, auxlhs{c}, growthneutralitycorrection{c}); + end + end + end + RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), RHS__); end end end if ~isempty(istar) - RHS = strrep(RHS, sprintf('pac_target_nonstationary(model_name = %s)', ispac.name), sprintf('%s(-1)', M_.endo_names{M_.pac.(ispac.name).ec.vars(M_.pac.(ispac.name).ec.istarget)})); + RHS = strrep(RHS, sprintf('pac_target_nonstationary(model_name = %s)', ispac.name), targetexpr()); end % Print equation for unrolled PAC/VAR-expectation and update % list of parameters and endogenous variables (if any). @@ -237,9 +277,23 @@ try end % Update pnames, enames and xnames if PAC with growth neutrality correction. if ~isempty(ispac) && ~isempty(growthneutralitycorrection) - [growthneutralitycorrection_pnames, ... - growthneutralitycorrection_enames, ... - growthneutralitycorrection_xnames] = get_variables_and_parameters_in_equation('', growthneutralitycorrection, M_); + if iscell(growthneutralitycorrection) + growthneutralitycorrection_pnames = []; + growthneutralitycorrection_enames = []; + growthneutralitycorrection_xnames = []; + for component=1:length(growthneutralitycorrection) + if ~isempty(growthneutralitycorrection{component}) + [tmp_pnames, tmp_enames, tmp_xnames] = get_variables_and_parameters_in_equation('', growthneutralitycorrection{component}, M_); + growthneutralitycorrection_pnames = union(growthneutralitycorrection_pnames, tmp_pnames); + growthneutralitycorrection_xnames = union(growthneutralitycorrection_xnames, tmp_xnames); + growthneutralitycorrection_enames = union(growthneutralitycorrection_enames, tmp_enames); + end + end + else + [growthneutralitycorrection_pnames, ... + growthneutralitycorrection_enames, ... + growthneutralitycorrection_xnames] = get_variables_and_parameters_in_equation('', growthneutralitycorrection, M_); + end if ~isempty(growthneutralitycorrection_pnames) pnames = union(pnames, growthneutralitycorrection_pnames); end @@ -321,6 +375,7 @@ if ~isempty(plist) fclose(fid); end + function printlistofvariables(fid, kind, list, DynareModel, vappend) if isfield(DynareModel, sprintf('%s_partitions', kind)) % Some endogenous variables are tagged. @@ -385,3 +440,62 @@ function printlistofvariables(fid, kind, list, DynareModel, vappend) end fprintf(fid, '%s;', vlist); end +end + +function expr = targetexpr() + if isfield(M_.pac.(ispac.name), 'components') + ns = ~strcmp({M_.pac.pacman.components.kind}, 'll'); % non stationary components + expr = ''; + for i=1:length(M_.pac.pacman.components) + if ns(i) + variable = rmauxiliary(M_.endo_names{M_.pac.(ispac.name).components(i).endo_var}, 1); + if isempty(expr) + if strcmp(M_.pac.(ispac.name).components(i).coeff_str, '1') + expr = variable; + else + expr = sprintf('%s*%s', M_.pac.(ispac.name).components(i).coeff_str, variable); + end + else + if strcmp(M_.pac.(ispac.name).components(i).coeff_str, '1') + expr = sprintf('%s+%s', expr, variable); + else + expr = sprintf('%s+%s*%s', expr, M_.pac.(ispac.name).components(i).coeff_str, variable); + end + end + end + end + else + expr = rmauxiliary(M_.endo_names{M_.pac.(ispac.name).ec.vars(M_.pac.(ispac.name).ec.istarget)}, 1); + end +end + + +function variable = rmauxiliary(variable, lag) + transformations = {}; + if isauxiliary(variable) + ida = get_aux_variable_id(variable); + op = 0; + while ida + op = op+1; + if isequal(M_.aux_vars(ida).type, 8) + transformations(op) = {'diff'}; + variable = M_.endo_names{M_.aux_vars(ida).orig_index}; + ida = get_aux_variable_id(variable); + elseif isequal(M_.aux_vars(ida).type, 10) + transformations(op) = {M_.aux_vars(ida).unary_op}; + variable = M_.endo_names{M_.aux_vars(ida).orig_index}; + ida = get_aux_variable_id(variable); + else + error('This case is not implemented.') + end + end + end + if nargin>1 + variable = sprintf('%s(-%u)', variable, lag); + end + for k=length(transformations):-1:1 + variable = sprintf('%s(%s)', transformations{k}, variable); + end +end + +end diff --git a/matlab/write_pac_mce_expectations.m b/matlab/write_pac_mce_expectations.m index 2ed0d5e48583c065ebc058c92a8e1c8d838c7f32..52ee8a6fd84856b414a13d1fa18bc775aec5e618 100644 --- a/matlab/write_pac_mce_expectations.m +++ b/matlab/write_pac_mce_expectations.m @@ -1,4 +1,4 @@ -function [expression, growthneutralitycorrection] = write_pac_mce_expectations(eqname, expectationmodelname, auxname) +function [expression, growthneutralitycorrection] = write_pac_mce_expectations(eqname, expectationmodelname, auxname, component) % Prints the expansion of the PAC_EXPECTATION term in files. % @@ -32,7 +32,14 @@ global M_ expectationmodel = M_.pac.(expectationmodelname); -targetid = expectationmodel.ec.vars((expectationmodel.ec.istarget==true)); +if nargin==3 && ischar(eqname) && ischar(expectationmodelname) && ischar(auxname) + targetid = expectationmodel.ec.vars((expectationmodel.ec.istarget==true)); +elseif nargin==4 && ischar(eqname) && ischar(expectationmodelname) && ischar(auxname) && isint(component) + targetid = expectationmodel.components(component).endo_var; +else + error('Unexpected number/types of input arguments') +end + alphaid = expectationmodel.mce.alpha; betaid = expectationmodel.discount_index; @@ -71,6 +78,12 @@ end % ᵐ ᵐ⁻¹ ᵐ⁻¹ % Zₜ = -∑ 𝛼ᵢ 𝛽ⁱ⁺¹ Zₜ₊ᵢ + A(1) [ 𝛥 yₜ − ∑ ∑ 𝛼ⱼ₊₁𝛽ʲ⁺¹𝛥 yₜ₊ₖ ] % ᵢ₌₁ ₖ₌₁ ⱼ₌ₖ +% +% The previous formula is for each non-stationary component of the target. For each stationary component we have instead: +% +% ᵐ +% Zₜ = -∑ 𝛼ᵢ 𝛽ⁱ⁺¹ Zₜ₊ᵢ + A(1)A(β) yₜ +% ᵢ₌₁ expression = ''; A1 = '1'; @@ -93,15 +106,44 @@ for i=1:length(alphaid) A1 = sprintf('%s+%s', A1, M_.param_names{alphaid(i)}); end +if nargin==4 + % Composite target. We need A(β) for the each stationary component. + AB = '1'; + for i=1:length(alphaid) + AB = sprintf('%s+%s*%s^%u', AB, M_.param_names{alphaid(i)}, M_.param_names{betaid}, i); + end +end + % Write % % ᵐ % -∑ 𝛼ᵢ 𝛽ⁱ⁺¹ Zₜ₊ᵢ + A(1) % ᵢ₌₁ +% +% or for a stationary component +% +% ᵐ +% -∑ 𝛼ᵢ 𝛽ⁱ⁺¹ Zₜ₊ᵢ + A(1)A(β)yₜ +% ᵢ₌₁ expression = sprintf('%s+(%s)', expression, A1); +if nargin==4 && strcmp(expectationmodel.components(component).kind, 'll') + if isempty(transformations) + expression = sprintf('%s*(%s)*%s', expression, AB, target); + else + variable = target; + for k=length(transformations):-1:1 + variable = sprintf('%s(%s)', transformations{k}, variable); + end + expression = sprintf('%s*(%s)*%s', expression, AB, variable); + end + growthneutralitycorrection = []; + % Nothing to do next for a stationary component. + return +end + % Write % % ᵐ @@ -145,11 +187,17 @@ end expression = sprintf('%s)', expression); % Add growth neutrality correction if required. -if isfield(expectationmodel, 'growth_neutrality_param_index') - if numel(expectationmodel.growth_linear_comb) == 1 - growthneutralitycorrection = sprintf('%s*%s', M_.param_names{expectationmodel.growth_neutrality_param_index}, expectationmodel.growth_str); +if nargin==3 + info = expectationmodel; +else + info = expectationmodel.components(component); +end + +if isfield(info, 'growth_neutrality_param_index') + if numel(info.growth_linear_comb) == 1 + growthneutralitycorrection = sprintf('%s*%s', M_.param_names{info.growth_neutrality_param_index}, info.growth_str); else - growthneutralitycorrection = sprintf('%s*(%s)', M_.param_names{expectationmodel.growth_neutrality_param_index}, expectationmodel.growth_str); + growthneutralitycorrection = sprintf('%s*(%s)', M_.param_names{info.growth_neutrality_param_index}, info.growth_str); end else growthneutralitycorrection = ''; diff --git a/preprocessor b/preprocessor index 8bfe3ef4bc8973589aa35d1a3cb265fb954748ee..92a85273004af68b2f16b40c69954b0315012d2a 160000 --- a/preprocessor +++ b/preprocessor @@ -1 +1 @@ -Subproject commit 8bfe3ef4bc8973589aa35d1a3cb265fb954748ee +Subproject commit 92a85273004af68b2f16b40c69954b0315012d2a