2021-01-22 19:53:57 +01:00
function [fval, info, exit_flag, df, junk1, oo_, M_, options_mom_] = method_of_moments_objective_function ( xparam1, Bounds, oo_, estim_params_, M_, options_mom_)
% [fval, info, exit_flag, df, junk1, oo_, M_, options_mom_] = method_of_moments_objective_function(xparam1, Bounds, oo_, estim_params_, M_, options_mom_)
2020-06-29 07:40:34 +02:00
% -------------------------------------------------------------------------
% This function evaluates the objective function for GMM/SMM estimation
% =========================================================================
% INPUTS
% o xparam1: current value of estimated parameters as returned by set_prior()
% o Bounds: structure containing parameter bounds
% o oo_: structure for results
% o estim_params_: structure describing the estimated_parameters
% o M_ structure describing the model
% o options_mom_: structure information about all settings (specified by the user, preprocessor, and taken from global options_)
% -------------------------------------------------------------------------
% OUTPUTS
% o fval: value of the quadratic form of the moment difference (except for lsqnonlin, where this is done implicitly)
% o info: vector storing error code and penalty
2020-07-10 21:42:18 +02:00
% o exit_flag: 0 if error, 1 if no error
2021-01-22 19:53:57 +01:00
% o df: analytical parameter Jacobian of the quadratic form of the moment difference (for GMM only)
% o junk1: empty matrix required for optimizer interface (Hessian would go here)
2020-06-29 07:40:34 +02:00
% o oo_: structure containing the results with the following updated fields:
% - mom.model_moments [numMom x 1] vector with model moments
2020-07-10 21:42:18 +02:00
% - mom.Q value of the quadratic form of the moment difference
2020-06-29 07:40:34 +02:00
% o M_: Matlab's structure describing the model
2021-01-14 10:03:39 +01:00
% o options_mom_: structure information about all settings (specified by the user, preprocessor, and taken from global options_)
2020-06-29 07:40:34 +02:00
% -------------------------------------------------------------------------
% This function is called by
% o method_of_moments.m
2021-01-14 10:03:39 +01:00
% o dynare_minimize_objective.m
2020-06-29 07:40:34 +02:00
% -------------------------------------------------------------------------
% This function calls
% o check_bounds_and_definiteness_estimation
% o pruned_state_space_system
% o resol
% o set_all_parameters
% =========================================================================
2021-01-07 10:32:35 +01:00
% Copyright (C) 2020-2021 Dynare Team
2020-06-29 07:40:34 +02:00
%
% 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 <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------
% Author(s):
% o Willi Mutschler (willi@mutschler.eu)
% o Johannes Pfeifer (jpfeifer@uni-koeln.de)
% =========================================================================
%------------------------------------------------------------------------------
% 0. Initialization of the returned variables and others...
%------------------------------------------------------------------------------
2021-01-22 19:53:57 +01:00
if options_mom_ . mom . compute_derivs && options_mom_ . mom . analytic_jacobian
if options_mom_ . vector_output == 1
if options_mom_ . mom . penalized_estimator
df = nan ( size ( oo_ . mom . data_moments , 1 ) + length ( xparam1 ) , length ( xparam1 ) ) ;
else
df = nan ( size ( oo_ . mom . data_moments , 1 ) , length ( xparam1 ) ) ;
end
2021-01-14 10:03:39 +01:00
else
2021-01-22 19:53:57 +01:00
df = nan ( 1 , length ( xparam1 ) ) ;
2021-01-14 10:03:39 +01:00
end
else
2021-01-22 19:53:57 +01:00
df = [ ] ; %required to be empty by e.g. newrat
2021-01-14 10:03:39 +01:00
end
2020-06-29 07:40:34 +02:00
junk1 = [ ] ;
junk2 = [ ] ;
%--------------------------------------------------------------------------
% 1. Get the structural parameters & define penalties
%--------------------------------------------------------------------------
2021-01-10 17:30:35 +01:00
% Ensure that xparam1 is a column vector; particleswarm.m requires this.
xparam1 = xparam1 ( : ) ;
2020-07-17 13:18:39 +02:00
M_ = set_all_parameters ( xparam1 , estim_params_ , M_ ) ;
[ fval , info , exit_flag ] = check_bounds_and_definiteness_estimation ( xparam1 , M_ , estim_params_ , Bounds ) ;
2020-06-29 07:40:34 +02:00
if info ( 1 )
if options_mom_ . vector_output == 1 % lsqnonlin requires vector output
fval = ones ( size ( oo_ . mom . data_moments , 1 ) , 1 ) * options_mom_ . huge_number ;
end
return
end
%--------------------------------------------------------------------------
% 2. call resol to compute steady state and model solution
%--------------------------------------------------------------------------
% Compute linear approximation around the deterministic steady state
[ dr , info , M_ , options_mom_ , oo_ ] = resol ( 0 , M_ , options_mom_ , oo_ ) ;
% Return, with endogenous penalty when possible, if resol issues an error code
if info ( 1 )
if info ( 1 ) == 3 || info ( 1 ) == 4 || info ( 1 ) == 5 || info ( 1 ) == 6 || info ( 1 ) == 19 || ...
info ( 1 ) == 20 || info ( 1 ) == 21 || info ( 1 ) == 23 || info ( 1 ) == 26 || ...
info ( 1 ) == 81 || info ( 1 ) == 84 || info ( 1 ) == 85 || info ( 1 ) == 86
%meaningful second entry of output that can be used
fval = Inf ;
info ( 4 ) = info ( 2 ) ;
exit_flag = 0 ;
if options_mom_ . vector_output == 1 % lsqnonlin requires vector output
fval = ones ( size ( oo_ . mom . data_moments , 1 ) , 1 ) * options_mom_ . huge_number ;
end
return
else
fval = Inf ;
info ( 4 ) = 0.1 ;
exit_flag = 0 ;
if options_mom_ . vector_output == 1 % lsqnonlin requires vector output
fval = ones ( size ( oo_ . mom . data_moments , 1 ) , 1 ) * options_mom_ . huge_number ;
end
return
end
end
if strcmp ( options_mom_ . mom . mom_method , ' GMM' )
%--------------------------------------------------------------------------
% 3. Set up pruned state-space system and compute model moments
%--------------------------------------------------------------------------
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
indpmodel = [ ] ; %initialize index for model parameters
if ~ isempty ( estim_params_ . param_vals )
indpmodel = estim_params_ . param_vals ( : , 1 ) ; %values correspond to parameters declaration order, row number corresponds to order in estimated_params
end
indpstderr = [ ] ; %initialize index for stderr parameters
if ~ isempty ( estim_params_ . var_exo )
indpstderr = estim_params_ . var_exo ( : , 1 ) ; %values correspond to varexo declaration order, row number corresponds to order in estimated_params
end
indpcorr = [ ] ; %initialize matrix for corr paramters
if ~ isempty ( estim_params_ . corrx )
indpcorr = estim_params_ . corrx ( : , 1 : 2 ) ; %values correspond to varexo declaration order, row number corresponds to order in estimated_params
end
if estim_params_ . nvn || estim_params_ . ncn %nvn is number of stderr parameters and ncn is number of corr parameters of measurement innovations as declared in estimated_params
error ( ' Analytic computation of standard errrors does not (yet) support measurement errors.\nInstead, define them explicitly as varexo and provide measurement equations in the model definition.\nAlternatively, use numerical standard errors.' )
end
modparam_nbr = estim_params_ . np ; % number of model parameters as declared in estimated_params
stderrparam_nbr = estim_params_ . nvx ; % number of stderr parameters
corrparam_nbr = estim_params_ . ncx ; % number of corr parameters
totparam_nbr = stderrparam_nbr + corrparam_nbr + modparam_nbr ;
dr . derivs = get_perturbation_params_derivs ( M_ , options_mom_ , estim_params_ , oo_ , indpmodel , indpstderr , indpcorr , 0 ) ; %analytic derivatives of perturbation matrices
oo_ . mom . model_moments_params_derivs = NaN ( options_mom_ . mom . mom_nbr , totparam_nbr ) ;
pruned_state_space = pruned_state_space_system ( M_ , options_mom_ , dr , oo_ . dr . obs_var , options_mom_ . ar , 0 , 1 ) ;
else
pruned_state_space = pruned_state_space_system ( M_ , options_mom_ , dr , oo_ . dr . obs_var , options_mom_ . ar , 0 , 0 ) ;
end
2020-06-29 07:40:34 +02:00
2020-07-10 22:32:39 +02:00
oo_ . mom . model_moments = NaN ( options_mom_ . mom . mom_nbr , 1 ) ;
2020-06-29 07:40:34 +02:00
offset = 0 ;
% First moments
2020-07-10 22:32:39 +02:00
if ~ options_mom_ . prefilter && isfield ( options_mom_ . mom . index , ' E_y' ) && nnz ( options_mom_ . mom . index . E_y ) > 0
2020-06-29 07:40:34 +02:00
E_y = pruned_state_space . E_y ;
2020-07-10 22:32:39 +02:00
E_y_nbr = nnz ( options_mom_ . mom . index . E_y ) ;
oo_ . mom . model_moments ( offset + 1 : E_y_nbr , 1 ) = E_y ( options_mom_ . mom . index . E_y ) ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
oo_ . mom . model_moments_params_derivs ( offset + 1 : E_y_nbr , : ) = pruned_state_space . dE_y ( options_mom_ . mom . index . E_y , : ) ;
end
2020-06-29 07:40:34 +02:00
offset = offset + E_y_nbr ;
end
% Second moments
% Contemporaneous covariance
2020-07-10 22:32:39 +02:00
if isfield ( options_mom_ . mom . index , ' E_yy' ) && nnz ( options_mom_ . mom . index . E_yy ) > 0
2020-06-29 07:40:34 +02:00
if options_mom_ . prefilter
E_yy = pruned_state_space . Var_y ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
dE_yy = pruned_state_space . dVar_y ;
end
2020-06-29 07:40:34 +02:00
else
E_yy = pruned_state_space . Var_y + pruned_state_space . E_y * pruned_state_space . E_y ' ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
dE_yy = pruned_state_space . dVar_y ;
for jp = 1 : totparam_nbr
dE_yy ( : , : , jp ) = dE_yy ( : , : , jp ) + pruned_state_space . dE_y ( : , jp ) * pruned_state_space . E_y ' + pruned_state_space . E_y * pruned_state_space . dE_y ( : , jp ) ' ;
end
end
2020-06-29 07:40:34 +02:00
end
2020-07-10 22:32:39 +02:00
E_yy_nbr = nnz ( tril ( options_mom_ . mom . index . E_yy ) ) ;
oo_ . mom . model_moments ( offset + ( 1 : E_yy_nbr ) , 1 ) = E_yy ( tril ( options_mom_ . mom . index . E_yy ) ) ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
oo_ . mom . model_moments_params_derivs ( offset + ( 1 : E_yy_nbr ) , : ) = reshape ( dE_yy ( repmat ( tril ( options_mom_ . mom . index . E_yy ) , [ 1 1 totparam_nbr ] ) ) , E_yy_nbr , totparam_nbr ) ;
end
2020-06-29 07:40:34 +02:00
offset = offset + E_yy_nbr ;
end
% Lead/lags covariance
2020-07-10 22:32:39 +02:00
if isfield ( options_mom_ . mom . index , ' E_yyt' ) && nnz ( options_mom_ . mom . index . E_yyt ) > 0
2020-06-29 07:40:34 +02:00
if options_mom_ . prefilter
E_yyt = pruned_state_space . Var_yi ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
dE_yyt = pruned_state_space . dVar_yi ;
end
2020-06-29 07:40:34 +02:00
else
E_yyt = pruned_state_space . Var_yi + repmat ( pruned_state_space . E_y * pruned_state_space . E_y ' , [ 1 1 size ( pruned_state_space . Var_yi , 3 ) ] ) ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
dE_yyt = pruned_state_space . dVar_yi ;
for jp = 1 : totparam_nbr
dE_yyt ( : , : , : , jp ) = dE_yyt ( : , : , : , jp ) + repmat ( pruned_state_space . dE_y ( : , jp ) * pruned_state_space . E_y ' , [ 1 1 size ( pruned_state_space . Var_yi , 3 ) ] ) ...
+ repmat ( pruned_state_space . E_y * pruned_state_space . dE_y ( : , jp ) ' , [ 1 1 size ( pruned_state_space . Var_yi , 3 ) ] ) ;
end
end
2020-06-29 07:40:34 +02:00
end
2020-07-10 22:32:39 +02:00
E_yyt_nbr = nnz ( options_mom_ . mom . index . E_yyt ) ;
oo_ . mom . model_moments ( offset + ( 1 : E_yyt_nbr ) , 1 ) = E_yyt ( options_mom_ . mom . index . E_yyt ) ;
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && ( options_mom_ . mom . analytic_standard_errors || options_mom_ . mom . analytic_jacobian )
2020-12-16 12:03:21 +01:00
oo_ . mom . model_moments_params_derivs ( offset + ( 1 : E_yyt_nbr ) , : ) = reshape ( dE_yyt ( repmat ( options_mom_ . mom . index . E_yyt , [ 1 1 1 totparam_nbr ] ) ) , E_yyt_nbr , totparam_nbr ) ;
end
2020-06-29 07:40:34 +02:00
end
elseif strcmp ( options_mom_ . mom . mom_method , ' SMM' )
%------------------------------------------------------------------------------
% 3. Compute Moments of the model solution for normal innovations
%------------------------------------------------------------------------------
% create shock series with correct covariance matrix from iid standard normal shocks
i_exo_var = setdiff ( 1 : M_ . exo_nbr , find ( diag ( M_ . Sigma_e ) == 0 ) ) ; %find singular entries in covariance
chol_S = chol ( M_ . Sigma_e ( i_exo_var , i_exo_var ) ) ;
2020-07-10 22:32:39 +02:00
scaled_shock_series = zeros ( size ( options_mom_ . mom . shock_series ) ) ; %initialize
scaled_shock_series ( : , i_exo_var ) = options_mom_ . mom . shock_series ( : , i_exo_var ) * chol_S ; %set non-zero entries
2020-06-29 07:40:34 +02:00
% simulate series
y_sim = simult_ ( M_ , options_mom_ , dr . ys , dr , scaled_shock_series , options_mom_ . order ) ;
% provide meaningful penalty if data is nan or inf
if any ( any ( isnan ( y_sim ) ) ) || any ( any ( isinf ( y_sim ) ) )
if options_mom_ . mode_compute == 13
fval = Inf ( size ( oo_ . mom . Sw , 1 ) , 1 ) ;
else
fval = Inf ;
end
info ( 1 ) = 180 ;
info ( 4 ) = 0.1 ;
exit_flag = 0 ;
if options_mom_ . mode_compute == 13
fval = ones ( size ( oo_ . mom . dataMoments , 1 ) , 1 ) * options_mom_ . huge_number ;
end
return
end
% Remove burn-in and focus on observables (note that y_sim is in declaration order)
2020-07-10 22:32:39 +02:00
y_sim = y_sim ( oo_ . dr . order_var ( oo_ . dr . obs_var ) , end - options_mom_ . mom . long + 1 : end ) ' ;
2020-06-29 07:40:34 +02:00
if ~ all ( diag ( M_ . H ) == 0 )
i_ME = setdiff ( [ 1 : size ( M_ . H , 1 ) ] , find ( diag ( M_ . H ) == 0 ) ) ; % find ME with 0 variance
chol_S = chol ( M_ . H ( i_ME , i_ME ) ) ; %decompose rest
2020-07-10 22:32:39 +02:00
shock_mat = zeros ( size ( options_mom_ . mom . ME_shock_series ) ) ; %initialize
2021-01-07 14:25:26 +01:00
shock_mat ( : , i_ME ) = options_mom_ . mom . ME_shock_series ( : , i_ME ) * chol_S ;
2020-06-29 07:40:34 +02:00
y_sim = y_sim + shock_mat ;
end
% Remove mean if centered moments
if options_mom_ . prefilter
y_sim = bsxfun ( @ minus , y_sim , mean ( y_sim , 1 ) ) ;
end
2020-08-05 15:30:58 +02:00
oo_ . mom . model_moments = method_of_moments_data_moments ( y_sim , oo_ , M_ . matched_moments , options_mom_ ) ;
2020-06-29 07:40:34 +02:00
end
%--------------------------------------------------------------------------
% 4. Compute quadratic target function
%--------------------------------------------------------------------------
moments_difference = oo_ . mom . data_moments - oo_ . mom . model_moments ;
residuals = sqrt ( options_mom_ . mom . weighting_matrix_scaling_factor ) * oo_ . mom . Sw * moments_difference ;
oo_ . mom . Q = residuals ' * residuals ;
if options_mom_ . vector_output == 1 % lsqnonlin requires vector output
fval = residuals ;
if options_mom_ . mom . penalized_estimator
fval = [ fval ; ( xparam1 - oo_ . prior . mean ) ./ sqrt ( diag ( oo_ . prior . variance ) ) ] ;
end
else
fval = oo_ . mom . Q ;
if options_mom_ . mom . penalized_estimator
fval = fval + ( xparam1 - oo_ . prior . mean ) ' / oo_ . prior . variance * ( xparam1 - oo_ . prior . mean ) ;
end
end
2021-01-14 10:03:39 +01:00
if options_mom_ . mom . compute_derivs && options_mom_ . mom . analytic_jacobian
if options_mom_ . mom . penalized_estimator
dxparam1 = eye ( length ( xparam1 ) ) ;
end
for jp = 1 : length ( xparam1 )
dmoments_difference = - oo_ . mom . model_moments_params_derivs ( : , jp ) ;
dresiduals = sqrt ( options_mom_ . mom . weighting_matrix_scaling_factor ) * oo_ . mom . Sw * dmoments_difference ;
if options_mom_ . vector_output == 1 % lsqnonlin requires vector output
if options_mom_ . mom . penalized_estimator
df ( : , jp ) = [ dresiduals ; dxparam1 ( : , jp ) ./ sqrt ( diag ( oo_ . prior . variance ) ) ] ;
else
df ( : , jp ) = dresiduals ;
end
else
df ( : , jp ) = dresiduals ' * residuals + residuals ' * dresiduals ;
if options_mom_ . mom . penalized_estimator
df ( : , jp ) = df ( : , jp ) + ( dxparam1 ( : , jp ) ) ' / oo_ . prior . variance * ( xparam1 - oo_ . prior . mean ) + ( xparam1 - oo_ . prior . mean ) ' / oo_ . prior . variance * ( dxparam1 ( : , jp ) ) ;
end
end
end
end
2020-06-29 07:40:34 +02:00
end %main function end