From fddee8e1db602a1dd51a43d1ffa965eeeb9b8528 Mon Sep 17 00:00:00 2001
From: Johannes Pfeifer <jpfeifer@gmx,de>
Date: Wed, 30 Oct 2013 14:26:30 +0100
Subject: [PATCH] Bugfixes for correlated shocks

Uses preprocessing capabilities introduced in 07137e804b34a0e615398cb7cb5876f4a9027274

Fixes #392 and #494. Also fixes a bug in the checking for positive definiteness of covariance matrices in likelihood functions

Allows for calibrated covariances by reading them out and setting them after covariance matrix has been reconstructed from correlation and variances.

Adds unit test
---
 matlab/dsge_likelihood.m                      | 24 +++++-
 matlab/dynare_estimation_1.m                  | 34 ++------
 matlab/non_linear_dsge_likelihood.m           | 26 +++++-
 matlab/print_info.m                           |  4 +
 matlab/set_all_parameters.m                   | 45 ++++++----
 matlab/set_parameters.m                       | 20 +++--
 matlab/set_prior.m                            |  4 +-
 .../fs2000_calibrated_covariance.mod          | 86 +++++++++++++++++++
 8 files changed, 187 insertions(+), 56 deletions(-)
 create mode 100644 tests/estimation/fs2000_calibrated_covariance.mod

diff --git a/matlab/dsge_likelihood.m b/matlab/dsge_likelihood.m
index 62bf68c1fa..8920413aa6 100644
--- a/matlab/dsge_likelihood.m
+++ b/matlab/dsge_likelihood.m
@@ -206,7 +206,7 @@ Q = Model.Sigma_e;
 H = Model.H;
 
 % Test if Q is positive definite.
-if ~issquare(Q) && EstimatedParameters.ncx
+if ~issquare(Q) || EstimatedParameters.ncx || isfield(EstimatedParameters,'calibrated_covariances')
     [Q_is_positive_definite, penalty] = ispd(Q);
     if ~Q_is_positive_definite
         fval = objective_function_penalty_base+penalty;
@@ -214,10 +214,20 @@ if ~issquare(Q) && EstimatedParameters.ncx
         info = 43;
         return
     end
+    if isfield(EstimatedParameters,'calibrated_covariances')
+        correct_flag=check_consistency_covariances(Q);
+        if ~correct_flag
+            penalty = sum(Q(EstimatedParameters.calibrated_covariances.position).^2);
+            fval = objective_function_penalty_base+penalty;
+            exit_flag = 0;
+            info = 71;
+            return
+        end
+    end
 end
 
 % Test if H is positive definite.
-if ~issquare(H) && EstimatedParameters.ncn
+if ~issquare(H) || EstimatedParameters.ncn || isfield(EstimatedParameters,'calibrated_covariances_ME')
     [H_is_positive_definite, penalty] = ispd(H);
     if ~H_is_positive_definite
         fval = objective_function_penalty_base+penalty;
@@ -225,6 +235,16 @@ if ~issquare(H) && EstimatedParameters.ncn
         info = 44;
         return
     end
+    if isfield(EstimatedParameters,'calibrated_covariances_ME')
+        correct_flag=check_consistency_covariances(H);
+        if ~correct_flag
+            penalty = sum(H(EstimatedParameters.calibrated_covariances_ME.position).^2);
+            fval = objective_function_penalty_base+penalty;
+            exit_flag = 0;
+            info = 72;
+            return
+        end
+    end
 end
 
 
diff --git a/matlab/dynare_estimation_1.m b/matlab/dynare_estimation_1.m
index 2c8783bfd2..da865af160 100644
--- a/matlab/dynare_estimation_1.m
+++ b/matlab/dynare_estimation_1.m
@@ -80,38 +80,16 @@ end
 
 [dataset_,xparam1, hh, M_, options_, oo_, estim_params_,bayestopt_] = dynare_estimation_init(var_list_, dname, [], M_, options_, oo_, estim_params_, bayestopt_);
 
+%check for calibrated covariances before updating parameters
+if ~isempty(estim_params_)
+    estim_params_=check_for_calibrated_covariances(xparam1,estim_params_,M_);
+end
 % Set sigma_e_is_diagonal flag (needed if the shocks block is not declared in the mod file).
 M_.sigma_e_is_diagonal = 1;
