function [param,sigma] = simulated_moments_estimation(dataset,options,parallel) % Performs estimation by Simulated Moments Method. % % INPUTS: % xparam [double] p*1 vector of initial values for the estimated parameters. % dataset [ ] Structure describing the data set. % options [ ] Structure defining options for SMM. % parallel [ ] Structure defining the parallel mode settings (optional). % % OUTPUTS: % param [double] p*1 vector of point estimates for the parameters. % sigma [double] p*p covariance matrix of the SMM estimates. % % SPECIAL REQUIREMENTS % The user has to provide a file where the moment conditions are defined. % Copyright (C) 2010-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 . global M_ options_ oo_ estim_params_ % Load the dataset. eval(dataset.name); dataset.data = []; for v = 1:dataset.number_of_observed_variables eval(['dataset.data = [ dataset.data , ' dataset.variables(v,:) ' ];']) end data = dataset.data(dataset.first_observation:dataset.first_observation+dataset.number_of_observations,:); % Compute sample moments and the weighting matrix. eval(['[sample_moments,long_run_covariance] = ' M_.fname '_moments;']) weighting_matrix = inv(long_run_covariance); % Initialize output. sigma = []; param = []; % Set options and initial condition. options.estimated_parameters.list = []; xparam = []; if ~isempty(estim_params_.var_exo) options.estimated_variances.idx = estim_params_.var_exo(:,1); options.estimated_parameters.list = char(M_.exo_names(options.estimated_variances.idx)); options.estimated_parameters.nv = rows(estim_params_.var_exo); xparam = [xparam; estim_params_.var_exo(:,2)]; end if ~isempty(estim_params_.param_vals) options.estimated_parameters.idx = estim_params_.param_vals(:,1); if isempty(options.estimated_parameters.list) options.estimated_parameters.list = char(M_.param_names(options.estimated_parameters.idx)); else options.estimated_parameters.list = char(options.estimated_parameters.list,... M_.param_names(options.estimated_parameters.idx)); end options.estimated_parameters.np = rows(estim_params_.param_vals); xparam = [xparam; estim_params_.param_vals(:,2)]; end options.estimated_parameters.nb = rows(options.estimated_parameters.list); options.estimated_parameters.lower_bound = NaN(options.estimated_parameters.nb,1); options.estimated_parameters.upper_bound = NaN(options.estimated_parameters.nb,1); options.estimated_parameters.lower_bound = []; options.estimated_parameters.lower_bound = [options.estimated_parameters.lower_bound; ... estim_params_.var_exo(:,3); ... estim_params_.param_vals(:,3) ]; options.estimated_parameters.upper_bound = []; options.estimated_parameters.upper_bound = [options.estimated_parameters.upper_bound; ... estim_params_.var_exo(:,4); ... estim_params_.param_vals(:,4) ]; options.number_of_simulated_sample = 0; for i=1:length(parallel) options.number_of_simulated_sample = options.number_of_simulated_sample + parallel(i).number_of_jobs*parallel(i).number_of_simulations; end options.observed_variables_idx = dataset.observed_variables_idx; % Set up parallel mode if needed. if nargin>2 if ~isunix error('The parallel version of SMM estimation is not implemented for non unix platforms!') end [~,hostname] = unix('hostname --fqdn'); hostname = deblank(hostname); master_is_running_a_job = 0; for i=1:length(parallel) if strcmpi(hostname,parallel(i).machine) master_is_running_a_job = 1; break end end if ~master_is_running_a_job error('Master has to run one job!'); end if options.optimization_routine>0 estimated_parameters_optimization_path = [NaN;xparam]; save('optimization_path.mat','estimated_parameters_optimization_path'); end skipline() disp('Master talks to its slaves...') skipline() % Save the workspace. save('master_variables.mat','options_','M_','oo_'); % Send the workspace to each remote computer. skipline() for i = 1:length(parallel) if ~strcmpi(hostname,parallel(i).machine) unix(['scp master_variables.mat ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); end end for i=1:length(parallel) % Write a bash script file to execute matlab scripts in the background fid = fopen('call_matlab_session.sh','w'); fprintf(fid,'#!/bin/sh\n'); fprintf(fid,'unset DISPLAY\n'); fprintf(fid,['cd ' parallel(i).folder '\n']); fprintf(fid,['nohup ' parallel(i).matlab '/matlab -nodesktop -nodisplay -nojvm < $1 > /dev/null 2>&1\n']); fprintf(fid,'exit'); fclose(fid); % Set the permission for this file (has to be executable) %fileattrib('call_matlab_session.sh','+x','u'); unix(['chmod u+x call_matlab_session.sh']); % Send the script file on each remote computer if ~strcmpi(hostname,parallel(i).machine) unix(['scp call_matlab_session.sh ' , parallel(i).login , '@' , parallel(i).machine , ':~/' ]); else unix(['cp call_matlab_session.sh ~/call_matlab_session.sh']); end end % Send the files to each remote computer. for i = 1:length(parallel) if ~strcmpi(hostname,parallel(i).machine) unix(['scp ' M_.fname '_steadystate.m ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); unix(['scp ' M_.fname '_moments.m ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); unix(['scp ' M_.fname '_static.m ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); if exist([M_.fname '_dynamic.c']) use_dll_flag = 1; unix(['scp ' M_.fname '_dynamic.c ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); else use_dll_flag = 0; unix(['scp ' M_.fname '_dynamic.m ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); end end end % If needed, compile dynamic model mex file on each remote computer if ~strcmpi(hostname,parallel(i).machine) && use_dll_flag % Write a matlab script that will trigger the compilation of the mex file. fid = fopen('compile_model.m', 'w'); fprintf(fid,[' eval(''mex -O LDFLAGS=''''-pthread -shared -Wl,--no-undefined'''' ' M_.fname '_dynamic.c'') ']); fprintf(fid, '\n exit'); fclose(fid); for i = 1:length(parallel) if ~strcmpi(hostname,parallel(i).machine) % Send the generated matlab script to the remote computer. unix(['scp compile_model.m ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder]); % Compile the mex file on the remote computer. unix(['ssh ' parallel(i).login , '@' , parallel(i).machine ' ./call_matlab_session.sh compile_model.m']); end end end % Write the matlab script files for the evaluation of the simulated moment conditions job = 0; for i=1:length(parallel) for j=1:parallel(i).number_of_jobs job = job+1; % Create random number streams write_job(hostname, parallel(i).machine, parallel(i).dynare, ... options.simulated_sample_size, length(sample_moments), ... dataset.observed_variables_idx, options.estimated_variances.idx', options.estimated_parameters.idx', options.burn_in_periods, [M_.fname '_moments'], parallel(i).number_of_simulations, ... parallel(i).number_of_threads_per_job, job, j, options.estimated_parameters.nb, options.estimated_parameters.nv, ... options.estimated_parameters.np); if ~strcmpi(hostname,parallel(i).machine) unix(['scp ' , 'job' , int2str(job) , '.m ' , parallel(i).login , '@' , parallel(i).machine , ':' parallel(i).folder ]); end end end skipline() disp('... And slaves do as ordered.') skipline() if exist('intermediary_results_from_master_and_slaves','dir') unix('rm -rf intermediary_results_from_master_and_slaves'); end unix('mkdir intermediary_results_from_master_and_slaves'); unix('chmod -R u+x intermediary_results_from_master_and_slaves'); end skipline() if options.optimization_routine==1 % Set options for csminwel. H0 = 1e-4*eye(options.estimated_parameters.nb); ct = 1e-4; it = 1000; vb = 2; % Minimization of the objective function. if nargin==2 [fval,param,grad,hessian_csminwel,itct,fcount,retcodehat] = ... csminwel1('smm_objective',xparam,H0,[],ct,it,2,options_.gradient_epsilon,sample_moments,weighting_matrix,options); elseif nargin>2 [fval,param,grad,hessian_csminwel,itct,fcount,retcodehat] = ... csminwel1('smm_objective',xparam,H0,[],ct,it,2,options_.gradient_epsilon,sample_moments,weighting_matrix,options,parallel); end elseif options.optimization_routine==2 optim_options = optimset('display','iter','MaxFunEvals',1000000,'MaxIter',6000,'TolFun',1e-4,'TolX',1e-4); if isfield(options_,'optim_opt') eval(['optim_options = optimset(optim_options,' options_.optim_opt ');']); end if nargin==2 [param,fval,exitflag] = fminsearch('smm_objective',xparam,optim_options,sample_moments,weighting_matrix,options); else [param,fval,exitflag] = fminsearch('smm_objective',xparam,optim_options,sample_moments,weighting_matrix,options,parallel); end elseif options.optimization_routine==0% Compute the variance of the SMM estimator load('optimization_path.mat'); tmp = sortrows(estimated_parameters_optimization_path',1); param = tmp(1,2:end)'; % Compute gradient of the moment function (distance between sample and simulated moments). [F,G] = dynare_gradient('moment_function',param,options_.gradient_epsilon,sample_moments,dataset,options,parallel); V = (1+1/options.number_of_simulated_sample)*G'*long_run_covariance*G; [param,diag(V)] elseif options.optimization_routine<0 T = -options.optimization_routine;% length of the simulated time series. time_series = extended_path(oo_.steady_state,T,1); save time_series.mat; end function write_job(hostname, remotename, dynare_path, sample_size, number_of_moments, observed_variables_idx, variance_idx, parameters_idx, burn_in_periods, moments_file_name, number_of_simulations,threads_per_job, slave_number, job_number,nb,nv,np) fid = fopen(['job' int2str(slave_number) '.m'],'w'); fprintf(fid,['% Generated by ' hostname '.\n\n']); if ( strcmpi(hostname,remotename) && (job_number>1) ) || ~strcmpi(hostname,remotename) fprintf(fid,'load(''master_variables'');\n'); fprintf(fid,'assignin(''base'',''M_'',M_);\n'); fprintf(fid,'assignin(''base'',''oo_'',oo_);\n'); fprintf(fid,'assignin(''base'',''options_'',options_);\n\n'); end if ( strcmpi(hostname,remotename) && (job_number>1) ) || ~strcmpi(hostname,remotename) fprintf(fid,['addpath ' dynare_path '\n']); fprintf(fid,['dynare_config;\n\n']); end fprintf(fid,['simulated_moments = zeros(' int2str(number_of_moments) ',1);\n\n']); fprintf(fid,'load(''estimated_parameters.mat'');\n'); fprintf(fid,['M_.params([' num2str(parameters_idx) ']) = xparams(' int2str(nv) '+1:' int2str(nb) ');\n\n']); fprintf(fid,'tmp = diag(M_.Sigma_e);') fprintf(fid,['tmp([' num2str(variance_idx) ']) = xparams(1:' int2str(nv) ').^2;\n\n']); fprintf(fid,'M_.Sigma_e = diag(tmp);') fprintf(fid,['stream=RandStream(''mt19937ar'',''Seed'',' int2str(slave_number) ');\n']); fprintf(fid,['RandStream.setGlobalStream(stream);\n\n']); fprintf(fid,['maxNumCompThreads(' int2str(threads_per_job) ');\n\n']); fprintf(fid,['for s = 1:' int2str(number_of_simulations) '\n'] ); fprintf(fid,[' time_series = extended_path([],' int2str(sample_size) ',1);\n']); fprintf(fid,[' data = time_series([' int2str(observed_variables_idx) '],' int2str(burn_in_periods) '+1:' int2str(sample_size) ');\n']); fprintf(fid,[' eval(''tmp = ' moments_file_name '(data);'');\n']); fprintf(fid,[' simulated_moments = simulated_moments + tmp;\n']); fprintf(fid,['end\n\n']); fprintf(fid,['simulated_moments = simulated_moments/' int2str(number_of_simulations) ';\n']); fprintf(fid,['save(''simulated_moments_slave_' int2str(slave_number) '.dat'',''simulated_moments'',''-ascii'');\n']); if ~strcmpi(hostname,remotename) fprintf(fid,['unix(''scp simulated_moments_slave_' int2str(slave_number) '.dat ' hostname ':' pwd '/intermediary_results_from_master_and_slaves '');\n']); fprintf(fid,['unix(''rm simulated_moments_slave_' int2str(slave_number) '.dat'');\n']); else fprintf(fid,['unix(''cp simulated_moments_slave_' int2str(slave_number) '.dat ' 'intermediary_results_from_master_and_slaves '');\n']); fprintf(fid,['unix(''rm simulated_moments_slave_' int2str(slave_number) '.dat'');\n']); end if ((job_number>1) && strcmpi(hostname,remotename)) || ~strcmpi(hostname,remotename) fprintf(fid,'exit'); end fclose(fid);