spm_logdet.m 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. function H = spm_logdet(C)
  2. % Compute the log of the determinant of positive (semi-)definite matrix C
  3. % FORMAT H = spm_logdet(C)
  4. % H = log(det(C))
  5. %
  6. % spm_logdet is a computationally efficient operator that can deal with
  7. % full or sparse matrices. For non-positive definite cases, the determinant
  8. % is considered to be the product of the positive singular values.
  9. %__________________________________________________________________________
  10. % Copyright (C) 2008-2013 Wellcome Trust Centre for Neuroimaging
  11. % Karl Friston and Ged Ridgway
  12. % $Id: spm_logdet.m 6321 2015-01-28 14:40:44Z karl $
  13. % Note that whether sparse or full, rank deficient cases are handled in the
  14. % same way as in spm_logdet revision 4068, using svd on a full version of C
  15. % remove null variances
  16. %--------------------------------------------------------------------------
  17. i = find(diag(C));
  18. C = C(i,i);
  19. [i,j,s] = find(C);
  20. if any(isnan(s)), H = nan; return; end
  21. % TOL = max(size(C)) * eps(max(s)); % as in MATLAB's rank function
  22. %--------------------------------------------------------------------------
  23. TOL = 1e-16;
  24. if any(i ~= j)
  25. % assymetric matrix
  26. %------------------------------------------------------------------
  27. if norm(spm_vec(C - C'),inf) > TOL
  28. s = svd(full(C));
  29. else
  30. % non-diagonal sparse matrix
  31. %------------------------------------------------------------------
  32. if issparse(C)
  33. % Note p is unused but requesting it can make L sparser
  34. %--------------------------------------------------------------
  35. [L,nondef,p] = chol(C, 'lower', 'vector');
  36. if ~nondef
  37. % pos. def. with Cholesky decomp L, and det(C) = det(L)^2
  38. %----------------------------------------------------------
  39. H = 2*sum(log(full(diag(L))));
  40. return
  41. end
  42. s = svd(full(C));
  43. else
  44. % non-diagonal full matrix
  45. %--------------------------------------------------------------
  46. try
  47. R = chol(C);
  48. H = 2*sum(log(diag(R)));
  49. return
  50. catch
  51. s = svd(C);
  52. end
  53. end
  54. end
  55. end
  56. % if still here, singular values in s (diagonal values as a special case)
  57. %--------------------------------------------------------------------------
  58. H = sum(log(s(s > TOL & s < 1/TOL)));