-if estim_params_.ncx || any(nnz(tril(M_.Sigma_e,-1)))
+if estim_params_.ncx || any(nnz(tril(M_.Correlation_matrix,-1))) || isfield(estim_params_,'calibrated_covariances')
     M_.sigma_e_is_diagonal = 0;
 end
 
-% Set the correlation matrix if necessary.
-if ~isequal(estim_params_.ncx,nnz(tril(M_.Sigma_e,-1)))
-    M_.Correlation_matrix = diag(1./sqrt(diag(M_.Sigma_e)))*M_.Sigma_e*diag(1./sqrt(diag(M_.Sigma_e)));
-    % Remove NaNs appearing because of variances calibrated to zero.
-    if any(isnan(M_.Correlation_matrix))
-        zero_variance_idx = find(~diag(M_.Sigma_e));
-        for i=1:length(zero_variance_idx)
-            M_.Correlation_matrix(zero_variance_idx(i),:) = 0;
-            M_.Correlation_matrix(:,zero_variance_idx(i)) = 0;
-        end
-    end
-end
-
-% Set the correlation matrix of measurement errors if necessary.
-if ~isequal(estim_params_.ncn,nnz(tril(M_.H,-1)))
-    M_.Correlation_matrix_ME = diag(1./sqrt(diag(M_.H)))*M_.H*diag(1./sqrt(diag(M_.H)));
-    % Remove NaNs appearing because of variances calibrated to zero.
-    if any(isnan(M_.Correlation_matrix_ME))
-        zero_variance_idx = find(~diag(M_.H));
-        for i=1:length(zero_variance_idx)
-            M_.Correlation_matrix_ME(zero_variance_idx(i),:) = 0;
-            M_.Correlation_matrix_ME(:,zero_variance_idx(i)) = 0;
-        end
-    end
-end
-
 data = dataset_.data;
 rawdata = dataset_.rawdata;
 data_index = dataset_.missing.aindex;
@@ -151,7 +129,7 @@ if exist(mh_scale_fname)
 end
 
 if ~isempty(estim_params_)
-    set_parameters(xparam1);
+    M_ = set_all_parameters(xparam1,estim_params_,M_);
 end
 
 % compute sample moments if needed (bvar-dsge)
diff --git a/matlab/non_linear_dsge_likelihood.m b/matlab/non_linear_dsge_likelihood.m
index 41ba13fdad..474b8dbb1c 100644
--- a/matlab/non_linear_dsge_likelihood.m
+++ b/matlab/non_linear_dsge_likelihood.m
@@ -163,7 +163,7 @@ Model = set_all_parameters(xparam1,EstimatedParameters,Model);
 Q = Model.Sigma_e;
 H = Model.H;
 
-if ~isscalar(Q) &&  EstimatedParameters.ncx
+if ~issquare(Q) || EstimatedParameters.ncx || isfield(EstimatedParameters,'calibrated_covariances')
     [Q_is_positive_definite, penalty] = ispd(Q);
     if ~Q_is_positive_definite
         fval = objective_function_penalty_base+penalty;
@@ -171,9 +171,20 @@ if ~isscalar(Q) &&  EstimatedParameters.ncx
         info = 43;
         return
     end
+    if isfield(EstimatedParameters,'calibrated_covariances')
+        correct_flag=check_consistency_covariances(Q);
+        if ~correct_flag
+            penalty = sum(Q(EstimatedParameters.calibrated_covariances.position).^2);
+            fval = objective_function_penalty_base+penalty;
+            exit_flag = 0;
+            info = 71;
+            return
+        end
+    end
+
 end
 
-if ~isscalar(H) && EstimatedParameters.ncn
+if ~issquare(H) || EstimatedParameters.ncn || isfield(EstimatedParameters,'calibrated_covariances_ME')
     [H_is_positive_definite, penalty] = ispd(H);
     if ~H_is_positive_definite
         fval = objective_function_penalty_base+penalty;
@@ -181,6 +192,17 @@ if ~isscalar(H) && EstimatedParameters.ncn
         info = 44;
         return
     end
+    if isfield(EstimatedParameters,'calibrated_covariances_ME')
+        correct_flag=check_consistency_covariances(H);
+        if ~correct_flag
+            penalty = sum(H(EstimatedParameters.calibrated_covariances_ME.position).^2);
+            fval = objective_function_penalty_base+penalty;
+            exit_flag = 0;
+            info = 72;
+            return
+        end
+    end
+
 end
 
 %------------------------------------------------------------------------------
