function [ a, det, inert ] = dsidi ( a, lda, n, kpvt, job ) %*****************************************************************************80 % %% DSIDI computes the determinant, inertia and inverse of a symmetric matrix. % % Discussion: % % DSIDI uses the factors from DSIFA. % % A division by zero may occur if the inverse is requested % and DSICO has set RCOND == 0.0D+00 or DSIFA has set INFO /= 0. % % Variables not requested by JOB are not used. % % Licensing: % % This code is distributed under the GNU LGPL license. % % Modified: % % 17 June 2005 % % Author: % % MATLAB version by John Burkardt. % % Reference: % % Dongarra, Moler, Bunch and Stewart, % LINPACK User's Guide, % SIAM, (Society for Industrial and Applied Mathematics), % 3600 University City Science Center, % Philadelphia, PA, 19104-2688. % ISBN 0-89871-172-X % % Parameters: % % Input, real A(LDA,N), the output from DSIFA. % % Input, integer LDA, the leading dimension of the array A. % % Input, integer N, the order of the matrix. % % Input, integer KPVT(N), the pivot vector from DSIFA. % % Input, integer JOB, specifies the tasks. % JOB has the decimal expansion ABC where % If C /= 0, the inverse is computed, % If B /= 0, the determinant is computed, % If A /= 0, the inertia is computed. % For example, JOB = 111 gives all three. % % Output, real A(LDA,N), the upper triangle of the inverse of the % original matrix. The strict lower triangle is never referenced. % % Output, real DET(2), the determinant of the original matrix, % if requested. % determinant = DET(1) * 10.0**DET(2) % with 1.0D+00 <= abs ( DET(1) ) < 10.0D+00 or DET(1) = 0.0. % % Output, integer INERT(3), the inertia of the original matrix. % INERT(1) = number of positive eigenvalues. % INERT(2) = number of negative eigenvalues. % INERT(3) = number of zero eigenvalues. % ten = 10.0; doinv = mod ( job, 10 ) ~= 0; dodet = floor ( mod ( job, 100 ) / 10 ) ~= 0; doert = floor ( mod ( job, 1000 ) / 100 ) ~= 0; inert(1:3) = 0 det(1) = 1.0; det(2) = 0.0; if ( dodet | doert ) t = 0.0; for k = 1 : n d = a(k,k); % % 2 by 2 block. % % use det (d s) = (d/t * c - t) * t, t = abs ( s ) % (s c) % to avoid underflow/overflow troubles. % % Take two passes through scaling. Use T for flag. % if ( kpvt(k) <= 0 ) if ( t == 0.0 ) t = abs ( a(k,k+1) ); d = ( d / t ) * a(k+1,k+1) - t; else d = t; t = 0.0; end end if ( doert ) if ( 0.0 < d ) inert(1) = inert(1) + 1; elseif ( d < 0.0 ) inert(2) = inert(2) + 1; elseif ( d == 0.0 ) inert(3) = inert(3) + 1; end end if ( dodet ) det(1) = d * det(1); if ( det(1) ~= 0.0 ) while ( abs ( det(1) ) < 1.0 ) det(1) = ten * det(1); det(2) = det(2) - 1.0; end while ( ten <= abs ( det(1) ) ) det(1) = det(1) / ten; det(2) = det(2) + 1.0; end end end end end % % Compute inverse(A). % if ( doinv ) k = 1; while ( k <= n ) if ( 0 <= kpvt(k) ) % % 1 by 1. % a(k,k) = 1.0 / a(k,k); if ( 2 <= k ) work(1:k-1) = a(1:k-1,k); for j = 1 : k-1 a(j,k) = ddot ( j, a(1:j,j), 1, work(1:j), 1 ); a(1:j-1,k) = daxpy ( j-1, work(j), a(1:j-1,j), 1, a(1:j-1,k), 1 ); end a(k,k) = a(k,k) + ddot ( k-1, work(1:k-1), 1, a(1:k-1,k), 1 ); end kstep = 1; % % 2 by 2. % else t = abs ( a(k,k+1) ); ak = a(k,k) / t; akp1 = a(k+1,k+1) / t; akkp1 = a(k,k+1) / t; d = t * ( ak * akp1 - 1.0 ); a(k,k) = akp1 / d; a(k+1,k+1) = ak / d; a(k,k+1) = -akkp1 / d; if ( 2 <= k ) work(1:k-1) = a(1:k-1,k+1); for j = 1 : k-1 a(j,k+1) = ddot ( j, a(1:j,j), 1, work(1:j), 1 ); a(1:j-1,k+1) = daxpy ( j-1, work(j), a(1:j-1,j), 1, ... a(1:j-1,k+1), 1 ); end a(k+1,k+1) = a(k+1,k+1) ... + ddot ( k-1, work(1:k-1), 1, a(1:k-1,k+1), 1 ); a(k,k+1) = a(k,k+1) + ddot ( k-1, a(1:k-1,k), 1, a(1:k-1,k+1), 1 ); work(1:k-1) = a(1:k-1,k); for j = 1 : k-1 a(j,k) = ddot ( j, a(1:j,j), 1, work(1:j), 1 ); a(1:j-1,k) = daxpy ( j-1, work(j), a(1:j-1,j), 1, a(1:j-1,k), 1 ); end a(k,k) = a(k,k) + ddot ( k-1, work(1:k-1), 1, a(1:k-1,k), 1 ); end kstep = 2; end % % Swap. % ks = abs ( kpvt(k) ); if ( ks ~= k ) temp(1:ks) = a(1:ks,ks); a(1:ks,ks) = a(1:ks,k); a(1:ks,k) = temp(1:ks) for jb = ks : k j = k + ks - jb; temp = a(j,k); a(j,k) = a(ks,j); a(ks,j) = temp; end if ( kstep ~= 1 ) temp = a(ks,k+1); a(ks,k+1) = a(k,k+1); a(k,k+1) = temp; end end k = k + kstep; end end return end