1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- function H = spm_logdet(C)
- % Compute the log of the determinant of positive (semi-)definite matrix C
- % FORMAT H = spm_logdet(C)
- % H = log(det(C))
- %
- % spm_logdet is a computationally efficient operator that can deal with
- % full or sparse matrices. For non-positive definite cases, the determinant
- % is considered to be the product of the positive singular values.
- %__________________________________________________________________________
- % Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging
- % Karl Friston and Ged Ridgway
- % $Id: spm_logdet.m 6321 2015-01-28 14:40:44Z karl $
- % Note that whether sparse or full, rank deficient cases are handled in the
- % same way as in spm_logdet revision 4068, using svd on a full version of C
- % remove null variances
- %--------------------------------------------------------------------------
- i = find(diag(C));
- C = C(i,i);
- [i,j,s] = find(C);
- if any(isnan(s)), H = nan; return; end
- % TOL = max(size(C)) * eps(max(s)); % as in MATLAB's rank function
- %--------------------------------------------------------------------------
- TOL = 1e-16;
- if any(i ~= j)
-
- % assymetric matrix
- %------------------------------------------------------------------
- if norm(spm_vec(C - C'),inf) > TOL
-
- s = svd(full(C));
-
- else
-
- % non-diagonal sparse matrix
- %------------------------------------------------------------------
- if issparse(C)
-
- % Note p is unused but requesting it can make L sparser
- %--------------------------------------------------------------
- [L,nondef,p] = chol(C, 'lower', 'vector');
- if ~nondef
-
- % pos. def. with Cholesky decomp L, and det(C) = det(L)^2
- %----------------------------------------------------------
- H = 2*sum(log(full(diag(L))));
- return
-
- end
- s = svd(full(C));
-
- else
-
- % non-diagonal full matrix
- %--------------------------------------------------------------
- try
- R = chol(C);
- H = 2*sum(log(diag(R)));
- return
- catch
- s = svd(C);
- end
- end
- end
- end
- % if still here, singular values in s (diagonal values as a special case)
- %--------------------------------------------------------------------------
- H = sum(log(s(s > TOL & s < 1/TOL)));
|