diff --git a/matlab/print_info.m b/matlab/print_info.m
index 157275fb4b..691bda9300 100644
--- a/matlab/print_info.m
+++ b/matlab/print_info.m
@@ -113,6 +113,10 @@ if ~noprint
         error(['Discretionary policy: some eigenvalues greater than options_.qz_criterium. Model potentially unstable.']);
       case 63
         error(['Discretionary policy: NaN elements are present in the solution. Procedure failed.']);
+      case 71
+        error(['Calibrated covariance of the structural errors implies correlation larger than  +-1.']);
+      case 72
+        error(['Calibrated covariance of the measurement errors implies correlation larger than  +-1.']);
         % Aim Code Conversions by convertAimCodeToInfo.m
       case 102
         error('Aim: roots not correctly computed by real_schur');
diff --git a/matlab/set_all_parameters.m b/matlab/set_all_parameters.m
index 656ac34edf..9fb3ef4bd6 100644
--- a/matlab/set_all_parameters.m
+++ b/matlab/set_all_parameters.m
@@ -56,9 +56,11 @@ nvn = estim_params.nvn;
 ncn = estim_params.ncn;
 np = estim_params.np;
 Sigma_e = M.Sigma_e;
+Correlation_matrix = M.Correlation_matrix;
 H = M.H;
-
-% setting shocks variance
+Correlation_matrix_ME = M.Correlation_matrix_ME;
+% setting shocks variance on the diagonal of Covariance matrix; used later
+% for updating covariances
 if nvx
     var_exo = estim_params.var_exo;
     for i=1:nvx
@@ -69,7 +71,8 @@ end
 % update offset
 offset = nvx;
 
-% setting measument error variance
+% setting measument error variance; on the diagonal of Covariance matrix; used later
+% for updating covariances
 if nvn
     for i=1:nvn
         k = estim_params.nvn_observable_correspondence(i,1);
@@ -81,38 +84,42 @@ end
 offset = nvx+nvn;
 
 % setting shocks covariances
-if ~isempty(M.Correlation_matrix)
-    Sigma_e = diag(sqrt(diag(Sigma_e)))*M.Correlation_matrix*diag(sqrt(diag(Sigma_e))); % use of old correlation matrix is correct due to the diagonal structure and later only using the hence correctly updated diagonal entries of Sigma_e
-end
 if ncx
     corrx = estim_params.corrx;
     for i=1:ncx
         k1 = corrx(i,1);
         k2 = corrx(i,2);
-        M.Correlation_matrix(k1,k2) = xparam1(i+offset);
-        M.Correlation_matrix(k2,k1) = M.Correlation_matrix(k1,k2);
-        Sigma_e(k1,k2) = xparam1(i+offset)*sqrt(Sigma_e(k1,k1)*Sigma_e(k2,k2));
-        Sigma_e(k2,k1) = Sigma_e(k1,k2);
+        Correlation_matrix(k1,k2) = xparam1(i+offset);
+        Correlation_matrix(k2,k1) = Correlation_matrix(k1,k2);
     end
 end
-
+%build covariance matrix from correlation matrix and variances already on
+%diagonal
+Sigma_e = diag(sqrt(diag(Sigma_e)))*Correlation_matrix*diag(sqrt(diag(Sigma_e))); 
+%if calibrated covariances, set them now to their stored value
+if isfield(estim_params,'calibrated_covariances')
+    Sigma_e(estim_params.calibrated_covariances.position)=estim_params.calibrated_covariances.cov_value;
+end
 % update offset
 offset = nvx+nvn+ncx;
+
 % setting measurement error covariances
-if ~isempty(M.Correlation_matrix_ME)
-    H = diag(sqrt(diag(H)))*M.Correlation_matrix_ME*diag(sqrt(diag(H)));
-end
 if ncn
     corrn_observable_correspondence = estim_params.corrn_observable_correspondence;
     for i=1:ncn
         k1 = corrn_observable_correspondence(i,1);
         k2 = corrn_observable_correspondence(i,2);
