spm_svd.m 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. function [U,S,V] = spm_svd(X,U)
  2. % Computationally efficient SVD (that can handle sparse arguments)
  3. % FORMAT [U,S,V] = spm_svd(X,u)
  4. % X - (m x n) matrix
  5. % u - threshold (1 > u > 0) for normalized eigenvalues (default = 1e-6)
  6. % - a value of zero induces u = 64*eps
  7. %
  8. % U - {m x p} singular vectors
  9. % V - {m x p} singular variates
  10. % S - {p x p} singular values
  11. %__________________________________________________________________________
  12. % Copyright (C) 1994-2011 Wellcome Trust Centre for Neuroimaging
  13. % Karl Friston
  14. % $Id: spm_svd.m 6110 2014-07-21 09:36:13Z karl $
  15. % default thresholds - preclude singular vectors with small singular values
  16. %--------------------------------------------------------------------------
  17. if nargin < 2, U = 1e-6; end
  18. if U >= 1; U = U - 1e-6; end
  19. if U <= 0; U = 64*eps; end
  20. % deal with sparse matrices
  21. %--------------------------------------------------------------------------
  22. [M,N] = size(X);
  23. p = find(any(X,2));
  24. q = find(any(X,1));
  25. X = X(p,q);
  26. % SVD
  27. %--------------------------------------------------------------------------
  28. [i, j, s] = find(X);
  29. [m, n] = size(X);
  30. if any(i - j)
  31. % off-leading diagonal elements - full SVD
  32. %----------------------------------------------------------------------
  33. X = full(X);
  34. if m > n
  35. [v, S, v] = svd(X'*X,0);
  36. S = sparse(S);
  37. s = diag(S);
  38. j = find(s*length(s)/sum(s) > U);
  39. v = v(:,j);
  40. u = spm_en(X*v);
  41. S = sqrt(S(j,j));
  42. elseif m < n
  43. [u, S, u] = svd(X*X',0);
  44. S = sparse(S);
  45. s = diag(S);
  46. j = find(s*length(s)/sum(s) > U);
  47. u = u(:,j);
  48. v = spm_en(X'*u);
  49. S = sqrt(S(j,j));
  50. else
  51. [u, S, v] = svd(X,0);
  52. S = sparse(S);
  53. s = diag(S).^2;
  54. j = find(s*length(s)/sum(s) > U);
  55. v = v(:,j);
  56. u = u(:,j);
  57. S = S(j,j);
  58. end
  59. else
  60. S = sparse(1:n,1:n,s,m,n);
  61. u = speye(m,n);
  62. v = speye(m,n);
  63. [i, j] = sort(-s);
  64. S = S(j,j);
  65. v = v(:,j);
  66. u = u(:,j);
  67. s = diag(S).^2;
  68. j = find(s*length(s)/sum(s) > U);
  69. v = v(:,j);
  70. u = u(:,j);
  71. S = S(j,j);
  72. end
  73. % replace in full matrices
  74. %--------------------------------------------------------------------------
  75. j = length(j);
  76. U = sparse(M,j);
  77. V = sparse(N,j);
  78. if j
  79. U(p,:) = u;
  80. V(q,:) = v;
  81. end