GMMB_COVFIXER - force matrix to be a valid covariance matrix covmatrix = GMMB_COVFIXER(matrix) Matrix is forced (complex conjugate) symmetric, positive definite and its diagonal real valued. [covmatrix, loops] = GMMB_COVFIXER(...) loops - number of rounds the positive definite fixer had to run. [covmatrix, loops, symerr] = GMMB_COVFIXER(...) symerr - symmetry error matrix
0001 %GMMB_COVFIXER - force matrix to be a valid covariance matrix 0002 % 0003 % covmatrix = GMMB_COVFIXER(matrix) 0004 % Matrix is forced (complex conjugate) symmetric, 0005 % positive definite and its diagonal real valued. 0006 % 0007 % [covmatrix, loops] = GMMB_COVFIXER(...) 0008 % loops - number of rounds the positive definite fixer had to run. 0009 % 0010 % [covmatrix, loops, symerr] = GMMB_COVFIXER(...) 0011 % symerr - symmetry error matrix 0012 0013 % 0014 % $Name: $ 0015 % $Id: gmmb_covfixer.m,v 1.2 2004/11/02 09:00:18 paalanen Exp $ 0016 % Copyright 2003, Pekka Paalanen <pekka.paalanen@lut.fi> 0017 0018 % except isspd() function which is from The MathWorks Matlab mvnpdf.m. 0019 0020 function [nsigma, varargout] = gmmb_covfixer(sigma); 0021 0022 D = size(sigma, 1); 0023 fixrate = 0.01; 0024 covfixmat = ones(D) + fixrate*eye(D); 0025 loops = 0; 0026 min_limit = eps*10; 0027 0028 if ~all( isfinite(sigma(:)) ) 0029 error('covariance matrix is not finite'); 0030 end 0031 0032 % Running imagfixer is not counted as covariance fixing, 0033 % the changes are assumed to be so small. 0034 nsigma = imagfixer(sigma); 0035 0036 if nargout>2 0037 varargout(2) = {(sigma-nsigma)}; 0038 end 0039 0040 while isspd(nsigma) == 0 0041 % covariance matrix is not positive definite 0042 % fix it 0043 loops = loops+1; 0044 d = diag(nsigma); 0045 if any(d <= min_limit) 0046 % negative or zero (<eps) on the diagonal 0047 m = max(abs(d)) * fixrate; 0048 neg = min(d); 0049 if neg < 0 0050 % there is a negative component on the diagonal 0051 % get rid of it. 0052 addit = (m-neg)*eye(D); 0053 else 0054 if m < min_limit 0055 m = min_limit; 0056 end 0057 addit = m*eye(D); 0058 end 0059 nsigma = nsigma + addit; 0060 else 0061 % increase diagonal values by 1 percent 0062 nsigma = nsigma .* covfixmat; 0063 end 0064 end 0065 0066 if nargout>1 0067 varargout(1) = {loops}; 0068 end 0069 0070 0071 % ------------------ 0072 0073 function [t,R] = isspd(Sigma) 0074 %ISPDS Test if a matrix is positive definite symmetric 0075 % T = ISPDS(SIGMA) returns a logical indicating whether the matrix SIGMA is 0076 % square, symmetric, and positive definite, i.e., it is a valid full rank 0077 % covariance matrix. 0078 % 0079 % [T,R] = ISPDS(SIGMA) returns the cholesky factor of SIGMA in R. If SIGMA 0080 % is not square symmetric, ISPDS returns [] in R. 0081 0082 % Copyright 1993-2002 The MathWorks, Inc. 0083 % Revision: 1.2 Date: 2002/03/28 16:51:27 0084 0085 % Test for square, symmetric 0086 % NOTE: imagfixer already enforces squareness and symmetricity, 0087 % and fixing affects only the diagonal, so this is not necessary 0088 %[n,m] = size(Sigma); 0089 %if (n == m) & all(all(abs(Sigma - Sigma') < 10*eps*max(abs(diag(Sigma))))); 0090 0091 % Test for positive definiteness 0092 [R,p] = chol(Sigma); 0093 if p == 0 0094 t = 1; 0095 else 0096 t = 0; 0097 end 0098 0099 %else 0100 % R = []; 0101 % t = 0; 0102 %end 0103 0104 % ------------------ 0105 0106 function nsigma = imagfixer(sigma); 0107 0108 % force symmetric 0109 nsigma = sigma - (sigma - sigma')/2; 0110 % purge imag 0111 purge = imag(diag(nsigma)); 0112 nsigma = nsigma - diag(purge)*1i; 0113 0114 if max(purge) > 1e-4 0115 warning_wrap('gmmbayes:covfixer:imagfixer', 'Quite big imaginary components removed from the diagonal'); 0116 end