function varargout = ahbeigs(varargin) % % AHBEIGS: will find a few eigenvalues and eigenvectors for either the % standard eigenvalue problem A*x = lambda*x or the generalized eigenvalue % problem A*x = lambda*B*x. % % [V,D,FLAG] = AHBEIGS(A,OPTIONS) % [V,D,FLAG] = AHBEIGS(A,B,OPTIONS) % [V,D,FLAG] = AHBEIGS('Afunc',N,B,OPTIONS) % % The first input argument must be a matrix A which can be passed as a numeric % matrix or as a M-file ('Afunc') that computes the product A*X or inv(B)*A*X, % where X is a (N x blsz) matrix. If A is passed as a M-file then the second % input argument N is the size of the matrix A. For the generalized eigenvalue % problem the matrix B is passed only as a numeric matrix. If a linear solver is % required then use the M-file ('Afunc') and compute inv(B)*A*X. In all the % implementations AHBEIGS(A,...) can be replaced with AHBEIGS('Afunc',N,...). % % The function 'Afunc' must be a M-file. The (N x blsz) matrix X is the first % input argument, the second input argument is N, (the size of the matrix A), % and the third input argument is blsz, i.e. Afunc(X,N,blsz). The output is % the (N x blsz) matrix Y where, Y = A*X or Y = inv(B)*A*X. % % OUTPUT OPTIONS: % --------------- % % I.) AHBEIGS(A) or AHBEIGS(A,B) % Displays the desired eigenvalues. % % II.) D = AHBEIGS(A) or D = AHBEIGS(A,B) % Returns the desired eigenvalues in the vector D. % % III.) [V,D] = AHBEIGS(A) or [V,D] = AHBEIGS(A,B) % D is a diagonal matrix that contains the desired eigenvalues along the % diagonal and the matrix V contains the corresponding eigenvectors, such % that A*V = V*D or A*V = B*V*D. If AHBEIGS reaches the maximum number of % iterations before convergence then the matrices V and D contain any % eigenpairs that have converged plus the last Ritz pair approximations % for the eigenpairs that have not converged. % % IV.) [V,D,FLAG] = AHBEIGS(A) or [V,D,FLAG] = AHBEIGS(A,B) % This option returns the same as (III) plus a two dimensional array FLAG % that reports if the algorithm converges and the number of matrix vector % products. If FLAG(1) = 0 this implies normal return, all eigenvalues have % converged. If FLAG(1) = 1 then the maximum number of iterations have been % reached before all desired eigenvalues have converged. FLAG(2) contains the % number of matrix vector products used by the code. If the maximum number of % iterations are reached then the matrices V and D contain any eigenpairs % that have converged plus the last Ritz pair approximations for the eigenpairs % that have not converged. % % INPUT OPTIONS: % -------------- % % ... = AHBEIGS(A,OPTS) or ... = AHBEIGS(A,B,OPTS) % OPTS is a structure containing input parameters. The input parameters can % be given in any order. The structure OPTS may contain some or all of the % following input parameters. The string for the input parameters can contain % upper or lower case characters. % % INPUT PARAMETER DESCRIPTION % % OPTS.ADJUST Initial number of vectors to add to the K restart vectors. After % vectors start to converge more vectors are added to help increase % convergence. Should be set so that K + ADJUST is a multiple of BLSZ. % DEFAULT VALUE OPTS.ADJUST = 3 % % OPTS.BLSZ Block size of the Arnoldi Hessenberg matrix. % DEFAULT VALUE BLSZ = 3 % % OPTS.CHOLB Indicates if the Cholesky factorization of the matrix B is available. % If the Cholesky factorization matrix R is available then set % CHOLB = 1 and replace the input matrix B with R where B = R'*R. % DEFAULT VALUE CHOLB = 0 % % OPTS.DISPR Indicates if K Ritz values and residuals are to be displayed on each % iteration. Set positive to display the Ritz values and residuals on % each iteration. % DEFAULT VALUE DISPR = 0 % % OPTS.PERMB Permutation vector for the Cholesky factorization of B(PERMB,PERMB). % When the input matrix B is replaced with R where B(PERMB,PERMB)=R'*R % then the vector PERMB is the permutation vector. % DEFAULT VALUE PERMB=1:N % % OPTS.K Number of desired eigenvalues. % DEFAULT VALUE K = 6 % % OPTS.MAXIT Maximum number of iterations, i.e. maximum number of restarts. % DEFAULT VALUE MAXIT = 100 % % OPTS.NBLS Number of blocks in the Arnoldi Hessenberg matrix. If number of % blocks is not sufficiently large enough then AHBEIGS will not % converge or miss some desired eigenvalues. % DEFAULT VALUE NBLS = 10 % % OPTS.SIGMA Two letter string or numeric value specifying the location % of the desired eigenvalues. % 'LM' or 'SM' Largest or Smallest Magnitude % 'LR' or 'SR' Largest or Smallest Real part % 'LI' or 'SI' Largest or Smallest Imaginary part % 'LA' or 'SA' Largest or Smallest Algebraic (Symmetric Problems only) % NVAL A numeric value. The program searches for the K closest % eigenvalues to the numeric value NVAL. (Program will factor % the matrix. This will increase storage requirements.) % DEFAULT VALUE SIGMA = 'LM' % % OPTS.TOL Tolerance used for convergence. Convergence is determined when % || Ax - lambda*x ||_2 <= TOL*max(abs(Ritz)). % DEFAULT VALUE TOL = 1d-6 % % OPTS.V0 A matrix of starting vectors. % DEFAULT VALUE V0 = randn % % DATE: 6/15/2005 % VER: 1.0 % AUTHOR: % James Baglama % Department of Mathematics % University of Rhode Island % Kingston, Rhode Island 02881 % E-Mail: jbaglama@math.uri.edu % % % Research supported by NSF grant DMS-0311786. % % Too many output arguments requested. if (nargout >= 4) error('ERROR: Too many output arguments.'); end %----------------------------% % BEGIN: PARSE INPUT VALUES. % %----------------------------% % No input arguments, return help. if nargin == 0, help ahbeigs, return, end % Get matrix A. Check type (numeric or character) and dimensions. if (isstruct(varargin{1})), error('A must be a matrix.'); end A = varargin{1}; if ischar(varargin{1}) if nargin == 1, error('Need N (size of matrix A).'); end n = varargin{2}; if ~isnumeric(n) | length(n) > 2 error('Second argument N must be a numeric value.'); end else [n,n] = size(varargin{1}); if any(size(varargin{1}) ~= n), error('Matrix A is not square.'); end if ~isnumeric(varargin{1}), error('A must be a numeric matrix.'); end end % Set all input options to default values or set to empty arrays. blsz = 3; adjust = []; cholB = 0; dispr = 0; K = 6; B=[]; maxit = 100; nbls = 10; permB = []; sigma = 'LM'; tol = 1d-6; V=[]; L=[]; U=[]; P=[]; nval=[]; % If a generalized eigenvalue problem is to be solved get matrix B. % Check type (numeric or character) and dimensions. if ((ischar(varargin{1}) & nargin > 2) | (isnumeric(varargin{1}) & nargin > 1)) if ~isstruct(varargin{2+ischar(varargin{1})}) B = varargin{2+ischar(varargin{1})}; if ~isnumeric(B), error('B must be a numeric matrix.'); end if any(size(B) ~= n), error('Matrix B must be the same size as A.'); end end end % Get input options from the structure array. if nargin > 1 + ischar(varargin{1}) + ~isempty(B) options = varargin{2+ischar(varargin{1}) + ~isempty(B):nargin}; names = fieldnames(options); I = strmatch('ADJUST',upper(names),'exact'); if ~isempty(I), adjust = getfield(options,names{I}); end I = strmatch('BLSZ',upper(names),'exact'); if ~isempty(I), blsz = getfield(options,names{I}); end I = strmatch('CHOLB',upper(names),'exact'); if ~isempty(I), cholB = getfield(options,names{I}); end I = strmatch('DISPR',upper(names),'exact'); if ~isempty(I), dispr = getfield(options,names{I}); end I = strmatch('K',upper(names),'exact'); if ~isempty(I), K = getfield(options,names{I}); end I = strmatch('MAXIT',upper(names),'exact'); if ~isempty(I), maxit = getfield(options,names{I}); end I = strmatch('NBLS',upper(names),'exact'); if ~isempty(I), nbls = getfield(options,names{I}); end I = strmatch('PERMB',upper(names),'exact'); if ~isempty(I), permB = getfield(options,names{I}); end I = strmatch('SIGMA',upper(names),'exact'); if ~isempty(I), sigma = upper(getfield(options,names{I})); end I = strmatch('TOL',upper(names),'exact'); if ~isempty(I), tol = getfield(options,names{I}); end I = strmatch('V0',upper(names),'exact'); if ~isempty(I), V = getfield(options,names{I}); end end % Check type of input values and output error message if needed. if (~isnumeric(blsz) | ~isnumeric(K) | ~isnumeric(dispr) | ... ~isnumeric(maxit) | ~isnumeric(nbls) | ~isnumeric(tol) | ... ~isnumeric(permB) | ~isnumeric(cholB)) error('Incorrect type for input value(s) in the structure.'); end % If a numeric value is given for sigma then set nval=sigma and % sigma = 'LM' to denote that the code is searching eigenvalues near nval. % Using the transformation inv(A-sigma*B)*B x = theta * x where % theta = 1/(lambda-sigma). if isnumeric(sigma), nval = sigma; sigma = 'LM'; end % Check the length and value of the character sigma. if length(sigma) ~= 2, error('SIGMA must be SA, LA, SM, LM, SR, LR, LI, or SI.'), end if (~strcmp(sigma,'SA') & ~strcmp(sigma,'LA') & ~strcmp(sigma,'LI') & ... ~strcmp(sigma,'SM') & ~strcmp(sigma,'LM') & ~strcmp(sigma,'SI') & ... ~strcmp(sigma,'SR') & ~strcmp(sigma,'LR')) error ('SIGMA must be SA, LA, SM, LM, SR, LR LI, or SI.'); end % Resize Krylov subspace if blsz*nbls (i.e. number of Arnoldi vectors) is larger % than n (i.e. the size of the matrix A). if blsz*nbls >= n nbls = floor(n/blsz); warning(['Changing NBLS to ',num2str(nbls)]); end % Increase the number of desired values to help increase convergence. % Set K+adjust to be next multiple of BLSZ > K. if isempty(adjust) adjust = 1:blsz; I = find(mod(K + adjust-1,blsz) == 0); adjust = adjust(I(1)); end K_org = K; K = K + adjust; % K_org to be orginal value of K. % Check for input errors in the structure array. if K <= 0, error('K must be a positive value.'); end if K > n, error('K is too large. Use eig(full(A))! '); end if blsz <= 0, error('BLSZ must be a positive value.'); end if nbls <=1, error('NBLS must be greater than 1.'); end if tol < 0, error('TOL must be non-negative.'); end if maxit <=0, error('MAXIT must be positive.'); end if ((cholB ~= 0) & (cholB ~= 1)), error('Unknown value for CHOLB.'); end if ~isempty(permB) if ((size(permB,1) ~= n) | (size(permB,2) ~= 1)) & ... ((size(permB,1) ~= 1) | (size(permB,2) ~= n)) error('Incorrect size for PERMB.'); end end % Automatically adjust Krylov subspace to accommodate larger values of K. if blsz*(nbls-1) - blsz - K - 1 < 0 nbls = ceil((K+1)/blsz+2.1); warning(['Changing NBLS to ',num2str(nbls)]); end if blsz*nbls >= n, nbls = floor(n/blsz-0.1); warning(['Changing NBLS to ',num2str(nbls)]); end if blsz*(nbls-1) - blsz - K - 1 < 0, error('K is too large.'); end % If starting matrix V0 is not given then set starting matrix V0 to be a % (n x blsz) matrix of normally distributed random numbers. Also, % preallocate memory size, so no resizing of the large matrix V occurs. if nnz(V) == 0 V = [randn(n,blsz) zeros(n,nbls*blsz)]; else if ~isnumeric(V), error('Incorrect starting matrix V0.'); end if (size(V,1) ~= n), error('Incorrect size of starting matrix V0.'); end if nnz(V) == 0, error('Matrix V contains all zeros.'); end V = [V zeros(n,nbls*blsz)]; end % Set tolerance to machine precision if tol < eps. if tol < eps, tol = eps; end % Using shift and invert if sigma is given as a real number. if ~isempty(nval) if ~isnumeric(varargin{1}) error('A must be a numeric matrix in order to use the internal shift and invert.'); end if ~isempty(B) [L,U,P] = lu(varargin{1}-nval*B); else [L,U,P] = lu(varargin{1}-nval*eye(n)); end end % If a generalized eigenvalue problem is to be solved then try to get the Cholesky % factorization of the matrix B (i.e. B=R'*R) and set B=R the upper triangular matrix. if ~isempty(B) & isempty(nval) % If B is sparse then compute the sparse cholesky factorization. Using symmmd or % symamd to get a permutation vector permB such that B(permB,permB) will have a % sparser cholesky factorization than B. The permutation is given by % B(permB,permB) = I(:,permB)'*B*I(:,permB), where I is the identity matrix. % To compute the product A(permB,permB)*X use Y(permB,:) = X; Y=A*Y; Y=Y(permB,:); if isempty(permB), permB = 1:n; end % If cholB = 1, then the input matrix B is given as R in the Cholesky factorization. if ~cholB if ~isreal(B), error('Matrix B must be real.'); end [L,cholerr] = chol(B(permB,permB)); % Will try to solve problem using the inverse of B, (i.e. inv(B)*A*x = lambda*x) % by computing the LU factorization of B. This may cause numerical instabilities. if cholerr [L,U,P] = lu(B); % Used only if B is not symmetric positive definite. else B = L; L=[]; end end end %--------------------------% % END: PARSE INPUT VALUES. % %--------------------------% %-----------------------------------------------------------% % BEGIN: DESCRIPTION AND INITIALIZATION OF LOCAL VARIABLES. % %-----------------------------------------------------------% check_norm_balance=[]; % Accuray of eigenpairs of H. Determines if nobalance in eig is needed. conv = 'F'; % Boolean to determine if all desired eigenvalues have converged. H = []; % Block Hessenberg (Hsz_n x Hsz_m) matrix. H_R = []; % Stores the last block of H. Used in updating H. H_eig = []; % Eigenvalues of H. H_eig_no = []; % Eigenvalues of H using nobalance in eig. Not always computed. H_eigv = []; % Eigenvectors of H. H_eigv_no = []; % Eigenvectors of H using nobalance in eig. Not always computed. Hsz_m = []; % Second dimension of H. Hsz_n = []; % First dimension of H. iter = 1; % Main loop iteration count. m = blsz; % Current number of columns in the matrix V. mprod = 0; % The number of matrix vector products. Q = []; % Schur vectors for H. R = []; % Is a diagonal matrix of 1 or -1's used in the function setuparnv. sqrteps = sqrt(eps); % Square root of machine tolerance. T = []; % T matrix in the WY representation of the Householder products. T_schur=[]; % Schur matrix for H. Tsz_m = []; % Size of T. %---------------------------------------------------------% % END: DESCRIPTION AND INITIALIZATION OF LOCAL VARIABLES. % %---------------------------------------------------------% %-----------------------------% % BEGIN: MAIN ITERATION LOOP. % %-----------------------------% while (iter <= maxit) % Compute the block Householder Arnoldi decomposition. [V,H,T,mprod] = ArnHouBlk(varargin{1},B,L,U,P,nval,permB,V,H,T,n,m,nbls,blsz,mprod); % Determine the size of the block Hessenberg matrix H. Possible % truncation may occur in ArnHouBlk if an invariant subspace % has been found or K + ADJUST is not a multiple of BLSZ. Hsz_n = size(H,1); Hsz_m = size(H,2); % Compute the eigenvalue decomposition of the block Hessenberg H(1:Hsz_m,:). [H_eigv,H_eig] = eig(H(1:Hsz_m,:)); % Check the accuracy of the computation of the eigenvalues of the % Hessenberg matrix. This is used to monitor balancing. check_norm_balance = norm(H(1:Hsz_m,:)*H_eigv - H_eigv*H_eig); if check_norm_balance >= eps*norm(H(1:Hsz_m,:)) [H_eigv_no,H_eig_no] = eig(H(1:Hsz_m,:),'nobalance'); check_norm_nobalance = norm(H(1:Hsz_m,:)*H_eigv_no - H_eigv_no*H_eig_no); if check_norm_nobalance < check_norm_balance H_eigv = H_eigv_no; H_eig = H_eig_no; end end H_eig = diag(H_eig); % Sort the eigenvalues and check for convergence. [H_eig,H_eigv,K,conv] = eigsortconv(Hsz_m,Hsz_n,blsz,dispr,H,iter,K_org,... K,adjust,H_eig,H_eigv,sigma,tol); % If all desired Ritz values converged then exit main loop. if strcmp(conv,'T'), break; end % Update the main iteration loop count. iter = iter + 1; if iter >= maxit, break; end % Convert the complex eigenvectors of the eigenvalue decomposition of H % to real vectors and convert the complex diagonal matrix to block diagonal. % Use MATLAB's internal function cdf2rdf to accomplish this task. if ~isreal(H_eig) [Q,T_Schur] = cdf2rdf(H_eigv,diag(H_eig)); % Convert complex vectors to real vectors. [Q,R] = qr(Q(:,1:K),0); % Compute the QR factorization of H_eigv(:,1:K). else [Q,R] = qr(H_eigv(:,1:K),0); % Compute the QR factorization of H_eigv(:,1:K). end % The Schur matrix for H. T_Schur = triu(Q'*H(1:Hsz_m,:)*Q,-1); % Compute the starting vectors and the residual vectors from the Householder % WY form. The starting vectors will be the first K Schur vectors and the % residual vectors are stored as the last BLSZ vectors in the Householder WY form. Tsz_m = size(T,1); V(:,Hsz_n-blsz+1:Hsz_n)= V(:,1:Tsz_m)*(T*V(Tsz_m-blsz+1:Tsz_m,1:Tsz_m)'); V(Tsz_m-blsz+1:Tsz_m,Hsz_n-blsz+1:Hsz_n) = eye(blsz,blsz)+V(Tsz_m-blsz+1:Tsz_m,Hsz_n-blsz+1:Hsz_n); % V(:,1:K) = V(:,1:Hsz_m)*(T(1:Hsz_m,1:Hsz_m)*(V(1:Hsz_m,1:Hsz_m)'*Q(:,1:K))); V(1:Hsz_m,1:K) = Q(:,1:K) + V(1:Hsz_m,1:K); % Set the size of the large matrix V and move the residual vectors. m = K + 2*blsz; V(:,K+1:K+blsz) = V(:,Hsz_n-blsz+1:Hsz_n); % Set the new starting vector(s) to be the desired vectors V(:,1:K) with the % residual vectors V(:,Hsz_n-blsz+1:Hsz_n). Place all vectors in the compact % WY form of the householder product. Compute the next set of vectors by % computing A*V(:,Hsz_n-blsz+1:Hsz_n) and store this in V(:,Hsz_n+1:Hsz_n+blsz). [V,T,R,mprod] = SetupArnVecs(V,T,varargin{1},B,L,U,P,nval,permB,n,blsz,m-blsz,mprod); % Compute the first K columns and K+BLSZ rows of the matrix H, used in augmenting. H_R = H(Hsz_n-blsz+1:Hsz_n,Hsz_m-blsz+1:Hsz_m); H=zeros(K+blsz,K); H(1:K,1:K) = R(1:K,1:K)*T_Schur(1:K,1:K)*R(1:K,1:K); H(K+1:K+blsz,1:K) = R(K+1:K+blsz,K+1:K+blsz)*H_R*Q(Hsz_m-(blsz-1):Hsz_m,1:K)*R(1:K,1:K); end %---------------------------% % END: MAIN ITERATION LOOP. % %---------------------------% %------------------------% % BEGIN: OUTPUT RESULTS. % %------------------------% % Test to see if maximum number of iterations have been reached. FLAG(1) = 0; if iter >= maxit FLAG(1) = 1; end; if FLAG(1)==1, warning('AHBEIGS did not find all requested eigenvalues!'); end % Truncated eigenvalue and eigenvector arrays to include only desired eigenpairs. H_eig = H_eig(1:K_org); H_eigv = H_eigv(:,1:K_org); % Convert the shift and invert eigenvalues back to orginal state using 1/(lambda-sigma). if ~isempty(nval), H_eig = 1./H_eig + nval; mprod = []; end % Sort output. [sortval,J] = sort(abs(H_eig(1:K_org))); J = J(length(J):-1:1); % Output option I: Display eigenvalues only. if (nargout == 0), eigenvalues = H_eig(J), end % Output option II: Set eigenvalues equal to output vector. if (nargout == 1), varargout{1} = H_eig(J); end % Output option III. Output diagonal matrix of eigenvalues and % corresponding matrix of eigenvectors. if nargout == 2 | nargout == 3 H_eigv = H_eigv(:,1:K_org); H_eigv = H_eigv(:,J); Tsz_m = size(T,1); H_sz1 = size(H_eigv,1); H_sz2 = size(H_eigv,2); V = V(:,1:Tsz_m)*(T*(V(1:H_sz1,1:Tsz_m)'*H_eigv)); V(1:H_sz1,1:H_sz2) = H_eigv + V(1:H_sz1,1:H_sz2); % Must solve a linear system to extract generalized eigenvectors. if ~isempty(B) & isempty(L) & isempty(nval), V = B\V(permB,:); end varargout{1} = V; varargout{2} = diag(H_eig(J)); end % Output option IV: Output FLAG. if nargout == 3, FLAG(2)=mprod; varargout{3}=FLAG; end %----------------------% % END: OUTPUT RESULTS. % %----------------------% %---------------------------------------------% % BEGIN: AUGMENTED BLOCK HOUSEHOLDER ARNOLDI. % %---------------------------------------------% function [V,H,T,mprod] = ArnHouBlk(A,B,L,U,P,nval,permB,V,H,T,n,m,nbls,blsz,mprod) % Computes the Block Arnoldi decomposition using Householder reflections. % % The matrix A can be passed as a numeric matrix or as a filename. Note % that if the matrix A is a filename then the file must accept [X,N,BLSZ] % as input in that order and the file must return the matrix-vector product A*X. % % Input: % A - Matrix A. % B - Matrix B for generalized eigenvalue problems. % L - LU factorization of (A-nval*B) or B. % U - LU factorization of (A-nval*B) or B. % P - Permutation matrix for the LU factorization. % NVAL - Numeric value of sigma, if given. % PERMB - Permutation vector for generalized eigenvalue problems. % V - (N x M) Initial matrix to start the Arnoldi reduction. % H - Empty or contains Schur values and residuals values on restart. % T - Upper triangular matrix used in Householder WY representation. % N - Size of the matrix A. % M - Current size of V. % NBLS - Maximum number of Arnoldi vectors. % BLSZ - Block size. % MPROD - Number matrix-vector products. % % Output: % V - N x BLSZ*NBLS+BLSZ matrix in WY-Householder format. % H - NBLS*BLSZ+BLSZ x NBLS*BLSZ upper block Hessenberg matrix. % T - Upper triangular matrix used in Householder WY representation. % MPROD - Number of matrix-vector products. % James Baglama % DATE: 7/20/2005 % LOCAL VARIABLES T_blk =zeros(blsz,blsz); % Small BLSZ x BLSZ upper triangular matrix used in Householder WY representation. % Check size of the block Arnoldi matrix H. If size is greater than n % reduce size. if blsz*(nbls+1) > n, nbls = floor(n/blsz)-1; end % Begin of main iteration loop for the Augmented Block Householder Arnoldi decomposition. while (m <= blsz*(nbls+1)) % Compute Householder vectors for BLSZ vectors V(m-blsz+1:n,m-blsz+1:m) using % MATLAB's internal qr algorithm. V(m-blsz+1:n,m-blsz+1:m) = qr(V(m-blsz+1:n,m-blsz+1:m)); % Compute the columns of the upper block hessenberg matrix H. if m > blsz H(1:m-blsz,m-2*blsz+1:m-blsz) = V(1:m-blsz,m-blsz+1:m); H(m-blsz+1:m,m-2*blsz+1:m-blsz) = triu(V(m-blsz+1:m,m-blsz+1:m)); end % Set up householder vectors. m2 = 2*m; if m2 > n, m2=n; end V(1:m2,m-blsz+1:m) = tril(V(1:m2,m-blsz+1:m),-(m-blsz+1)); for i=m-blsz+1:m,V(i,i)=1; end % Using the compact WY form of the householder product. See, % "A storage-efficient WY representation for products of % householder transformations", by Schreiber and Van Loan, % SIAM J. Sci. Stat. Comput. Vol. 10, No. 1 (1989) pp. 53-57. % P_{1} * P_{2} * ... * P_{n} = I + V *T *V'; % Place BLSZ householder vectors into I + V *T_blk *V' form. T_blk(1,1) = -2/(V(:,m-blsz+1)'*V(:,m-blsz+1)); for i=2:blsz T_blk(1:i,i) = (V(:,m-blsz+i)'*V(:,m-blsz+1:m-blsz+i))'; T_blk(i,i) = -2/T_blk(i,i); T_blk(1:i-1,i) = T_blk(i,i)*T_blk(1:i-1,1:i-1)*T_blk(1:i-1,i); end % Update I + V *T *V'. T = [ [T; zeros(blsz,m-blsz)] [(T*(V(:,m-blsz+1:m)'*V(:,1:m-blsz))')*T_blk; T_blk]]; if m <= blsz*nbls % V_{m+blsz} = ( I + V_m * T_m * V_m') * E_m. V(:,m+1:m+blsz) = V(:,1:m)*(T*V(m-blsz+1:m,1:m)'); V(m-blsz+1:m,m+1:m+blsz) = eye(blsz,blsz)+V(m-blsz+1:m,m+1:m+blsz); % Matrix-vector product, V_{m+blsz} = A * V_{m+blsz}. [V(:,m+1:m+blsz),mprod] = matrixprod(A,B,L,U,P,nval,permB,V(:,m+1:m+blsz),n,blsz,mprod); % V_{m+blsz} = (I + V_m * T_m' * V_m')*V_{m+blsz}. V(:,m+1:m+blsz) = V(:,m+1:m+blsz) + V(:,1:m)*((V(:,m+1:m+blsz)'*V(:,1:m))*T)'; end % Update iteration count. m = m + blsz; end % End main loop. %-------------------------------------------% % END: AUGMENTED BLOCK HOUSEHOLDER ARNOLDI. % %-------------------------------------------% %--------------------------------------------------------% % BEGIN: EIGENVALUE REORDERING AND CONVERGENCE TESTING. % %--------------------------------------------------------% function [H_eig,H_eigv,K,conv] = eigsortconv(Hsz_m,Hsz_n,blsz,dispr,H,iter,K_org,K,... adjust,H_eig,H_eigv,sigma,tol); % This reorders the eigenvalues of H and determines convergence. % % Input: % HSZ_M - Second dimension of H. % HSZ_N - First dimension of H. % BLSZ - Block size of H. % DISPR - Boolean to determine if Ritz pairs should be displayed. % H - Block Hessenberg (Hsz_n x Hsz_m) matrix. % ITER - Number of iterations of the main loop. % K_ORG - Orginal number of desired eigenpairs. % K - Adjusted number of eigenpairs. % ADJUST - Orginal value added to K_ORG % H_EIG - Eigenvalues of H. % H_EIGV - Eigenvectors of H. % SIGMA - Two letter string specifying the location of the desired eigenvalues. % TOL - Tolerance used for convergence. Convergence is determined when % || Ax - lambda_i*x ||_2 <= TOL*abs(Ritz_i). % % Output: % H_EIG - Sorted eigenvalues of H. % H_EIGV - Sorted eigenvectors of H. % K - Adjusted number of eigenpairs. Increased if eigenvectors converge. % CONV - Boolean to indicate all eigenpairs have converged. % James Baglama % DATE: 7/20/2005 % LOCAL VARIABLES conv = 'F'; % Boolean to determine if all desired eigenpairs have converged. eig_conj=[]; % Indicator for when K splits a conjugate pair. K is increased by 1. I_eig = []; % Integer vector of indexes for the ordering of the eigenvalues. Len_res=[]; % Number of converged values. % If sigma = LI or SI and all eigenvalues are real then sort by the real % value. if isreal(H_eig) & (strcmp(sigma,'SI') | strcmp(sigma,'LI')) if strcmp(sigma,'SI'), sigma = 'SR'; end if strcmp(sigma,'LI'), sigma = 'LR'; end end % Determine the ordering of the eigenvalues. switch sigma % Eigenvalues of largest magnitude. case 'LM', [Y,I_eig] = sort(abs(H_eig)); I_eig = I_eig(length(I_eig):-1:1); % Eigenvalues of smallest magnitude. case 'SM', [Y,I_eig] = sort(abs(H_eig)); % Eigenvalues of largest real part. case 'LR', [Y,I_eig] = sort(real(H_eig)); I_eig = I_eig(length(I_eig):-1:1); % Eigenvalues of smallest real part. case 'SR', [Y,I_eig] = sort(real(H_eig)); % Eigenvalues of largest imaginary part. case 'LI', [Y,I_eig] = sort((abs(imag(H_eig)))); I_eig = I_eig(length(I_eig):-1:1); % Eigenvalues of smallest imaginary part. case 'SI', [Y,I_eig] = sort((abs(imag(H_eig)))); % Largest algebraic eigenvalues (symmetric problems only). case 'LA', [Y,I_eig] = sort(H_eig); I_eig = I_eig(length(I_eig):-1:1); % Smallest algebraic eigenvalues (symmetric problems only). case 'SA', [Y,I_eig] = sort(H_eig); end % Sort the eigenvalue and eigenvector arrays. H_eig = H_eig(I_eig); H_eigv = H_eigv(:,I_eig); % Compute the residuals for the K_org Ritz values. residuals = (sum(abs(H(Hsz_n-blsz+1:Hsz_n,Hsz_m-blsz+1:Hsz_m)*... H_eigv(Hsz_m-(blsz-1):Hsz_m,1:K_org)).^2, 1).^(0.5)); % Output intermediate results. if dispr ~= 0 format short e % Sort output values. [sortval,J] = sort(abs(H_eig(1:K_org))); J = J(length(J):-1:1); S = [H_eig(J) residuals(J)']; if ~isreal(S) disp(sprintf(' Ritz values Residual Iteration: %d',iter)); else disp(sprintf(' Ritz values Residual Iteration: %d',iter)); end disp(S); disp(' '); disp(' '); end % Check for convergence. Len_res = length(find(residuals(1:K_org)' < tol*abs(H_eig(1:K_org)))); if Len_res >= K_org, conv = 'T'; end % Set convergence to true. % Adjust K to include more vectors as the number of vectors converge. Len_res = length(find(residuals(1:K_org)' < eps*abs(H_eig(1:K_org)))); K = K_org + adjust+ Len_res; if K > Hsz_m - 2*blsz-1, K = Hsz_m - 2*blsz-1; end % Determine if K splits a conjugate pair. If so replace K with K + 1. if ~isreal(H_eig(K)) eig_conj = 1; if K < Hsz_m if abs(imag(H_eig(K)) + imag(H_eig(K+1))) < sqrt(eps) K = K + 1; eig_conj = 0; end end if K > 1 & eig_conj if abs(imag(H_eig(K)) + imag(H_eig(K-1))) < sqrt(eps) eig_conj = 0; end end if eig_conj, error('%d th conjugate pair split.',K(i)); end end %-----------------------------------------------------% % END: EIGENVALUE REORDERING AND CONVERGENCE TESTING. % %-----------------------------------------------------% %----------------------------------------------------------% % BEGIN: WY HOUSEHOLDER REPRESENATION OF STARTING VECTORS. % %----------------------------------------------------------% function [V,T,R,mprod] = SetupArnVecs(V,T,A,B,L,U,P,nval,permB,n,blsz,m,mprod) % Given an orthogonal matrix V, this function SetupArnVecs computes the % compact WY form of the householder product. See, "A storage-efficient % WY representation for products of householder transformations", by Schreiber % and Van Loan, SIAM J. Sci. Stat. Comput. Vol. 10, No. 1 (1989) pp. 53-57. % Also to save on computations the next vector in the block Arnoldi process % is also calculated. % % Input: % V - (N x M) orthogonal Matrix. % T - Upper triangular matrix for WY-compact form. % A - Matrix A. % B - Matrix B for generalized eigenvalue problems. % L - LU factorization of (A-nval*B) or B. % U - LU factorization of (A-nval*B) or B. % P - Permutation matrix for the LU factorization. % NVAL - Numeric value of sigma, if given. % PERMB - Permutation vector for generalized eigenvalue problems. % N - Size of the matrix A. % BLSZ - Block size % m - Current size of V. % MPROD - Number of matrix-vector products. % % Output: % V - (N x M+BLSZ) matrix such that (N x 1:M) are the Householder vectors % and (N x M+1:M+BLSZ) are the Arnoldi vectors needed to restart the % Arnoldi process % T - (M x M) Upper triangular matrix such that P_{1} * ... * P_{n} = I + V*T *V'. % R - R is a diagonal matrix of 1's and -1's. R*R = I where % V(input) * R = (I + V * T * V') * I(:,m). % MPROD - Number of matrix-vector products. % James Baglama % DATE: 7/20/2005 % LOCAL VARIABLES V_sign = []; % Used to determine Householder vectors, the sign of the diagonal value. Vdot = []; % Dot product of Householder vectors. D = []; % Used for scaling. % Initialize matrix T. T = V(1:m,1:m); % Matrix-vector product, V_{m+1:m+blsz} = A * V_{m-blsz+1:m}. [V(:,m+1:m+blsz),mprod] = matrixprod(A,B,L,U,P,nval,permB,V(:,m-blsz+1:m),n,blsz,mprod); % Compute the householder vectors V. The input matrix V(:,1:m) is orthogonal % and the length of each vector is 1. Hence the householder vector % u_i = v_i + e_i*||v_i||_2 *sign(v_ii) = v_i + e_i*sign(v_ii) and the % dot product u_i'*u_i = 2 + 2*sign(v_ii)*v_ii. Also, since the matrix is % orthognal only the first m columns and rows are updated at this stage. % At this stage V=[V_1; V_2], V_1 is a m x m matrix which is now computed. for i =1:m V_sign(i) = sign(V(i,i)); if V_sign(i) == 0, V_sign(i)=1; end Vdot = 1 + V_sign(i)*V(i,i); % Dot product of householder vectors. V(i,i) = V(i,i) + V_sign(i); % Reflection to the ith axis. D(i,i) = 1/V(i,i); % Used for scaling. Note: V(i,i) >= 1. % Apply the householder vectors to update the i+1:m vectors in V. Only % the first m rows are needed at this stage. V(1:m,i+1:m) = V(1:m,i+1:m) - V(1:m,i)*((V_sign(i)/Vdot)*V(i,i+1:m)); end % Scale the matrix V_1, so that diagonal elements are 1. V(1:m,1:m) = V(1:m,1:m)*D; % Compute the upper triangular matrix R such that the following relationship % holds V(input) * R = (I + V * T * V') * I(:,m). R = -(diag(V_sign)); % Update the new block. V(:,m+1:m+blsz) = V(:,m+1:m+blsz)*(R(m-blsz+1:m,m-blsz+1:m)); % Set up householder vectors. Put exact zeros in place of computed zeros. V(1:m,1:m) = tril(V(1:m,1:m),0); % Compute T. Note that V(input) * R = (I + V * T * V') * E_m. Let % V = [V_1; V_2]. V_1 is already computed. Hence we have % T = inv(V_1)*(E_m'*V_(input)*R - E_m)*inv(V_1)'. % V_1 is upper triangular matrix with 1's on the diagonal. T = T*R - eye(m); T = T/V(1:m,1:m)'; T = triu(V(1:m,1:m)\T); % Compute the V_2 n-m x m matrix in V = [V_1; V_2]. % V_2 = V(input)*[0; I(n-m,m)]*R*inv(T*V_1). V(m+1:n,1:m) = V(m+1:n,1:m)*(R/(T*V(1:m,1:m)')); % V_{m+blsz} = (I + V_m * T_m' * V_m')*V_{m+blsz}. Update the vectors to % be used in the block Arnoldi subroutine. V(:,m+1:m+blsz) = V(:,m+1:m+blsz) + V(:,1:m)*((V(:,m+1:m+blsz)'*V(:,1:m))*T)'; %---------------------------------------------------------% % END: WY HOUSEHOLDER REPRESENATION OF STARTING VECTORS. % %---------------------------------------------------------% %-------------------------------% % BEGIN: MATRIX-VECTOR PRODUCT. % %-------------------------------% function [X,mprod] = matrixprod(A,B,L,U,P,nval,permB,X,n,blsz,mprod) % Computes the matrix vector products. % % Input: % A - Matrix A. % B - Matrix B for generalized eigenvalue problems. % L - LU factorization of (A-nval*B) or B. % U - LU factorization of (A-nval*B) or B. % P - Permutation matrix for the LU factorization. % NVAL - Numeric value of sigma, if given. % PERMB - Permutation vector for generalized eigenvalue problems. % X - (N x BLSZ) Matrix to multiply OP (operator). % N - Size of the matrix A. % BLSZ - Block size. % MPROD - Number of matrix-vector products. % % Output: % X - (N x BLSZ) Product of OP*X (operator). % MPROD - Number of matrix-vector products. % James Baglama % DATE: 7/20/2005 % Generalized eigenvalue problem (Cholesky factored). if ~isempty(B) & isempty(L) & isempty(nval) X(permB,:) = B \ X; if ischar(A), X = feval(A,X,n,blsz); else X = A*X; end X = (X(permB,:)'/B)'; end % Generalized eigenvalue problem (LU factored). if ~isempty(B) & ~isempty(L) & isempty(nval) if ischar(A), X = feval(A,X,n,blsz); else X = A*X; end X = U \ (L \ (P * X)); end % Generalized or standard eigenvalue problem (Shift & Invert). if ~isempty(nval) if isempty(B) X = U \ (L \ (P * X)); else X = U \ (L \ (P * B* X)); end end % Standard eigenvalue problem. if isempty(B) & isempty(nval) if ischar(A), X = feval(A,X,n,blsz); else X = A*X; end end % Number of matrix-vector products with A. mprod = mprod+blsz; %-----------------------------% % END: MATRIX-VECTOR PRODUCT. % %-----------------------------%