spm_mldivide.m 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. function D = spm_mldivide(A, B)
  2. % Regularised variant of mldivide(A, B) or A \ B, similar to spm_inv(A) * B
  3. % FORMAT D = spm_mldivide(A, B)
  4. %
  5. % D = inv(A) * B, or if A is near singular D = inv(A + TOL*eye(size(A)) * B
  6. %
  7. % where TOL is adaptively increased if necessary.
  8. %
  9. % This function should be preferable to spm_inv(A) * B if A is large and
  10. % sparse or if B has few columns, since the inverse need not be explicitly
  11. % computed (the linear system can be solved with the backslash operator).
  12. %
  13. % See also: spm_mrdivide
  14. %__________________________________________________________________________
  15. % Copyright (C) 2011 Wellcome Trust Centre for Neuroimaging
  16. % Ged Ridgway
  17. % $Id: spm_mldivide.m 5219 2013-01-29 17:07:07Z spm $
  18. % A problem with this (and with original spm_inv) is that negative definite
  19. % matrices (or those with mixed positive and negative eigenvalues) will not
  20. % be sensibly regularised by adding a scaled identity. However, it is both
  21. % expensive to compute the eigenvalues and also difficult to find a general
  22. % strategy to handle a mixed-sign set of eigenvalues.
  23. % Stop warning being displayed, but clear lastwarn so can observe occurence
  24. sw = warning('off', 'MATLAB:nearlySingularMatrix');
  25. lastwarn('');
  26. D = A \ B;
  27. if ~isempty(lastwarn)
  28. % Warning would have occurred, but was turned off, try regularising,
  29. % starting with low TOL and increasing if required...
  30. [m,n] = size(A);
  31. TOL = max(eps(norm(A, 'inf')) * max(m, n), exp(-32));
  32. while ~isempty(lastwarn)
  33. lastwarn('');
  34. D = (A + TOL * speye(m, n)) \ B;
  35. % ...increase regularisation in case warning obtained again...
  36. TOL = TOL * 100;
  37. end
  38. end
  39. warning(sw);