diff --git a/matlab/evaluate_planner_objective.m b/matlab/evaluate_planner_objective.m index c37764ab6c8033c0e4a25297f62893204125840f..65c1059b1c5296d91b2b62365a17b12526537847 100644 --- a/matlab/evaluate_planner_objective.m +++ b/matlab/evaluate_planner_objective.m @@ -198,7 +198,7 @@ if options_.ramsey_policy Wbar = U/(1-beta); Wy = Uy*gy/(eye(nspred)-beta*Gy); Wu = Uy*gu + beta*Wy*Gu; - + if isempty(options_.qz_criterium) options_.qz_criterium = 1+1e-6; end @@ -225,16 +225,43 @@ if options_.ramsey_policy planner_objective_value.conditional.steady_initial_multiplier = W_L_SS; planner_objective_value.conditional.zero_initial_multiplier = W_L_0; else - %Order k code will go here! - if ~isempty(M_.endo_histval) - fprintf('\nevaluate_planner_objective: order>2 conditional and unconditional welfare calculations not yet supported when an histval block is provided\n') - else - fprintf('\nevaluate_planner_objective: order>2 conditional welfare with initial Lagrange multipliers set to zero and unconditional welfare calculations not yet supported\n') - planner_objective_value.conditional.steady_initial_multiplier = k_order_welfare(dr, M_, options_); - planner_objective_value.conditional.zero_initial_multiplier = NaN; - planner_objective_value.unconditional = NaN; + % Computes the welfare decision rule + [W] = k_order_welfare(dr,M_,options_); + % Appends the welfare decision rule to the endogenous variables decision + % rule + g = dr; + for i=0:options_.order + eval("g.g_"+num2str(i)+" = [dr.g_"+num2str(i)+"; W.W_"+num2str(i)+"];"); end - return + % Amends the steady-state vector accordingly + [U] = feval([M_.fname '.objective.static'],ys,zeros(1,exo_nbr), M_.params); + ysteady = [ys(oo_.dr.order_var); U/(1-beta)]; + + % Generates the sequence of shocks to compute unconditional welfare + nper = 10000; + nburn = 1000; + chol_S = chol(M_.Sigma_e); + exo_simul = chol_S*randn(nper,M_.exo_nbr)'; + yhat_start = zeros(M_.endo_nbr+1,1); + [moment] = k_order_mean(options_.order, M_.nstatic, M_.npred, M_.nboth, M_.nfwrd+1, M_.exo_nbr, 1, nburn, yhat_start, exo_simul, ysteady, g); + + % Stores the result for unconditional welfare + planner_objective_value.unconditional = moment(end); + + % Conditional welfare + % Gets initial values + [yhat_L_SS,yhat_L_0, u] = get_initial_state(ys,M_,dr,oo_); + + % Conditional welfare (i) with Lagrange multipliers set to their + % steady-state values + yhat_start(M_.nstatic+1:M_.nstatic+M_.npred+M_.nboth) = yhat_L_SS; + [moment,sim] = k_order_mean(options_.order, M_.nstatic, M_.npred, M_.nboth, M_.nfwrd+1, M_.exo_nbr, 1, 0, yhat_start, u, ysteady, g); + planner_objective_value.conditional.steady_initial_multiplier = sim(end,1); + + % Conditional welfare (ii) with Lagrange multipliers set to 0 + yhat_start(M_.nstatic+1:M_.nstatic+M_.npred+M_.nboth) = yhat_L_0; + [moment,sim] = k_order_mean(options_.order, M_.nstatic, M_.npred, M_.nboth, M_.nfwrd+1, M_.exo_nbr, 1, nburn, yhat_start, u, ysteady, g); + planner_objective_value.conditional.zero_initial_multiplier = sim(end,1); end end elseif options_.discretionary_policy diff --git a/mex/build/k_order_mean.am b/mex/build/k_order_mean.am new file mode 100644 index 0000000000000000000000000000000000000000..5c38cd37c101f56d1cb927effd0247a010581662 --- /dev/null +++ b/mex/build/k_order_mean.am @@ -0,0 +1,14 @@ +mex_PROGRAMS = k_order_mean + +k_order_mean_FCFLAGS = $(AM_FCFLAGS) -I../libkordersim + +nodist_k_order_mean_SOURCES = \ + mexFunction.f08 + +k_order_mean_LDADD = ../libkordersim/libkordersim.a + +BUILT_SOURCES = $(nodist_k_order_mean_SOURCES) +CLEANFILES = $(nodist_k_order_mean_SOURCES) + +%.f08: $(top_srcdir)/../../sources/k_order_mean/%.f08 + $(LN_S) -f $< $@ diff --git a/mex/build/matlab/Makefile.am b/mex/build/matlab/Makefile.am index 9609b172393ab4acdb44e9b313c5408b0051aaca..7b565fb3a07b851ca55305ebc200cfc89da512a0 100644 --- a/mex/build/matlab/Makefile.am +++ b/mex/build/matlab/Makefile.am @@ -4,7 +4,7 @@ SUBDIRS = mjdgges kronecker bytecode block_kalman_filter sobol perfect_foresight # libdynare++ must come before gensylv, k_order_perturbation, dynare_simul_ if ENABLE_MEX_DYNAREPLUSPLUS -SUBDIRS += libdynare++ gensylv libkorder dynare_simul_ k_order_perturbation k_order_welfare local_state_space_iterations libkordersim folded_to_unfolded_dr local_state_space_iteration_fortran k_order_simul +SUBDIRS += libdynare++ gensylv libkorder dynare_simul_ k_order_perturbation k_order_welfare local_state_space_iterations libkordersim folded_to_unfolded_dr local_state_space_iteration_fortran k_order_simul k_order_mean endif if ENABLE_MEX_MS_SBVAR diff --git a/mex/build/matlab/configure.ac b/mex/build/matlab/configure.ac index 06182ea8bab8e3aade8f87472d9b6aea45f4776d..f377afc141dd5141ca1745b46deda65308f41b23 100644 --- a/mex/build/matlab/configure.ac +++ b/mex/build/matlab/configure.ac @@ -165,6 +165,7 @@ AC_CONFIG_FILES([Makefile folded_to_unfolded_dr/Makefile local_state_space_iteration_fortran/Makefile k_order_simul/Makefile + k_order_mean/Makefile perfect_foresight_problem/Makefile num_procs/Makefile block_trust_region/Makefile diff --git a/mex/build/matlab/k_order_mean/Makefile.am b/mex/build/matlab/k_order_mean/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..58684092cff79725863fb7f3c8381ee0091992dc --- /dev/null +++ b/mex/build/matlab/k_order_mean/Makefile.am @@ -0,0 +1,2 @@ +include ../mex.am +include ../../k_order_mean.am \ No newline at end of file diff --git a/mex/sources/Makefile.am b/mex/sources/Makefile.am index 214c1382fa1b94b6a28a2bec4b17d2128ad18df3..d4d924c07252022ae9905e4f8b392bcf175fe226 100644 --- a/mex/sources/Makefile.am +++ b/mex/sources/Makefile.am @@ -20,6 +20,7 @@ EXTRA_DIST = \ folded_to_unfolded_dr \ local_state_space_iteration_fortran \ k_order_simul \ + k_order_mean \ gensylv \ dynare_simul_ \ perfect_foresight_problem \ diff --git a/mex/sources/k_order_mean/mexFunction.f08 b/mex/sources/k_order_mean/mexFunction.f08 new file mode 100644 index 0000000000000000000000000000000000000000..d2ecee7a5fbed63a8c1a87d3cc8ec61f06ab64d1 --- /dev/null +++ b/mex/sources/k_order_mean/mexFunction.f08 @@ -0,0 +1,200 @@ +! Copyright © 2021 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/>. +! +! input: +! order the order of approximation, needs order+1 derivatives +! nstat +! npred +! nboth +! nforw +! nexog +! order_moment order of the moment we need to compute +! nburn number of burn-in periods +! yhat_start starting value for the full vector of endogenous variables minus its steady-state value +! shocks matrix of shocks (number of exogenous variables x number of periods) +! ysteady steady-state value for the full vector of endogenous variables +! dr structure containing the matrices for the decision rule (g_0, g_1,…) +! output: +! mean estimated `order_moment`-order moment for the full vector of e + +subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction') + use iso_fortran_env + use iso_c_binding + use struct + use matlab_mex + use partitions + use simulation + implicit none + + type(c_ptr), dimension(*), intent(in), target :: prhs + type(c_ptr), dimension(*), intent(out) :: plhs + integer(c_int), intent(in), value :: nlhs, nrhs + type(c_ptr) :: order_mx, nstatic_mx, npred_mx, nboth_mx, nfwrd_mx, nexog_mx, order_moment_mx, nburn_mx, & + yhat_start_mx, shocks_mx, ysteady_mx, dr_mx, tmp + type(pol), dimension(:), allocatable, target :: fdr, udr + integer :: order, nstatic, npred, nboth, nfwrd, exo_nbr, endo_nbr, nys, nvar, nper, nburn, order_moment + real(real64), dimension(:,:), allocatable :: shocks, sim + real(real64), dimension(:), allocatable :: dyu, mean + real(real64), dimension(:), pointer, contiguous :: ysteady, yhat_start + type(pascal_triangle) :: p + type(horner), dimension(:), allocatable :: h + integer :: i, t, d, m, n + character(kind=c_char, len=10) :: fieldname + + order_mx = prhs(1) + nstatic_mx = prhs(2) + npred_mx = prhs(3) + nboth_mx = prhs(4) + nfwrd_mx = prhs(5) + nexog_mx = prhs(6) + order_moment_mx = prhs(7) + nburn_mx = prhs(8) + yhat_start_mx = prhs(9) + shocks_mx = prhs(10) + ysteady_mx = prhs(11) + dr_mx = prhs(12) + + ! Checking the consistence and validity of input arguments + if (nrhs /= 12) then + call mexErrMsgTxt("Must have exactly 12 inputs") + end if + if (.not. (mxIsScalar(order_mx)) .and. mxIsNumeric(order_mx)) then + call mexErrMsgTxt("1st argument (order) should be a numeric scalar") + end if + if (.not. (mxIsScalar(nstatic_mx)) .and. mxIsNumeric(nstatic_mx)) then + call mexErrMsgTxt("2nd argument (nstat) should be a numeric scalar") + end if + if (.not. (mxIsScalar(npred_mx)) .and. mxIsNumeric(npred_mx)) then + call mexErrMsgTxt("3rd argument (npred) should be a numeric scalar") + end if + if (.not. (mxIsScalar(nboth_mx)) .and. mxIsNumeric(nboth_mx)) then + call mexErrMsgTxt("4th argument (nboth) should be a numeric scalar") + end if + if (.not. (mxIsScalar(nfwrd_mx)) .and. mxIsNumeric(nfwrd_mx)) then + call mexErrMsgTxt("5th argument (nforw) should be a numeric scalar") + end if + if (.not. (mxIsScalar(nexog_mx)) .and. mxIsNumeric(nexog_mx)) then + call mexErrMsgTxt("6th argument (nexog) should be a numeric scalar") + end if + if (.not. (mxIsScalar(order_moment_mx)) .and. mxIsNumeric(order_moment_mx)) then + call mexErrMsgTxt("7th argument (order_moment) should be a numeric scalar") + end if + if (.not. (mxIsScalar(nburn_mx)) .and. mxIsNumeric(nburn_mx)) then + call mexErrMsgTxt("8th argument (nburn) should be a numeric scalar") + end if + if (.not. (mxIsDouble(yhat_start_mx) .and. (mxGetM(yhat_start_mx) == 1 .or. mxGetN(yhat_start_mx) == 1))) then + call mexErrMsgTxt("9th argument (yhat_start) should be a real vector") + end if + if (.not. (mxIsDouble(shocks_mx))) then + call mexErrMsgTxt("10th argument (shocks) should be a real matrix") + end if + if (.not. (mxIsDouble(ysteady_mx) .and. (mxGetM(ysteady_mx) == 1 .or. mxGetN(ysteady_mx) == 1))) then + call mexErrMsgTxt("11th argument (ysteady) should be a real vector") + end if + if (.not. mxIsStruct(dr_mx)) then + call mexErrMsgTxt("12th argument (dr) should be a struct") + end if + + ! Converting inputs in Fortran format + order = int(mxGetScalar(order_mx)) + nstatic = int(mxGetScalar(nstatic_mx)) + npred = int(mxGetScalar(npred_mx)) + nboth = int(mxGetScalar(nboth_mx)) + nfwrd = int(mxGetScalar(nfwrd_mx)) + exo_nbr = int(mxGetScalar(nexog_mx)) + endo_nbr = nstatic+npred+nboth+nfwrd + nys = npred+nboth + nvar = nys+exo_nbr + nburn = int(mxGetScalar(nburn_mx)) + order_moment = int(mxGetScalar(order_moment_mx)) + + if (endo_nbr /= int(mxGetM(yhat_start_mx))) then + call mexErrMsgTxt("yhat_start should have nstat+npred+nboth+nforw rows") + end if + yhat_start => mxGetPr(yhat_start_mx) + + if (exo_nbr /= int(mxGetM(shocks_mx))) then + call mexErrMsgTxt("shocks should have nexog rows") + end if + nper = int(mxGetN(shocks_mx)) + allocate(shocks(exo_nbr,nper)) + shocks = reshape(mxGetPr(shocks_mx),[exo_nbr,nper]) + + if (.not. (int(mxGetM(ysteady_mx)) == endo_nbr)) then + call mexErrMsgTxt("ysteady should have nstat+npred+nboth+nforw rows") + end if + ysteady => mxGetPr(ysteady_mx) + + allocate(h(0:order), fdr(0:order), udr(0:order)) + do i = 0, order + write (fieldname, '(a2, i1)') "g_", i + tmp = mxGetField(dr_mx, 1_mwIndex, trim(fieldname)) + if (.not. (c_associated(tmp) .and. mxIsDouble(tmp))) then + call mexErrMsgTxt(trim(fieldname)//" is not allocated in dr") + end if + m = int(mxGetM(tmp)) + n = int(mxGetN(tmp)) + allocate(fdr(i)%g(m,n), udr(i)%g(endo_nbr, nvar**i), h(i)%c(endo_nbr, nvar**i)) + fdr(i)%g(1:m,1:n) = reshape(mxGetPr(tmp), [m,n]) + end do + + udr(0)%g = fdr(0)%g + udr(1)%g = fdr(1)%g + if (order > 1) then + ! Compute the useful binomial coefficients from Pascal's triangle + p = pascal_triangle(nvar+order-1) + block + type(uf_matching), dimension(2:order) :: matching + ! Pinpointing the corresponding offsets between folded and unfolded tensors + do d=2,order + allocate(matching(d)%folded(nvar**d)) + call fill_folded_indices(matching(d)%folded, nvar, d, p) + udr(d)%g = fdr(d)%g(:,matching(d)%folded) + end do + end block + end if + + allocate(dyu(nvar), mean(endo_nbr), sim(endo_nbr,nper)) + ! Getting the predetermined part of the endogenous variable vector + dyu(1:nys) = yhat_start(nstatic+1:nstatic+nys) + dyu(nys+1:) = shocks(:,1) + ! Using the Horner algorithm to evaluate the decision rule at the chosen dyu + call eval(h, dyu, udr, endo_nbr, nvar, order) + sim(:,1) = h(0)%c(:,1) + ysteady + mean = 0. + + ! Carrying out the simulation + do t=2,nper + dyu(1:nys) = h(0)%c(nstatic+1:nstatic+nys,1) + dyu(nys+1:) = shocks(:,t) + call eval(h, dyu, udr, endo_nbr, nvar, order) + sim(:,t) = h(0)%c(:,1) + ysteady + if (t > nburn) then + mean = mean + sim(:,t)**order_moment + end if + end do + ! scaling the mean with the number of non-burn-in periods + mean = mean/(nper-nburn) + + ! Generating output + plhs(1) = mxCreateDoubleMatrix(int(endo_nbr, mwSize), 1_mwSize, mxREAL) + mxGetPr(plhs(1)) = mean + plhs(2) = mxCreateDoubleMatrix(int(endo_nbr, mwSize), int(nper, mwSize), mxREAL) + mxGetPr(plhs(2)) = reshape(sim, [size(sim)]) + + +end subroutine mexFunction diff --git a/mex/sources/k_order_welfare/approximation_welfare.cc b/mex/sources/k_order_welfare/approximation_welfare.cc index 5e3b527f9c6fd6c8e65df24e847448e026b6490c..ccd82854cf1bfc39b34fcf7aaf6782eaec71d8b3 100644 --- a/mex/sources/k_order_welfare/approximation_welfare.cc +++ b/mex/sources/k_order_welfare/approximation_welfare.cc @@ -24,8 +24,7 @@ #include "approximation_welfare.hh" ApproximationWelfare::ApproximationWelfare(KordwDynare &w, double discount_factor_arg, const FGSContainer &rule_ders_arg, const FGSContainer &rule_ders_s_arg, Journal &j) - : welfare{w}, discount_factor(discount_factor_arg), cond(1), - nvs{welfare.getModel().nys(), welfare.getModel().nexog(), welfare.getModel().nexog(), 1}, journal{j} + : welfare{w}, discount_factor(discount_factor_arg), nvs{welfare.getModel().nys(), welfare.getModel().nexog(), welfare.getModel().nexog(), 1}, journal{j} { rule_ders = std::make_unique<FGSContainer>(rule_ders_arg); rule_ders_s = std::make_unique<FGSContainer>(rule_ders_s_arg); @@ -42,23 +41,12 @@ ApproximationWelfare::approxAtSteady() KOrderWelfare korderwel(welfare.getModel().nstat(), welfare.getModel().npred(), welfare.getModel().nboth(), welfare.getModel().nforw(), welfare.getModel().nexog(), welfare.getModel().order(), discount_factor, welfare.getPlannerObjDerivatives(), get_rule_ders(), get_rule_ders_s(), welfare.getModel().getVcov(), journal); for (int k = 1; k <= welfare.getModel().order(); k++) korderwel.performStep<Storage::fold>(k); - saveRuleDerivs(korderwel.getFoldU(), korderwel.getFoldW()); - // construct the welfare approximations - calcStochShift(); //conditional welfare + saveRuleDerivs(korderwel.getFoldW()); - // construct the resulting decision rules - unc_fdr = std::make_unique<FoldDecisionRule>(*unc_ders, welfare.getModel().nys(), welfare.getModel().nexog(), welfare.getModel().getSteady()); + // construct the resulting decision rule cond_fdr = std::make_unique<FoldDecisionRule>(*cond_ders, welfare.getModel().nys(), welfare.getModel().nexog(), welfare.getModel().getSteady()); } -/* This just returns ‘fdr’ with a check that it is created. */ -const FoldDecisionRule & -ApproximationWelfare::getFoldUncWel() const -{ - KORD_RAISE_IF(!unc_fdr, - "Folded decision rule has not been created in ApproximationWelfare::getFoldUncWel"); - return *unc_fdr; -} const FoldDecisionRule & ApproximationWelfare::getFoldCondWel() const { @@ -68,29 +56,7 @@ ApproximationWelfare::getFoldCondWel() const } void -ApproximationWelfare::saveRuleDerivs(const FGSContainer &U, const FGSContainer &W) +ApproximationWelfare::saveRuleDerivs(const FGSContainer &W) { - unc_ders = std::make_unique<FGSContainer>(U); cond_ders = std::make_unique<FGSContainer>(W); -} - -/* This method calculates the shift of the conditional welfare function w.r.t its steady-state value because of the presence of stochastic shocks, i.e. - 1 -W ≈ Wbar + ∑ ── W_σᵈ - d=1 d! -*/ -void -ApproximationWelfare::calcStochShift() -{ - cond.zeros(); - cond.add(1.0/(1.0-discount_factor), welfare.getResid()); - KORD_RAISE_IF(cond.length() != 1, - "Wrong length of output vector for ApproximationWelfare::calcStochShift"); - int dfac = 1; - for (int d = 1; d <= cond_ders->getMaxDim(); d++, dfac *= d) - if (KOrderWelfare::is_even(d)) - { - Symmetry sym{0, 0, 0, d}; - cond.add(1.0/dfac, cond_ders->get(sym).getData()); - } -} +} \ No newline at end of file diff --git a/mex/sources/k_order_welfare/approximation_welfare.hh b/mex/sources/k_order_welfare/approximation_welfare.hh index c2d2d166f9e8c8d67933fac868772a367ed5a62b..9c22eae259edc15b4350fb4afcd5ad54543111f2 100644 --- a/mex/sources/k_order_welfare/approximation_welfare.hh +++ b/mex/sources/k_order_welfare/approximation_welfare.hh @@ -31,14 +31,9 @@ class ApproximationWelfare double discount_factor; std::unique_ptr<FGSContainer> rule_ders; std::unique_ptr<FGSContainer> rule_ders_s; - std::unique_ptr<FGSContainer> unc_ders; std::unique_ptr<FGSContainer> cond_ders; - std::unique_ptr<FoldDecisionRule> unc_fdr; std::unique_ptr<FoldDecisionRule> cond_fdr; - Vector cond; - // const FNormalMoments mom; IntSequence nvs; - // TwoDMatrix ss; Journal &journal; public: ApproximationWelfare(KordwDynare &w, double discount_factor, const FGSContainer &rule_ders, const FGSContainer &rule_ders_s, Journal &j); @@ -59,30 +54,16 @@ public: return *rule_ders_s; } const FGSContainer & - get_unc_ders() const - { - return *unc_ders; - } - const FGSContainer & get_cond_ders() const { return *cond_ders; } - const Vector & - getCond() const - { - return cond; - } - const FoldDecisionRule & getFoldUncWel() const; - const FoldDecisionRule & getUnfoldUncWel() const; const FoldDecisionRule & getFoldCondWel() const; - const FoldDecisionRule & getUnfoldCondWel() const; void approxAtSteady(); protected: - void saveRuleDerivs(const FGSContainer &U, const FGSContainer &W); - void calcStochShift(); + void saveRuleDerivs(const FGSContainer &W); }; #endif diff --git a/mex/sources/k_order_welfare/k_order_welfare.cc b/mex/sources/k_order_welfare/k_order_welfare.cc index 266d133383553a75bbe70e1bd095e3de4acc07f7..53501411eccfe0fea199cc4207d72462d77a72cd 100644 --- a/mex/sources/k_order_welfare/k_order_welfare.cc +++ b/mex/sources/k_order_welfare/k_order_welfare.cc @@ -59,7 +59,6 @@ DynareMxArrayToString(const mxArray *mxFldp) ) */ -std::vector<std::string> U_fieldnames; std::vector<std::string> W_fieldnames; void @@ -278,113 +277,25 @@ extern "C" { ApproximationWelfare appwel(welfare, discount_factor, app.get_rule_ders(), app.get_rule_ders_s(), journal); appwel.approxAtSteady(); - // Conditional welfare approximation at non-stochastic steady state when stochastic shocks are enabled - const Vector &cond_approx = appwel.getCond(); - plhs[0] = mxCreateDoubleMatrix(cond_approx.length(), 1, mxREAL); - std::copy_n(cond_approx.base(), cond_approx.length(), mxGetPr(plhs[0])); - - if (nlhs > 1) - { - const FoldDecisionRule &unc_fdr = appwel.getFoldUncWel(); - // Add possibly missing field names - for (int i = static_cast<int>(U_fieldnames.size()); i <= kOrder; i++) - U_fieldnames.emplace_back("U_" + std::to_string(i)); - // Create structure for storing derivatives in Dynare++ format - const char *U_fieldnames_c[kOrder+1]; - for (int i = 0; i <= kOrder; i++) - U_fieldnames_c[i] = U_fieldnames[i].c_str(); - plhs[1] = mxCreateStructMatrix(1, 1, kOrder+1, U_fieldnames_c); - - // Fill that structure - for (int i = 0; i <= kOrder; i++) - { - const FFSTensor &t = unc_fdr.get(Symmetry{i}); - mxArray *tmp = mxCreateDoubleMatrix(t.nrows(), t.ncols(), mxREAL); - const ConstVector &vec = t.getData(); - assert(vec.skip() == 1); - std::copy_n(vec.base(), vec.length(), mxGetPr(tmp)); - mxSetField(plhs[1], 0, ("U_" + std::to_string(i)).c_str(), tmp); - } - - if (nlhs > 2) - { - const FoldDecisionRule &cond_fdr = appwel.getFoldCondWel(); - // Add possibly missing field names - for (int i = static_cast<int>(W_fieldnames.size()); i <= kOrder; i++) - W_fieldnames.emplace_back("W_" + std::to_string(i)); - // Create structure for storing derivatives in Dynare++ format - const char *W_fieldnames_c[kOrder+1]; - for (int i = 0; i <= kOrder; i++) - W_fieldnames_c[i] = W_fieldnames[i].c_str(); - plhs[2] = mxCreateStructMatrix(1, 1, kOrder+1, W_fieldnames_c); - - // Fill that structure - for (int i = 0; i <= kOrder; i++) - { - const FFSTensor &t = cond_fdr.get(Symmetry{i}); - mxArray *tmp = mxCreateDoubleMatrix(t.nrows(), t.ncols(), mxREAL); - const ConstVector &vec = t.getData(); - assert(vec.skip() == 1); - std::copy_n(vec.base(), vec.length(), mxGetPr(tmp)); - mxSetField(plhs[2], 0, ("W_" + std::to_string(i)).c_str(), tmp); - } - if (nlhs > 3) - { - - const FGSContainer &U = appwel.get_unc_ders(); - - size_t nfields = (kOrder == 1 ? 2 : (kOrder == 2 ? 6 : 12)); - const char *c_fieldnames[] = { "Uy", "Uu", "Uyy", "Uyu", "Uuu", "Uss", "Uyyy", "Uyyu", "Uyuu", "Uuuu", "Uyss", "Uuss" }; - plhs[3] = mxCreateStructMatrix(1, 1, nfields, c_fieldnames); - - copy_derivatives(plhs[3], Symmetry{1, 0, 0, 0}, U, "Uy"); - copy_derivatives(plhs[3], Symmetry{0, 1, 0, 0}, U, "Uu"); - if (kOrder >= 2) - { - copy_derivatives(plhs[3], Symmetry{2, 0, 0, 0}, U, "Uyy"); - copy_derivatives(plhs[3], Symmetry{0, 2, 0, 0}, U, "Uuu"); - copy_derivatives(plhs[3], Symmetry{1, 1, 0, 0}, U, "Uyu"); - copy_derivatives(plhs[3], Symmetry{0, 0, 0, 2}, U, "Uss"); - } - if (kOrder >= 3) - { - copy_derivatives(plhs[3], Symmetry{3, 0, 0, 0}, U, "Uyyy"); - copy_derivatives(plhs[3], Symmetry{0, 3, 0, 0}, U, "Uuuu"); - copy_derivatives(plhs[3], Symmetry{2, 1, 0, 0}, U, "Uyyu"); - copy_derivatives(plhs[3], Symmetry{1, 2, 0, 0}, U, "Uyuu"); - copy_derivatives(plhs[3], Symmetry{1, 0, 0, 2}, U, "Uyss"); - copy_derivatives(plhs[3], Symmetry{0, 1, 0, 2}, U, "Uuss"); - } - - if (nlhs > 4) - { - const FGSContainer &W = appwel.get_cond_ders(); - - size_t nfields = (kOrder == 1 ? 2 : (kOrder == 2 ? 6 : 12)); - const char *c_fieldnames[] = { "Wy", "Wu", "Wyy", "Wyu", "Wuu", "Wss", "Wyyy", "Wyyu", "Wyuu", "Wuuu", "Wyss", "Wuss" }; - plhs[4] = mxCreateStructMatrix(1, 1, nfields, c_fieldnames); - - copy_derivatives(plhs[4], Symmetry{1, 0, 0, 0}, W, "Wy"); - copy_derivatives(plhs[4], Symmetry{0, 1, 0, 0}, W, "Wu"); - if (kOrder >= 2) - { - copy_derivatives(plhs[4], Symmetry{2, 0, 0, 0}, W, "Wyy"); - copy_derivatives(plhs[4], Symmetry{0, 2, 0, 0}, W, "Wuu"); - copy_derivatives(plhs[4], Symmetry{1, 1, 0, 0}, W, "Wyu"); - copy_derivatives(plhs[4], Symmetry{0, 0, 0, 2}, W, "Wss"); - } - if (kOrder >= 3) - { - copy_derivatives(plhs[4], Symmetry{3, 0, 0, 0}, W, "Wyyy"); - copy_derivatives(plhs[4], Symmetry{0, 3, 0, 0}, W, "Wuuu"); - copy_derivatives(plhs[4], Symmetry{2, 1, 0, 0}, W, "Wyyu"); - copy_derivatives(plhs[4], Symmetry{1, 2, 0, 0}, W, "Wyuu"); - copy_derivatives(plhs[4], Symmetry{1, 0, 0, 2}, W, "Wyss"); - copy_derivatives(plhs[4], Symmetry{0, 1, 0, 2}, W, "Wuss"); - } - } - } - } - } + const FoldDecisionRule &cond_fdr = appwel.getFoldCondWel(); + // Add possibly missing field names + for (int i = static_cast<int>(W_fieldnames.size()); i <= kOrder; i++) + W_fieldnames.emplace_back("W_" + std::to_string(i)); + // Create structure for storing derivatives in Dynare++ format + const char *W_fieldnames_c[kOrder+1]; + for (int i = 0; i <= kOrder; i++) + W_fieldnames_c[i] = W_fieldnames[i].c_str(); + plhs[0] = mxCreateStructMatrix(1, 1, kOrder+1, W_fieldnames_c); + + // Fill that structure + for (int i = 0; i <= kOrder; i++) + { + const FFSTensor &t = cond_fdr.get(Symmetry{i}); + mxArray *tmp = mxCreateDoubleMatrix(t.nrows(), t.ncols(), mxREAL); + const ConstVector &vec = t.getData(); + assert(vec.skip() == 1); + std::copy_n(vec.base(), vec.length(), mxGetPr(tmp)); + mxSetField(plhs[0], 0, ("W_" + std::to_string(i)).c_str(), tmp); + } } // end of mexFunction() } // end of extern C diff --git a/mex/sources/local_state_space_iteration_fortran/mexFunction.f08 b/mex/sources/local_state_space_iteration_fortran/mexFunction.f08 index ae3662aa2094192d3d979eff579ca1f6fa6929f6..9d4d32af33f104ef7b5d3a7760bd00383889c598 100644 --- a/mex/sources/local_state_space_iteration_fortran/mexFunction.f08 +++ b/mex/sources/local_state_space_iteration_fortran/mexFunction.f08 @@ -17,7 +17,7 @@ ! input: ! yhat values of endogenous variables -! epsilon values of the exgogenous shock +! epsilon values of the exogenous shock ! dr struct containing the folded tensors g_0, g_1, ... ! M struct containing the model features ! options struct containing the model options diff --git a/tests/optimal_policy/neo_growth_ramsey_k_order.mod b/tests/optimal_policy/neo_growth_ramsey_k_order.mod index 8e62a43992043180633e059aa9c30c4d2a6c2bf4..e11ff0f519361f200592095a1fca3f5e4eb6abc8 100644 --- a/tests/optimal_policy/neo_growth_ramsey_k_order.mod +++ b/tests/optimal_policy/neo_growth_ramsey_k_order.mod @@ -33,11 +33,8 @@ stoch_simul(order=6, irf=0); evaluate_planner_objective; -[condWelfare, U_dynpp, W_dynpp, U_dyn, W_dyn] = k_order_welfare(oo_.dr, M_, options_); +[W_dynpp] = k_order_welfare(oo_.dr, M_, options_); -if condWelfare~=oo_.planner_objective_value.conditional.steady_initial_multiplier - error('Inaccurate conditional welfare with Lagrange multiplier set to its steady-state value'); -end if ~exist(['neo_growth_k_order' filesep 'Output' filesep 'neo_growth_k_order_results.mat'],'file'); error('neo_growth_k_order must be run first'); end; @@ -46,20 +43,16 @@ oo = load(['neo_growth_k_order' filesep 'Output' filesep 'neo_growth_k_order_res M = load(['neo_growth_k_order' filesep 'Output' filesep 'neo_growth_k_order_results'],'M_'); options = load(['neo_growth_k_order' filesep 'Output' filesep 'neo_growth_k_order_results'],'options_'); -ind_U = strmatch('U', M.M_.endo_names,'exact'); ind_W = strmatch('W', M.M_.endo_names,'exact'); err = -1e6; for i = 1:options_.order - field_U = strcat('U_', num2str(i)); field_W = strcat('W_', num2str(i)); g_i = eval(strcat('oo.oo_.dr.g_', num2str(i))); - tmp_err = max(U_dynpp.(field_U) - g_i(ind_U, :)); - err = max(err, tmp_err); tmp_err = max(W_dynpp.(field_W) - g_i(ind_W, :)); err = max(err, tmp_err); end if err > 1e-10; - error('Inaccurate assessment of the derivatives of the felicity and the welfare functions'); + error('Inaccurate assessment of the derivatives of the welfare function'); end;