function [Q,varargout]=ortha(A,X) %ORTHA Orthonormalization Relative to matrix A % Q=ortha(A,X) % Q=ortha('Afunc',X) % Computes an orthonormal basis Q for the range of X, relative to the % scalar product using a positive definite and selfadjoint matrix A. % That is, Q'*A*Q = I, the columns of Q span the same space as % columns of X, and rank(Q)=rank(X). % % [Q,AQ]=ortha(A,X) also gives AQ = A*Q. % % Required input arguments: % A : either an m x m positive definite and selfadjoint matrix A % or a linear operator A=A(v) that is positive definite selfadjoint; % X : m x n matrix containing vectors to be orthonormalized relative % to A. % % ortha(eye(m),X) spans the same space as orth(X) % % Examples: % [q,Aq]=ortha(hilb(20),eye(20,5)) % computes 5 column-vectors q spanned by the first 5 coordinate vectors, % and orthonormal with respect to the scalar product given by the % 20x20 Hilbert matrix, % while an attempt to orthogonalize (in the same scalar product) % all 20 coordinate vectors using % [q,Aq]=ortha(hilb(20),eye(20)) % gives 14 column-vectors out of 20. % Note that rank(hilb(20)) = 13 in double precision. % % Algorithm: % X=orth(X), [U,S,V]=SVD(X'*A*X), then Q=X*U*S^(-1/2) % If A is ill conditioned an extra step is performed to % improve the result. This extra step is performed only % if a test indicates that the program is running on a % machine that supports higher precison arithmetic % (greater than 64 bit precision). % % See also ORTH, SVD % % Copyright (c) 2001 Freeware for noncommercial use. % Andrew Knyazev, Rico Argentati % Contact email: knyazev@na-net.ornl.gov % $Revision: 1.5.8 $ $Date: 2001/8/28 % Tested under MATLAB R10-12.1 % Check input parameter A [m,n] = size(X); if ~isstr(A) [mA,mA] = size(A); if any(size(A) ~= mA) error('Matrix A must be a square matrix or a string.') end if size(A) ~= m error(['The size ' int2str(size(A)) ... ' of the matrix A does not match with ' int2str(m) ... ' - the number of rows of X']) end end % Normalize, so ORTH below would not delete wanted vectors for i=1:size(X,2), normXi=norm(X(:,i),inf); %Adjustment makes tol consistent with experimental results if normXi > eps^.981 X(:,i)=X(:,i)/normXi; % Else orth will take care of this end end % Make sure X is full rank and orthonormalize X=orth(X); %This can also be done using QR.m, in which case %the column scaling above is not needed %Set tolerance [m,n]=size(X); tol=max(m,n)*eps; % Compute an A-orthonormal basis if ~isstr(A) AX = A*X; else AX = feval(A,X); end XAX = X'*AX; XAX = 0.5.*(XAX' + XAX); [U,S,V]=svd(XAX); if n>1 s=diag(S); elseif n==1, s=S(1); else s=0; end %Adjustment makes tol consistent with experimental results threshold1=max(m,n)*max(s)*eps^1.1; r=sum(s>threshold1); s(r+1:size(s,1))=1; S=diag(1./sqrt(s),0); X=X*U*S; AX=AX*U*S; XAX = X'*AX; % Check error against tolerance error=normest(XAX(1:r,1:r)-eye(r)); % Check internal precision, e.g., 80bit FPU registers of P3/P4 precision_test=[1 eps/1024 -1]*[1 1 1]'; if error1 s=diag(S); elseif n==1, s=S(1); else s=0; end threshold2=max(m,n)*max(s)*eps; r=sum(s>threshold2); S=diag(1./sqrt(s(1:r)),0); Q=X*U(:,1:r)*S(1:r,1:r); varargout(1)={AX*U(:,1:r)*S(1:r,1:r)};