Mercurial > hg > octave-nkf
diff scripts/linear-algebra/krylov.m @ 3211:440b2b28e74a
[project @ 1998-11-05 04:16:22 by jwe]
author | jwe |
---|---|
date | Thu, 05 Nov 1998 04:16:34 +0000 |
parents | |
children | 7aae2c3636a7 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/scripts/linear-algebra/krylov.m @@ -0,0 +1,130 @@ +# Copyright (C) 1996,1998 A. Scottedward Hodel +# +# This file is part of Octave. +# +# Octave is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any +# later version. +# +# Octave is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with Octave; see the file COPYING. If not, write to the Free +# Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +function [U,H,k1] = krylov(A,v,k,eps1); + # function [U,H,k1] = krylov(A,v,k{,eps1}); + # construct orthogonal basis U of Krylov subspace; + # span([v Av A^2*v ... A^(k+1)*v]); + # via householder reflections; reflections are multiplied to obtain U + # eps1: threshhold for 0 relative to norm of current column (default: 1e-12) + # method used: householder reflections to guard against loss of + # orthogonality + # + # outputs: + # returned basis U is n x k+1; A*U(:,1:k) = U*H + # k1: dimension of span of krylov subspace (based on eps1) + # if k > m-1, krylov returns the Hessenberg decompostion of A. + + # Written by A. S. Hodel 1992 + # $Revision: 1.2 $ + # $Log$ + + if(nargin == 3) + eps1 = 1e-12; + endif + + if( !is_square(A) ) + error("first argument must be a square matrix") + else + [m,n] = size(v); + if(m != is_square(A)) + error("krylov: argument dimensions do not match") + elseif( !is_sample(k) ) + error("krylov: third argument must be a scalar integer") + elseif( k > m) + warning(["krylov: k is too large; reducing to ",num2str(m)]); + k = m-1; + endif + endif + + if(norm(v) == 0) + U = []; + H = []; + k1 = 0; + return + endif + + k1 = k+1; # Assume subspace basis has full rank + [m,n] = size(A); + [hv,alpha(1),z] = housh(v,1,0); + + # initial orthogonal vector + q = zeros(n,1); + q(1) = 1; + q = q - alpha*hv*hv'*q; + normq = norm(q); + normres = normq; + + U(:,1) = hv; + j = 1; + while(j <= k & normres > eps1*normq) + # multiply to get new vector; + q = A*q; + normq = norm(q); + + # multiply by householder reflections to obtain projected vector and the + # next column of H + for i=1:j + hv = U(i:n,i); + av = alpha(i); + q(i:n,1) = q(i:n,1)-av*hv*(hv'*q(i:n,1)); + endfor + + i = j+1; + # compute and apply next householder vector; + if(i <= n) + [hv,av,z] = housh(q(i:n,1),1,0); + alpha(i) = av; + q(i:n,1) = q(i:n,1)-av*hv*(hv'*q(i:n,1)); + U(i:n,i) = hv; + H(1:i,j) = q(1:i); + else + av = 0; + H(:,j) = q; # complete Hessenberg decomposition + endif + + # see if done yet + normres = norm(q(i:n)); + if(normres > eps1*normq) + j = j+1; + else + k1 = min(k1,j); # time to quit; norm of residual is small + endif + + # back out new q vector for next pass; + j1 = columns(U); + q = zeros(n,1); + q(j1) = 1; + for i=j1:-1:1; + hv = U(i:n,i); + av = alpha(i); + q(i:n,1) = q(i:n,1)-av*hv*(hv'*q(i:n,1)); + endfor + endwhile + + # back out U matrix ; + j1 = columns(U); + for i=j1:-1:1; + hv = U(i:n,i); + av = alpha(i); + U(:,i) = zeros(n,1); + U(i,i) = 1; + U(i:n,i:j1) = U(i:n,i:j1)-av*hv*(hv'*U(i:n,i:j1)); + endfor + +endfunction