-        M.Correlation_matrix_ME(k1,k2) = xparam1(i+offset);
-        M.Correlation_matrix_ME(k2,k1) = M.Correlation_matrix_ME(k1,k2);
-        H(k1,k2) = xparam1(i+offset)*sqrt(H(k1,k1)*H(k2,k2));
-        H(k2,k1) = H(k1,k2);
+        Correlation_matrix_ME(k1,k2) = xparam1(i+offset);
+        Correlation_matrix_ME(k2,k1) = Correlation_matrix_ME(k1,k2);
     end
 end
+%build covariance matrix from correlation matrix and variances already on
+%diagonal
+H = diag(sqrt(diag(H)))*Correlation_matrix_ME*diag(sqrt(diag(H)));
+%if calibrated covariances, set them now to their stored value
+if isfield(estim_params,'calibrated_covariances_ME')
+    H(estim_params.calibrated_covariances_ME.position)=estim_params.calibrated_covariances_ME.cov_value;
+end
 
 % update offset
 offset = nvx+ncx+nvn+ncn;
@@ -125,7 +132,9 @@ end
 % updating matrices in M
 if nvx || ncx
     M.Sigma_e = Sigma_e;
+    M.Correlation_matrix=Correlation_matrix;
 end
 if nvn || ncn
     M.H = H;
+    M.Correlation_matrix_ME=Correlation_matrix_ME;    
 end
\ No newline at end of file
diff --git a/matlab/set_parameters.m b/matlab/set_parameters.m
index d1e81afd81..58e167d554 100644
--- a/matlab/set_parameters.m
+++ b/matlab/set_parameters.m
@@ -14,7 +14,7 @@ function set_parameters(xparam1)
 % SPECIAL REQUIREMENTS
 %    none
 
-% Copyright (C) 2003-2009 Dynare Team
+% Copyright (C) 2003-2013 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -39,9 +39,11 @@ nvn = estim_params_.nvn;
 ncn = estim_params_.ncn;
 np = estim_params_.np;
 Sigma_e = M_.Sigma_e;
+Correlation_matrix = M_.Correlation_matrix;
 offset = 0;
 
-% stderrs of the exogenous shocks
+% setting shocks variance on the diagonal of Covariance matrix; used later
+% for updating covariances
 if nvx
     var_exo = estim_params_.var_exo;
     for i=1:nvx
@@ -58,10 +60,17 @@ if ncx
     for i=1:ncx
         k1 = corrx(i,1);
         k2 = corrx(i,2);
-        Sigma_e(k1,k2) = xparam1(i+offset)*sqrt(Sigma_e(k1,k1)*Sigma_e(k2,k2));
-        Sigma_e(k2,k1) = Sigma_e(k1,k2);
+        Correlation_matrix(k1,k2) = xparam1(i+offset);
+        Correlation_matrix(k2,k1) = Correlation_matrix(k1,k2);
     end
 end
+%build covariance matrix from correlation matrix and variances already on
+%diagonal
+Sigma_e = diag(sqrt(diag(Sigma_e)))*Correlation_matrix*diag(sqrt(diag(Sigma_e))); 
+if isfield(estim_params,'calibrated_covariances')
+    Sigma_e(estim_params.calibrated_covariances.position)=estim_params.calibrated_covariances.cov_value;
+end
+
 % and update offset
 offset = offset + ncx + ncn;
 
@@ -70,4 +79,5 @@ if np
     M_.params(estim_params_.param_vals(:,1)) = xparam1(offset+1:end);
 end
 
-M_.Sigma_e = Sigma_e;
\ No newline at end of file
+M_.Sigma_e = Sigma_e;
+M_.Correlation_matrix=Correlation_matrix;
diff --git a/matlab/set_prior.m b/matlab/set_prior.m
index f82223ec85..9f2c40285b 100644
--- a/matlab/set_prior.m
+++ b/matlab/set_prior.m
@@ -75,9 +75,10 @@ if nvx
 end
 if nvn
     estim_params_.nvn_observable_correspondence=NaN(nvn,1); % stores number of corresponding observable
-    if isequal(M_.H,0)
+    if isequal(M_.H,0) %if no previously set measurement error, initialize H
         nvarobs = size(options_.varobs,1);
         M_.H = zeros(nvarobs,nvarobs);
+        M_.Correlation_matrix_ME = eye(nvarobs);
     end
     for i=1:nvn
         obsi_ = strmatch(deblank(M_.endo_names(estim_params_.var_endo(i,1),:)),deblank(options_.varobs),'exact');
