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