diff --git a/matlab/dsge_likelihood.m b/matlab/dsge_likelihood.m index 3238565e30b7913ba0562372bfb73794d9d17e86..e6880d5910d7e8f4993d56a90519ca48fb77b6ec 100644 --- a/matlab/dsge_likelihood.m +++ b/matlab/dsge_likelihood.m @@ -596,7 +596,7 @@ end if ((kalman_algo==1) || (kalman_algo==3))% Multivariate Kalman Filter if no_missing_data_flag - if DynareOptions.block == 1 + if DynareOptions.block [err, LIK] = block_kalman_filter(T,R,Q,H,Pstar,Y,start,Z,kalman_tol,riccati_tol, Model.nz_state_var, Model.n_diag, Model.nobs_non_statevar); mexErrCheck('block_kalman_filter', err); else @@ -609,11 +609,16 @@ if ((kalman_algo==1) || (kalman_algo==3))% Multivariate Kalman Filter end else - [LIK,lik] = missing_observations_kalman_filter(DynareDataset.missing.aindex,DynareDataset.missing.number_of_observations,DynareDataset.missing.no_more_missing_observations,Y,diffuse_periods+1,size(Y,2), ... + if 0 %DynareOptions.block + [err, LIK,lik] = block_kalman_filter(DynareDataset.missing.aindex,DynareDataset.missing.number_of_observations,DynareDataset.missing.no_more_missing_observations,... + T,R,Q,H,Pstar,Y,start,Z,kalman_tol,riccati_tol, Model.nz_state_var, Model.n_diag, Model.nobs_non_statevar); + else + [LIK,lik] = missing_observations_kalman_filter(DynareDataset.missing.aindex,DynareDataset.missing.number_of_observations,DynareDataset.missing.no_more_missing_observations,Y,diffuse_periods+1,size(Y,2), ... a, Pstar, ... kalman_tol, DynareOptions.riccati_tol, ... DynareOptions.presample, ... T,Q,R,H,Z,mm,pp,rr,Zflag,diffuse_periods); + end; end if analytic_derivation, LIK1=LIK; diff --git a/mex/sources/block_kalman_filter/block_kalman_filter.cc b/mex/sources/block_kalman_filter/block_kalman_filter.cc index 13fde7525a6e80c17c4047cf86e6a2f83e2b657c..e1ce39dbf3ba332c03b79de744afe19561b2f3f9 100644 --- a/mex/sources/block_kalman_filter/block_kalman_filter.cc +++ b/mex/sources/block_kalman_filter/block_kalman_filter.cc @@ -21,22 +21,12 @@ #include <iostream> #include <fstream> #include <vector> - +#include "omp.h" +#include "block_kalman_filter.h" using namespace std; //#define BLAS - #define DIRECT -#ifndef DEBUG_EX -# include <dynmex.h> -#else -# include "mex_interface.hh" -#endif - -#include <dynblas.h> -#include <dynlapack.h> - -#define BLOCK void mexDisp(mxArray* P) @@ -52,50 +42,24 @@ mexDisp(mxArray* P) mexPrintf(" %9.4f",M[i+ j * m]); mexPrintf("\n"); } + mexEvalString("drawnow;"); } -/* -(T,R,Q,H,P,Y,start,mf,kalman_tol,riccati_tol, block) -% Computes the likelihood of a stationnary state space model. -% -% INPUTS -% T [double] n*n transition matrix of the state equation. -% R [double] n*rr matrix, mapping structural innovations to state variables. -% Q [double] rr*rr covariance matrix of the structural innovations. -% H [double] pp*pp (or 1*1 =0 if no measurement error) covariance matrix of the measurement errors. -% P [double] n*n variance-covariance matrix with stationary variables -% Y [double] pp*smpl matrix of (detrended) data, where pp is the maximum number of observed variables. -% start [integer] scalar, likelihood evaluation starts at 'start'. -% mf [integer] pp*1 vector of indices. -% kalman_tol [double] scalar, tolerance parameter (rcond). -% riccati_tol [double] scalar, tolerance parameter (riccati iteration). -% -% OUTPUTS -% LIK [double] scalar, MINUS loglikelihood -% lik [double] vector, density of observations in each period. -% -% REFERENCES -% See "Filtering and Smoothing of State Vector for Diffuse State Space -% Models", S.J. Koopman and J. Durbin (2003, in Journal of Time Series -% Analysis, vol. 24(1), pp. 85-98). -% -% NOTES -% The vector "lik" is used to evaluate the jacobian of the likelihood. - -%global options_ -smpl = size(Y,2); % Sample size. -n = size(T,2); % Number of state variables. -pp = size(Y,1); % Maximum number of observed variables. -a = zeros(n,1); % State vector. -dF = 1; % det(F). -QQ = R*Q*transpose(R); % Variance of R times the vector of structural innovations. -t = 0; % Initialization of the time index. -lik = zeros(smpl,1); % Initialization of the vector gathering the densities. -LIK = Inf; % Default value of the log likelihood. -oldK = Inf; -notsteady = 1; % Steady state flag. -F_singular = 1; -if block + +void +mexDisp(double* M, int m, int n) +{ + mexPrintf("%d x %d\n", m, n); + mexEvalString("drawnow;"); + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + mexPrintf(" %9.4f",M[i+ j * m]); + mexPrintf("\n"); + } + mexEvalString("drawnow;"); +} +/*if block %nz_state_var = M_.nz_state_var; while notsteady && t<smpl t = t+1; @@ -147,28 +111,7 @@ else end end end - -if F_singular - error('The variance of the forecast error remains singular until the end of the sample') -end - -if t < smpl - t0 = t+1; - while t < smpl - t = t+1; - v = Y(:,t)-a(mf); - a = T*(a+K*v); - lik(t) = transpose(v)*iF*v; - end - lik(t0:smpl) = lik(t0:smpl) + log(dF); -end - -% adding log-likelihhod constants -lik = (lik + pp*log(2*pi))/2; - -LIK = sum(lik(start:end)); % Minus the log-likelihood.*/ - - +*/ bool not_all_abs_F_bellow_crit(double* F, int size, double crit) @@ -196,115 +139,116 @@ det(double* F, int dim, lapack_int* ipiv) det *= -F[i + i * dim]; return det; } -void -mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) + + + +BlockKalmanFilter::BlockKalmanFilter(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[], double *P_mf[], double *v_pp[], double *K[], double *v_n[], double *a[], double *K_P[], double *P_t_t1[], double *tmp[], double *P[]) { if (nlhs > 3) - DYN_MEX_FUNC_ERR_MSG_TXT("kalman_filter provides at most 3 output argument."); - if (nrhs != 13) - DYN_MEX_FUNC_ERR_MSG_TXT("kalman_filter requires exactly 13 input arguments."); -//(T,R,Q,H,P,Y,start,mf,kalman_tol,riccati_tol, block) - mxArray *pT = mxDuplicateArray(prhs[0]); - mxArray *pR = mxDuplicateArray(prhs[1]); - mxArray *pQ = mxDuplicateArray(prhs[2]); - mxArray *pH = mxDuplicateArray(prhs[3]); - mxArray *pP = mxDuplicateArray(prhs[4]); - mxArray *pY = mxDuplicateArray(prhs[5]); + DYN_MEX_FUNC_ERR_MSG_TXT("block_kalman_filter provides at most 3 output argument."); + if (nrhs != 13 && nrhs != 16) + DYN_MEX_FUNC_ERR_MSG_TXT("block_kalman_filter requires exactly \n 13 input arguments for standard Kalman filter \nor\n 16 input arguments for missing observations Kalman filter."); + if (nrhs == 16) + missing_observations = true; + else + missing_observations = false; + if (missing_observations) + { + if (! mxIsCell (prhs[0])) + DYN_MEX_FUNC_ERR_MSG_TXT("the first input argument of block_missing_observations_kalman_filter must be a Call Array."); + pdata_index = prhs[0]; + if (! mxIsDouble (prhs[1])) + DYN_MEX_FUNC_ERR_MSG_TXT("the second input argument of block_missing_observations_kalman_filter must be a scalar."); + number_of_observations = ceil(mxGetScalar(prhs[1])); + if (! mxIsDouble (prhs[2])) + DYN_MEX_FUNC_ERR_MSG_TXT("the third input argument of block_missing_observations_kalman_filter must be a scalar."); + no_more_missing_observations = ceil(mxGetScalar(prhs[2])); + pT = mxDuplicateArray(prhs[3]); + pR = mxDuplicateArray(prhs[4]); + pQ = mxDuplicateArray(prhs[5]); + pH = mxDuplicateArray(prhs[6]); + pP = mxDuplicateArray(prhs[7]); + pY = mxDuplicateArray(prhs[8]); + start = mxGetScalar(prhs[9]); + mfd = (double*)mxGetData(prhs[10]); + kalman_tol = mxGetScalar(prhs[11]); + riccati_tol = mxGetScalar(prhs[12]); + nz_state_var = (double*)mxGetData(prhs[13]); + n_diag = mxGetScalar(prhs[14]); + pure_obs = mxGetScalar(prhs[15]); + } + else + { + no_more_missing_observations = 0; + pT = mxDuplicateArray(prhs[0]); + pR = mxDuplicateArray(prhs[1]); + pQ = mxDuplicateArray(prhs[2]); + pH = mxDuplicateArray(prhs[3]); + pP = mxDuplicateArray(prhs[4]); + pY = mxDuplicateArray(prhs[5]); + start = mxGetScalar(prhs[6]); + /*Defining the initials values*/ + n = mxGetN(pT); // Number of state variables. + pp = mxGetM(pY); // Maximum number of observed variables. + smpl = mxGetN(pY); // Sample size. ; + mfd = (double*)mxGetData(prhs[7]); + kalman_tol = mxGetScalar(prhs[8]); + riccati_tol = mxGetScalar(prhs[9]); + nz_state_var = (double*)mxGetData(prhs[10]); + n_diag = mxGetScalar(prhs[11]); + pure_obs = mxGetScalar(prhs[12]); + } + T = mxGetPr(pT); + R = mxGetPr(pR); + Q = mxGetPr(pQ); + H = mxGetPr(pH); + *P = mxGetPr(pP); + Y = mxGetPr(pY); - double *T = mxGetPr(pT); - double *R = mxGetPr(pR); - double *Q = mxGetPr(pQ); - double *H = mxGetPr(pH); - double *P = mxGetPr(pP); - double *Y = mxGetPr(pY); - int start = mxGetScalar(prhs[6]); - double* mfd = (double*)mxGetData(prhs[7]); + n = mxGetN(pT); // Number of state variables. + pp = mxGetM(pY); // Maximum number of observed variables. + smpl = mxGetN(pY); // Sample size. ; + n_state = n - pure_obs; + - - double kalman_tol = mxGetScalar(prhs[8]); - double riccati_tol = mxGetScalar(prhs[9]); - int pure_obs = mxGetScalar(prhs[12]); - /* Reading the sparse structure of matrix in (§A) */ - typedef struct - { - int indx_1; - int indx_2; - int indx_3; - } t_Var; - - /*Defining the initials values*/ - int smpl = mxGetN(pY); // Sample size. ; - int n = mxGetN(pT); // Number of state variables. - lapack_int pp = mxGetM(pY); // Maximum number of observed variables. - int n_state = n - pure_obs; - int n_shocks = mxGetM(pQ); - - -#ifdef DIRECT - double* nz_state_var = (double*)mxGetData(prhs[10]); - int *i_nz_state_var = (int*)mxMalloc(n*sizeof(int)); - for (int i = 0; i < n; i++) - i_nz_state_var[i] = nz_state_var[i]; + /*mexPrintf("T\n"); + mexDisp(pT);*/ -#else - mxArray *M_; - M_ = mexGetVariable("global", "M_"); - if (M_ == NULL) - mexErrMsgTxt(" in main, global variable not found: M_\n"); - mxArray *mxa = mxGetFieldByNumber(M_, 0, mxGetFieldNumber(M_, "fname")); - int buflen = mxGetM(mxa) * mxGetN(mxa) + 1; - char *fname; - fname = (char *) mxCalloc(buflen+1, sizeof(char)); - int status = mxGetString(mxa, fname, buflen); - fname[buflen] = ' '; - if (status != 0) - mexWarnMsgTxt("Not enough space. Filename is truncated."); - string file_name = fname; - file_name.append(".kfi"); + H_size = mxGetN(pH) * mxGetM(pH); - ifstream KF_index_file; - KF_index_file.open(file_name.c_str(), ios::in | ios::binary); - int n_diag; - KF_index_file.read(reinterpret_cast<char *>(&n_diag), sizeof(n_diag)); - /*mexPrintf("n_diag=%d\n",n_diag);*/ - int size_index_KF; - KF_index_file.read(reinterpret_cast<char *>(&size_index_KF), sizeof(size_index_KF)); - //mexPrintf("size_index_KF=%d\n", size_index_KF); - t_Var *Var = (t_Var*)mxMalloc(size_index_KF * sizeof(t_Var)); - KF_index_file.read(reinterpret_cast<char *>(Var), size_index_KF * sizeof(t_Var)); + n_shocks = mxGetM(pQ); - int size_index_KF_2; - KF_index_file.read(reinterpret_cast<char *>(&size_index_KF_2), sizeof(size_index_KF_2)); - //mexPrintf("size_index_KF_2=%d\n", size_index_KF_2); - t_Var *Var_2 = (t_Var*)mxMalloc(size_index_KF_2 * sizeof(t_Var)); - KF_index_file.read(reinterpret_cast<char *>(Var_2), size_index_KF_2 * sizeof(t_Var)); - KF_index_file.close(); -#endif + if (missing_observations) + if (mxGetNumberOfElements(pdata_index) != (unsigned int)smpl) + DYN_MEX_FUNC_ERR_MSG_TXT("the number of element in the cell array passed to block_missing_observation_kalman_filter as first argument has to be equal to the smpl size"); + + i_nz_state_var = (int*)mxMalloc(n*sizeof(int)); + for (int i = 0; i < n; i++) + i_nz_state_var[i] = nz_state_var[i]; - mxArray* pa = mxCreateDoubleMatrix(n, 1, mxREAL); // State vector. - double* a = mxGetPr(pa); - double* tmp_a = (double*)mxMalloc(n * sizeof(double)); - double dF = 0.0; // det(F). - mxArray* p_tmp = mxCreateDoubleMatrix(n, n_state, mxREAL); - double *tmp = mxGetPr(p_tmp); - mxArray* p_tmp1 = mxCreateDoubleMatrix(n, n_shocks, mxREAL); - double *tmp1 = mxGetPr(p_tmp1); - int t = 0; // Initialization of the time index. - mxArray* plik = mxCreateDoubleMatrix(smpl, 1, mxREAL); - double* lik = mxGetPr(plik); - double Inf = mxGetInf(); - double LIK = 0.0; // Default value of the log likelihood. - - bool notsteady = true; // Steady state flag. - bool F_singular = true; - double* v_pp = (double*)mxMalloc(pp * sizeof(double)); - double* v_n = (double*)mxMalloc(n * sizeof(double)); - int* mf = (int*)mxMalloc(pp * sizeof(int)); + pa = mxCreateDoubleMatrix(n, 1, mxREAL); // State vector. + *a = mxGetPr(pa); + tmp_a = (double*)mxMalloc(n * sizeof(double)); + dF = 0.0; // det(F). + p_tmp = mxCreateDoubleMatrix(n, n_state, mxREAL); + *tmp = mxGetPr(p_tmp); + p_tmp1 = mxCreateDoubleMatrix(n, n_shocks, mxREAL); + tmp1 = mxGetPr(p_tmp1); + t = 0; // Initialization of the time index. + plik = mxCreateDoubleMatrix(smpl, 1, mxREAL); + lik = mxGetPr(plik); + Inf = mxGetInf(); + LIK = 0.0; // Default value of the log likelihood. + notsteady = true; // Steady state flag. + F_singular = true; + *v_pp = (double*)mxMalloc(pp * sizeof(double)); + *v_n = (double*)mxMalloc(n * sizeof(double)); + mf = (int*)mxMalloc(pp * sizeof(int)); for (int i = 0; i < pp; i++) mf[i] = mfd[i] - 1; - double pi = atan2((double)0.0,(double)-1.0); + pi = atan2((double)0.0,(double)-1.0); /*compute QQ = R*Q*transpose(R)*/ // Variance of R times the vector of structural innovations.; // tmp = R * Q; @@ -318,8 +262,8 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } // QQ = tmp * transpose(R) - mxArray* pQQ = mxCreateDoubleMatrix(n, n, mxREAL); - double* QQ = mxGetPr(pQQ); + pQQ = mxCreateDoubleMatrix(n, n, mxREAL); + QQ = mxGetPr(pQQ); for (int i = 0; i < n; i++) for (int j = i; j < n; j++) { @@ -329,112 +273,185 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) QQ[i + j * n] = QQ[j + i * n] = res; } mxDestroyArray(p_tmp1); - - mxArray* pv = mxCreateDoubleMatrix(pp, 1, mxREAL); - double* v = mxGetPr(pv); - mxArray* pF = mxCreateDoubleMatrix(pp, pp, mxREAL); - double* F = mxGetPr(pF); - mxArray* piF = mxCreateDoubleMatrix(pp, pp, mxREAL); - double* iF = mxGetPr(piF); - lapack_int lw = pp * 4; - double* w = (double*)mxMalloc(lw * sizeof(double)); - lapack_int* iw = (lapack_int*)mxMalloc(pp * sizeof(lapack_int)); - lapack_int* ipiv = (lapack_int*)mxMalloc(pp * sizeof(lapack_int)); - lapack_int info = 0; - double rcond; - #ifdef BLAS - mxArray* p_P_t_t1 = mxCreateDoubleMatrix(n, n, mxREAL); - #else - mxArray* p_P_t_t1 = mxCreateDoubleMatrix(n_state, n_state, mxREAL); - #endif - double* P_t_t1 = mxGetPr(p_P_t_t1); - mxArray* pK = mxCreateDoubleMatrix(n, pp, mxREAL); - double* K = mxGetPr(pK); - #ifdef BLAS - mxArray* p_K_P = mxCreateDoubleMatrix(n, n, mxREAL); - #else - mxArray* p_K_P = mxCreateDoubleMatrix(n_state, n_state, mxREAL); - #endif - double* K_P = mxGetPr(p_K_P); - double* oldK = (double*)mxMalloc(n * pp * sizeof(double)); - double* P_mf = (double*)mxMalloc(n * pp * sizeof(double)); - for (int i = 0; i < pp; i++) - oldK[i] = Inf; + pv = mxCreateDoubleMatrix(pp, 1, mxREAL); + v = mxGetPr(pv); + pF = mxCreateDoubleMatrix(pp, pp, mxREAL); + F = mxGetPr(pF); + piF = mxCreateDoubleMatrix(pp, pp, mxREAL); + iF = mxGetPr(piF); + lw = pp * 4; + w = (double*)mxMalloc(lw * sizeof(double)); + iw = (lapack_int*)mxMalloc(pp * sizeof(lapack_int)); + ipiv = (lapack_int*)mxMalloc(pp * sizeof(lapack_int)); + info = 0; + p_P_t_t1 = mxCreateDoubleMatrix(n_state, n_state, mxREAL); + *P_t_t1 = mxGetPr(p_P_t_t1); + pK = mxCreateDoubleMatrix(n, pp, mxREAL); + *K = mxGetPr(pK); + p_K_P = mxCreateDoubleMatrix(n_state, n_state, mxREAL); + *K_P = mxGetPr(p_K_P); + oldK = (double*)mxMalloc(n * pp * sizeof(double)); + *P_mf = (double*)mxMalloc(n * pp * sizeof(double)); + for (int i = 0; i < n * pp; i++) + oldK[i] = Inf; +} + +void +BlockKalmanFilter::block_kalman_filter_ss(double *P_mf, double *v_pp, double *K, double *v_n, double *a, double *K_P, double *P_t_t1, double *tmp, double *P) +{ + if (t+1 < smpl) + { + while (t < smpl) + { + //v = Y(:,t)-a(mf); + for (int i = 0; i < pp; i++) + v[i] = Y[i + t * pp] - a[mf[i]]; + + //a = T*(a+K*v); + for (int i = pure_obs; i < n; i++) + { + double res = 0.0; + for (int j = 0; j < pp; j++) + res += K[j * n + i] * v[j]; + v_n[i] = res + a[i]; + } + for (int i = 0; i < n; i++) + { + double res = 0.0; + for (int j = pure_obs; j < n; j++) + res += T[j * n + i] * v_n[j]; + a[i] = res; + } + + //lik(t) = transpose(v)*iF*v; + for (int i = 0; i < pp; i++) + { + double res = 0.0; + for (int j = 0; j < pp; j++) + res += v[j] * iF[j * pp + i]; + v_pp[i] = res; + } + double res = 0.0; + for (int i = 0; i < pp; i++) + res += v_pp[i] * v[i]; + + lik[t] = (log(dF) + res + pp * log(2.0*pi))/2; + if (t + 1 > start) + LIK += lik[t]; + + t++; + } + } +} + +bool +BlockKalmanFilter::block_kalman_filter(int nlhs, mxArray *plhs[], double *P_mf, double *v_pp, double *K, double *v_n, double *a, double *K_P, double *P_t_t1, double *tmp, double *P) +{ while (notsteady && t < smpl) { - //v = Y(:,t) - a(mf) - for (int i = 0; i < pp; i++) - v[i] = Y[i + t * pp] - a[mf[i]]; - - //F = P(mf,mf) + H; - for (int i = 0; i < pp; i++) - for (int j = 0; j < pp; j++) - iF[i + j * pp] = F[i + j * pp] = P[mf[i] + mf[j] * n] + H[i + j * pp]; + if(missing_observations) + { + + // retrieve the d_index + pd_index = mxGetCell( pdata_index, t); + dd_index = (double*)mxGetData(pd_index); + size_d_index = mxGetM(pd_index); + d_index.resize(size_d_index); + for (int i = 0; i < size_d_index; i++) + { + d_index[i] = ceil(dd_index[i]) - 1; + } + + //v = Y(:,t) - a(mf) + int i_i = 0; + //#pragma omp parallel for shared(v, i_i, d_index) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (vector<int>::const_iterator i = d_index.begin(); i != d_index.end(); i++) + { + //mexPrintf("i_i=%d, omp_get_max_threads()=%d\n",i_i,omp_get_max_threads()); + v[i_i] = Y[*i + t * pp] - a[mf[*i]]; + i_i++; + } + + + //F = P(mf,mf) + H; + i_i = 0; + if (H_size == 1) + { + //#pragma omp parallel for shared(iF, F, i_i) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (vector<int>::const_iterator i = d_index.begin(); i != d_index.end(); i++, i_i++) + { + int j_j = 0; + for (vector<int>::const_iterator j = d_index.begin(); j != d_index.end(); j++, j_j++) + iF[i_i + j_j * size_d_index] = F[i_i + j_j * size_d_index] = P[mf[*i] + mf[*j] * n] + H[0]; + } + } + else + { + //#pragma omp parallel for shared(iF, F, P, H, mf, i_i) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (vector<int>::const_iterator i = d_index.begin(); i != d_index.end(); i++, i_i++) + { + int j_j = 0; + for (vector<int>::const_iterator j = d_index.begin(); j != d_index.end(); j++, j_j++) + iF[i_i + j_j * size_d_index] = F[i_i + j_j * size_d_index] = P[mf[*i] + mf[*j] * n] + H[*i + *j * pp]; + } + } + + } + else + { + size_d_index = pp; + + //v = Y(:,t) - a(mf) + for (int i = 0; i < pp; i++) + v[i] = Y[i + t * pp] - a[mf[i]]; + + //F = P(mf,mf) + H; + if (H_size == 1) + { + for (int i = 0; i < pp; i++) + for (int j = 0; j < pp; j++) + iF[i + j * pp] = F[i + j * pp] = P[mf[i] + mf[j] * n] + H[0]; + } + else + { + for (int i = 0; i < pp; i++) + for (int j = 0; j < pp; j++) + iF[i + j * pp] = F[i + j * pp] = P[mf[i] + mf[j] * n] + H[i + j * pp]; + } + } - /* Computes the norm of x */ - double anorm = dlange("1", &pp, &pp, iF, &pp, w); + + /* Computes the norm of iF */ + double anorm = dlange("1", &size_d_index, &size_d_index, iF, &size_d_index, w); + //mexPrintf("anorm = %f\n",anorm); /* Modifies F in place with a LU decomposition */ - dgetrf(&pp, &pp, iF, &pp, ipiv, &info); + dgetrf(&size_d_index, &size_d_index, iF, &size_d_index, ipiv, &info); if (info != 0) fprintf(stderr, "dgetrf failure with error %d\n", (int) info); /* Computes the reciprocal norm */ - dgecon("1", &pp, iF, &pp, &anorm, &rcond, w, iw, &info); + dgecon("1", &size_d_index, iF, &size_d_index, &anorm, &rcond, w, iw, &info); if (info != 0) fprintf(stderr, "dgecon failure with error %d\n", (int) info); if (rcond < kalman_tol) - if (not_all_abs_F_bellow_crit(F, pp * pp, kalman_tol)) //~all(abs(F(:))<kalman_tol) + if (not_all_abs_F_bellow_crit(F, size_d_index * size_d_index, kalman_tol)) //~all(abs(F(:))<kalman_tol) { mexPrintf("error: F singular\n"); - double LIK = Inf; - // info = 0 - plhs[0] = mxCreateDoubleScalar(0); - if (nlhs >= 2) - { - plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); - double* pind = mxGetPr(plhs[1]); - pind[0] = LIK; - } - + LIK = Inf; if (nlhs == 3) { for (int i = t; i < smpl; i++) lik[i] = Inf; - plhs[2] = plik; } - else - mxDestroyArray(plik); - mxFree(w); -#ifdef DIRECT - mxFree(i_nz_state_var); -#else - mxFree(Var); - mxFree(Var_2); -#endif - mxFree(tmp_a); - mxFree(v_pp); - mxFree(v_n); - mxFree(mf); - mxFree(w); - mxFree(iw); - mxFree(ipiv); - mxFree(oldK); - mxFree(P_mf); - mxDestroyArray(pa); - mxDestroyArray(p_tmp); - mxDestroyArray(pQQ); - mxDestroyArray(pv); - mxDestroyArray(pF); - mxDestroyArray(piF); - mxDestroyArray(p_P_t_t1); - mxDestroyArray(pK); - mxDestroyArray(p_K_P); - return; + // info = 0 + return_results_and_clean(nlhs, plhs, &P_mf, &v_pp, &K, &K_P, &a, &K_P, &P_t_t1, &tmp, &P); + return false; } else { mexPrintf("F singular\n"); + //a = T*a; for (int i = 0; i < n; i++) { @@ -447,57 +464,27 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) //P = T*P*transpose(T)+QQ; memset(tmp, 0, n * n_state * sizeof(double)); -#ifdef DIRECT + for (int i = 0; i < n; i++) for (int j = pure_obs; j < n; j++) { int j1 = j - pure_obs; int j1_n_state = j1 * n_state - pure_obs; - //if ((i < pp) || (i >= n_diag + pp) || (j1 >= n_diag)) - for (int k = pure_obs; k < i_nz_state_var[i]; k++) - { - tmp[i + j1 * n ] += T[i + k * n] * P[k + j1_n_state]; - } + for (int k = pure_obs; k < i_nz_state_var[i]; k++) + tmp[i + j1 * n ] += T[i + k * n] * P[k + j1_n_state]; } - /*for (int i = pp; i < pp + n_diag; i++) - for (int j = pp; j < pp + n_diag; j++) - tmp[i + (j - pp) * n] = T[i + i * n] * P_t_t1[j - pp + (i - pp) * n_state];*/ + memset(P, 0, n * n * sizeof(double)); int n_n_obs = n * pure_obs; for (int i = 0; i < n; i++) for (int j = i; j < n; j++) { - //if ((i < pp) || (i >= n_diag + pp) || (j < pp) || (j >= n_diag + pp)) - for (int k = pure_obs; k < i_nz_state_var[j]; k++) - { - int k_n = k * n; - P[i * n + j] += tmp[i + k_n - n_n_obs] * T[j + k_n]; - } + for (int k = pure_obs; k < i_nz_state_var[j]; k++) + { + int k_n = k * n; + P[i * n + j] += tmp[i + k_n - n_n_obs] * T[j + k_n]; + } } -#else - #pragma omp parallel for shared(T, P_t_t1, tmp, Var) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) - //for (int i = 0; i < n; i++) - for (int j = 0; j < size_index_KF; j++) - { - t_Var *s_Var = &Var[j]; - tmp[s_Var->indx_1 ] += T[s_Var->indx_2] * P[s_Var->indx_3]; - } - for (int i = pp; i < pp + n_diag; i++) - for (int j = pp; j < pp + n_diag; j++) - tmp[i + (j - pp) * n] = T[i + i * n] * P[j + i * n]; - memset(P, 0, n * n * sizeof(double)); - #pragma omp parallel for shared(T, tmp, P, Var_2) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) - //for (int i = 0; i < n; i++) - for (int j = 0; j < size_index_KF_2; j++) - { - t_Var *s_Var = &Var_2[j]; - P[s_Var->indx_1 /*+ i*/] += tmp[s_Var->indx_2 /*+ i*/] * T[s_Var->indx_3]; - } -#endif - /*for (int i = pp; i < pp + n_diag; i++) - for (int j = i; j < pp + n_diag; j++) - P[j + i * n] = T[i + i * n] * T[j + j * n] * P[j + i * n];*/ - //P[j + i * n] = tmp[i +] for ( int i = 0; i < n; i++) { @@ -512,52 +499,72 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) F_singular = false; //dF = det(F); - dF = det(iF, pp, ipiv); + dF = det(iF, size_d_index, ipiv); //iF = inv(F); //int lwork = 4/*2*/* pp; - dgetri(&pp, iF, &pp, ipiv, w, &lw, &info); + dgetri(&size_d_index, iF, &size_d_index, ipiv, w, &lw, &info); if (info != 0) fprintf(stderr, "dgetri failure with error %d\n", (int) info); //lik(t) = log(dF)+transpose(v)*iF*v; - for (int i = 0; i < pp; i++) + #pragma omp parallel for shared(v_pp) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (int i = 0; i < size_d_index; i++) { double res = 0.0; - for (int j = 0; j < pp; j++) - res += v[j] * iF[j * pp + i]; + for (int j = 0; j < size_d_index; j++) + res += v[j] * iF[j * size_d_index + i]; v_pp[i] = res; } double res = 0.0; - for (int i = 0; i < pp; i++) + for (int i = 0; i < size_d_index; i++) res += v_pp[i] * v[i]; - lik[t] = (log(dF) + res + pp * log(2.0*pi))/2; + lik[t] = (log(dF) + res + size_d_index * log(2.0*pi))/2; if (t + 1 >= start) LIK += lik[t]; - //K = P(:,mf)*iF; - for (int i = 0; i < n; i++) - for (int j = 0; j < pp; j++) - P_mf[i + j * n] = P[i + mf[j] * n]; + if (missing_observations) + { + //K = P(:,mf)*iF; + #pragma omp parallel for shared(P_mf) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (int i = 0; i < n; i++) + { + int j_j = 0; + //for (int j = 0; j < pp; j++) + for (vector<int>::const_iterator j = d_index.begin(); j != d_index.end(); j++, j_j++) + P_mf[i + j_j * n] = P[i + mf[*j] * n]; + } + } + else + { + //K = P(:,mf)*iF; + for (int i = 0; i < n; i++) + for (int j = 0; j < pp; j++) + P_mf[i + j * n] = P[i + mf[j] * n]; + } + + #pragma omp parallel for shared(K) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = 0; i < n; i++) - for (int j = 0; j < pp; j++) + for (int j = 0; j < size_d_index; j++) { double res = 0.0; - int j_pp = j * pp; - for (int k = 0; k < pp; k++) + int j_pp = j * size_d_index; + for (int k = 0; k < size_d_index; k++) res += P_mf[i + k * n] * iF[j_pp + k]; K[i + j * n] = res; } - + //a = T*(a+K*v); + #pragma omp parallel for shared(v_n) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = pure_obs; i < n; i++) { double res = 0.0; - for (int j = 0; j < pp; j++) + for (int j = 0; j < size_d_index; j++) res += K[j * n + i] * v[j]; v_n[i] = res + a[i]; } + #pragma omp parallel for shared(a) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = 0; i < n; i++) { double res = 0.0; @@ -565,24 +572,38 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) res += T[j * n + i] * v_n[j]; a[i] = res; } - - //P = T*(P-K*P(mf,:))*transpose(T)+QQ; - for (int i = 0; i < pp; i++) - for (int j = pure_obs; j < n; j++) - P_mf[i + j * pp] = P[mf[i] + j * n]; + + if (missing_observations) + { + //P = T*(P-K*P(mf,:))*transpose(T)+QQ; + int i_i = 0; + //#pragma omp parallel for shared(P_mf) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (vector<int>::const_iterator i = d_index.begin(); i != d_index.end(); i++, i_i++) + for (int j = pure_obs; j < n; j++) + P_mf[i_i + j * size_d_index] = P[mf[*i] + j * n]; + } + else + { + //P = T*(P-K*P(mf,:))*transpose(T)+QQ; + #pragma omp parallel for shared(P_mf) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + for (int i = 0; i < pp; i++) + for (int j = pure_obs; j < n; j++) + P_mf[i + j * pp] = P[mf[i] + j * n]; + } + #ifdef BLAS - #pragma omp parallel for shared(K, P, K_P) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) + #pragma omp parallel for shared(K_P) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = 0; i < n; i++) for (int j = i; j < n; j++) { double res = 0.0; //int j_pp = j * pp; - for (int k = 0; k < pp; k++) - res += K[i + k * n] * P_mf[k + j * pp]; + for (int k = 0; k < size_d_index; k++) + res += K[i + k * n] * P_mf[k + j * size_d_index]; K_P[i * n + j] = K_P[j * n + i] = res; } //#pragma omp parallel for shared(P, K_P, P_t_t1) - for (int i = pp; i < n; i++) + for (int i = size_d_index; i < n; i++) for (int j = i; j < n; j++) { unsigned int k = i * n + j; @@ -599,11 +620,8 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) &n, &one, tmp, &n, T, &n, &one, P, &n); - mexPrintf("P\n"); - mexDisp(pP); #else - //#pragma omp parallel for shared(K, P, K_P) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) - + #pragma omp parallel for shared(K_P) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = pure_obs; i < n; i++) { unsigned int i1 = i - pure_obs; @@ -611,32 +629,14 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { unsigned int j1 = j - pure_obs; double res = 0.0; - int j_pp = j * pp; - for (int k = 0; k < pp; k++) + int j_pp = j * size_d_index; + for (int k = 0; k < size_d_index; k++) res += K[i + k * n] * P_mf[k + j_pp]; K_P[i1 * n_state + j1] = K_P[j1 * n_state + i1] = res; } } - /*for (int j = pp; j < n; j++) - { - unsigned int j1 = j - pp; - double res = P[mf[j] + j * n] - for (int i = 0; i < n; i++) - { - unsigned int i1 = i - pp; - K_P[i1 * n_state + j1] = res * K[i + j * n]; - } - for (int i = pp; i < n; i++) - { - unsigned int i1 = i - pp; - double res = 0.0; - for (int k = 0; k < pp; k++) - res += K[i + k * n] * P[mf[k] + j * n]; - K_P[i1 * n_state + j1] = K_P[j1 * n_state + i1] = res; - } - }*/ - - //#pragma omp parallel for shared(P, K_P, P_t_t1) + + #pragma omp parallel for shared(P_t_t1) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = pure_obs; i < n; i++) { unsigned int i1 = i - pure_obs; @@ -647,9 +647,10 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) P_t_t1[j1 * n_state + i1] = P_t_t1[k1] = P[i * n + j] - K_P[k1]; } } - + memset(tmp, 0, n * n_state * sizeof(double)); -#ifdef DIRECT + + #pragma omp parallel for shared(tmp) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = 0; i < n; i++) { int max_k = i_nz_state_var[i]; @@ -658,21 +659,21 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) int j1 = j - pure_obs; int j1_n_state = j1 * n_state - pure_obs; int indx_tmp = i + j1 * n ; - //if ((i < pp) || (i >= n_diag + pp) || (j1 >= n_diag)) - for (int k = pp; k < max_k; k++) + for (int k = pure_obs; k < max_k; k++) tmp[indx_tmp] += T[i + k * n] * P_t_t1[k + j1_n_state]; } } + memset(P, 0, n * n * sizeof(double)); - + + int n_n_obs = - n * pure_obs; + #pragma omp parallel for shared(P) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for (int i = 0; i < n; i++) { - int n_n_obs = - n * pure_obs; for (int j = i; j < n; j++) { int max_k = i_nz_state_var[j]; int P_indx = i * n + j; - //if ((i < pp) || (i >= n_diag + pp) || (j < pp) || (j >= n_diag + pp)) for (int k = pure_obs; k < max_k; k++) { int k_n = k * n; @@ -680,24 +681,8 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } } } -#else - //#pragma omp parallel for shared(T, P_t_t1, tmp, Var) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) - for (int j = 0; j < size_index_KF; j++) - { - t_Var *s_Var = &Var[j]; - tmp[s_Var->indx_1 ] += T[s_Var->indx_2 ] * P_t_t1[s_Var->indx_3]; - } - for (int i = pp; i < pp + n_diag; i++) - for (int j = pp; j < pp + n_diag; j++) - tmp[i + (j - pp) * n] = T[i + i * n] * P_t_t1[j - pp + (i - pp) * n_state]; - memset(P, 0, n * n * sizeof(double)); - //#pragma omp parallel for shared(T, tmp, P, Var_2) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) - for (int j = 0; j < size_index_KF_2; j++) - { - t_Var *s_Var = &Var_2[j]; - P[s_Var->indx_1 /*+ i*/] += tmp[s_Var->indx_2 /*+ i*/] * T[s_Var->indx_3]; - } -#endif + + #pragma omp parallel for shared(P) num_threads(atoi(getenv("DYNARE_NUM_THREADS"))) for ( int i = 0; i < n; i++) { for ( int j = i ; j < n; j++) @@ -706,72 +691,39 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) P[i + j * n] = P[j + i * n]; } #endif - //notsteady = max(abs(K(:)-oldK)) > riccati_tol; - double max_abs = 0.0; - for (int i = 0; i < n * pp; i++) + + if (t >= no_more_missing_observations) { - double res = abs(K[i] - oldK[i]); - if (res > max_abs) - max_abs = res; - } - notsteady = max_abs > riccati_tol; + double max_abs = 0.0; + for (int i = 0; i < n * size_d_index; i++) + { + double res = abs(K[i] - oldK[i]); + if (res > max_abs) + max_abs = res; + } + notsteady = max_abs > riccati_tol; - //oldK = K(:); - memcpy(oldK, K, n * pp * sizeof(double)); + //oldK = K(:); + + memcpy(oldK, K, n * pp * sizeof(double)); + } } t++; } if (F_singular) mexErrMsgTxt("The variance of the forecast error remains singular until the end of the sample\n"); + if (t < smpl) + block_kalman_filter_ss(P_mf, v_pp, K, K_P, a, K_P, P_t_t1, tmp, P); + return true; +} - if (t+1 < smpl) - { - while (t < smpl) - { - //v = Y(:,t)-a(mf); - for (int i = 0; i < pp; i++) - v[i] = Y[i + t * pp] - a[mf[i]]; - - //a = T*(a+K*v); - for (int i = pure_obs; i < n; i++) - { - double res = 0.0; - for (int j = 0; j < pp; j++) - res += K[j * n + i] * v[j]; - v_n[i] = res + a[i]; - } - for (int i = 0; i < n; i++) - { - double res = 0.0; - for (int j = pure_obs; j < n; j++) - res += T[j * n + i] * v_n[j]; - a[i] = res; - } - - //lik(t) = transpose(v)*iF*v; - for (int i = 0; i < pp; i++) - { - double res = 0.0; - for (int j = 0; j < pp; j++) - res += v[j] * iF[j * pp + i]; - v_pp[i] = res; - } - double res = 0.0; - for (int i = 0; i < pp; i++) - res += v_pp[i] * v[i]; - - lik[t] = (log(dF) + res + pp * log(2.0*pi))/2; - if (t + 1 > start) - LIK += lik[t]; - t++; - } - } - - // info = 0 +void +BlockKalmanFilter::return_results_and_clean(int nlhs, mxArray *plhs[], double *P_mf[], double *v_pp[], double *K[], double *v_n[], double *a[], double *K_P[], double *P_t_t1[], double *tmp[], double *P[]) +{ plhs[0] = mxCreateDoubleScalar(0); - + if (nlhs >= 2) { plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); @@ -783,23 +735,18 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) plhs[2] = plik; else mxDestroyArray(plik); - + mxFree(w); -#ifdef DIRECT mxFree(i_nz_state_var); -#else - mxFree(Var); - mxFree(Var_2); -#endif mxFree(tmp_a); - mxFree(v_pp); - mxFree(v_n); + //mxFree(v_pp); + //mxFree(v_n); mxFree(mf); - mxFree(w); mxFree(iw); mxFree(ipiv); mxFree(oldK); - mxFree(P_mf); + //mxFree(P_mf); + mxDestroyArray(pa); mxDestroyArray(p_tmp); mxDestroyArray(pQQ); @@ -811,3 +758,12 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mxDestroyArray(p_K_P); } +void +mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + double *P_mf, * v_pp, *v_n, *a, *K, *K_P, *P_t_t1, *tmp, *P; + BlockKalmanFilter block_kalman_filter(nlhs, plhs, nrhs, prhs, &P_mf, &v_pp, &K, &v_n, &a, &K_P, &P_t_t1, &tmp, &P); + if (block_kalman_filter.block_kalman_filter(nlhs, plhs, P_mf, v_pp, K, K_P, a, K_P, P_t_t1, tmp, P)) + block_kalman_filter.return_results_and_clean(nlhs, plhs, &P_mf, &v_pp, &K, &K_P, &a, &K_P, &P_t_t1, &tmp, &P); +} + diff --git a/mex/sources/block_kalman_filter/block_kalman_filter.h b/mex/sources/block_kalman_filter/block_kalman_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..99f23ef9285b5380dbc56feb603272c4293a2bb8 --- /dev/null +++ b/mex/sources/block_kalman_filter/block_kalman_filter.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2011 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef BLOCK_KALMAN_FILTER +#define BLOCK_KALMAN_FILTER + +#ifndef DEBUG_EX +# include <dynmex.h> +#else +# include "mex_interface.hh" +#endif + +#include <dynblas.h> +#include <dynlapack.h> +using namespace std; + +class BlockKalmanFilter +{ + public: + mxArray *pT , *pR, *pQ, *pH, *pP, *pY, *pQQ, *pv, *pF, *piF, *p_P_t_t1, *pK, *p_K_P; + double *T , *R, *Q , *H, *Y, *mfd, *QQ, *v, *F, *iF; + int start, pure_obs, smpl, n, n_state, n_shocks, H_size; + double kalman_tol, riccati_tol, dF, LIK, Inf, pi; + lapack_int pp, lw, info; + + double* nz_state_var; + int *i_nz_state_var, *mf; + int n_diag, t; + mxArray *M_; + mxArray* pa, *p_tmp, *p_tmp1, *plik; + double *tmp_a, *tmp1, *lik, *v_n, *w, *oldK; + bool notsteady, F_singular, missing_observations; + lapack_int *iw, *ipiv; + double anorm, rcond; + int size_d_index, no_more_missing_observations, number_of_observations; + const mxArray* pdata_index; + vector<int> d_index; + const mxArray* pd_index; + double* dd_index; + + public: + BlockKalmanFilter(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[], double *P_mf[], double *v_pp[], double *K[], double *v_n[], double *a[], double *K_P[], double *P_t_t1[], double *tmp[], double *P[]); + bool block_kalman_filter(int nlhs, mxArray *plhs[], double *P_mf, double *v_pp, double *K, double *v_n, double *a, double *K_P, double *P_t_t1, double *tmp, double *P); + void block_kalman_filter_ss(double *P_mf, double *v_pp, double *K, double *v_n, double *a, double *K_P, double *P_t_t1, double *tmp, double *P); + void return_results_and_clean(int nlhs, mxArray *plhs[], double *P_mf[], double *v_pp[], double *K[], double *v_n[], double *a[], double *K_P[], double *P_t_t1[], double *tmp[], double *P[]); +}; +#endif