@@ -116,6 +117,7 @@ if ncn
     if isequal(M_.H,0)
         nvarobs = size(options_.varobs,1);
         M_.H = zeros(nvarobs,nvarobs);
+        M_.Correlation_matrix_ME = eye(nvarobs);
     end
     xparam1 = [xparam1; estim_params_.corrn(:,3)];
     ub = [ub; max(min(estim_params_.corrn(:,5),1),-1)];
diff --git a/tests/estimation/fs2000_calibrated_covariance.mod b/tests/estimation/fs2000_calibrated_covariance.mod
new file mode 100644
index 0000000000..20d34c84ad
--- /dev/null
+++ b/tests/estimation/fs2000_calibrated_covariance.mod
@@ -0,0 +1,86 @@
+//two covariances are calibrated and one covariance of the ME. One of the calibrated covariances is superseded by estimation
+
+var m P c e W R k d n l gy_obs gp_obs y dA;
+varexo e_a e_m e_f;
+
+parameters alp bet gam mst rho psi del;
+
+alp = 0.33;
+bet = 0.99;
+gam = 0.003;
+mst = 1.011;
+rho = 0.7;
+psi = 0.787;
+del = 0.02;
+
+model;
+dA = exp(gam+e_a);
+log(m) = (1-rho)*log(mst) + rho*log(m(-1))+e_m;
+-P/(c(+1)*P(+1)*m)+bet*P(+1)*(alp*exp(-alp*(gam+log(e(+1))))*k^(alp-1)*n(+1)^(1-alp)+(1-del)*exp(-(gam+log(e(+1)))))/(c(+2)*P(+2)*m(+1))=0;
+W = l/n;
+-(psi/(1-psi))*(c*P/(1-n))+l/n = 0;
+R = P*(1-alp)*exp(-alp*(gam+e_a))*k(-1)^alp*n^(-alp)/W;
+1/(c*P)-bet*P*(1-alp)*exp(-alp*(gam+e_a))*k(-1)^alp*n^(1-alp)/(m*l*c(+1)*P(+1)) = 0;
+c+k = exp(-alp*(gam+e_a))*k(-1)^alp*n^(1-alp)+(1-del)*exp(-(gam+e_a))*k(-1);
+P*c = m;
+m-1+d = l;
+e = exp(e_a);
+y = k(-1)^alp*n^(1-alp)*exp(-alp*(gam+e_a));
+gy_obs = dA*y/y(-1);
+gp_obs = (P/P(-1))*m(-1)/dA;
+end;
+
+initval;
+k = 6;
+m = mst;
+P = 2.25;
+c = 0.45;
+e = 1;
+W = 4;
+R = 1.02;
+d = 0.85;
+n = 0.19;
+l = 0.86;
+y = 0.6;
+gy_obs = exp(gam);
+gp_obs = exp(-gam);
+dA = exp(gam);
+end;
+
+varobs gp_obs gy_obs;
+
+shocks;
+var e_a; stderr 0.01;
+var e_f; stderr 0.01;
+var gy_obs; stderr 0.01;
+var gy_obs, gp_obs= 0.00005;
+var e_a, e_m = 0.00005;
+var e_m, e_f = 0.00001;
+end;
+
+steady;
+check;
+
+estimated_params;
+stderr e_m, 0.008862;
+corr e_a, e_m, 0.5;
+stderr gp_obs, 0.035449;
+end;
+
+estimated_params_init;
+stderr e_m, 0.5;
+corr e_a, e_m, 0.5;
+stderr gp_obs, 0.5;
+end;
+
+estimation(order=1,datafile=fsdat_simul,nobs=192, loglinear, mh_replic=2002, mh_nblocks=1, mh_jscale=0.8);
+
+if ~isequal(M_.Sigma_e(3,2),1e-5) || ~isequal(M_.Sigma_e(2,3),1e-5)
+    error('Problem in setting calibrated covariance of structural shocks')
+end
+if isequal(M_.Sigma_e(2,1),5e-5) || isequal(M_.Sigma_e(1,2),5e-5)
+    error('Problem in overriding calibrated covariance of structural shocks by estimated correlation')
+end
+if ~isequal(M_.H(2,1),5e-5) || ~isequal(M_.H(1,2),5e-5)
+    error('Problem in setting calibrated covariance of measurement errors')
+end
\ No newline at end of file
-- 
GitLab