⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 my_gmres_schur_unsym.m

📁 求解线性系统的Krylov方法的工具箱
💻 M
字号:
function [x,flag,relres,iter,resvec] = my_gmres_schur_unsym(L,U,B,C,b,restart,tol,maxit,M1,D,M2,x0)
%GMRES  Generalized Minimum Residual Method. 
% function [x,flag,relres,iter,resvec] = my_gmres_schur(L,U,B,C,b,restart,tol,maxit,M1,D,M2,x0)
% the A*x is replaced by a schur operation
% on input: C*inv(L*U)*B', b---the linear system; restart---restart GMRES after restart
% times; tol---stopping criterion; maxit---maximum iteration times;
% M1,D,M2---preconditioners; x0---initial guess
% on output: x---the approximate solution of the linear system;
% flag:
%    0 GMRES converged to the desired tolerance TOL within MAXIT
%      iterations;
%    1 GMRES iterated MAXIT times but did not converge;
%    2 preconditioner M was ill-conditioned;
%    3 GMRES stagnated (two consecutive iterates were the same);
% relres---the relative residual NORM(b-A*x)/NORM(b), if flag is 0, relres
%          <= tol;
% iter---both the outer and inner iteration numbers at which x was
%        computed: 0 <= iter(1) <= maxit and 0 <= iter(2) <= restart;
% resvec---a vector of the residual norms at each inner iteration, including
%          NORM(b-A*x0).

% Author: Liang Li, UESTC
% Date  : 2008-01-03

if (nargin < 5)
   error('Not enough input arguments.');
end

[m,n] = size(C);
% Check for all zero right hand side vector => all zero solution
n2b = norm(b);                      % Norm of rhs vector, b
if (n2b == 0)                       % if    rhs vector is all zeros
   x = zeros(m,1);                  % then  solution is all zeros
   flag = 0;                        % a valid solution has been obtained
   relres = 0;                      % the relative residual is actually 0/0
   iter = [0 0];                    % no iterations need be performed
   resvec = 0;                      % resvec(1) = norm(b-A*x) = norm(0)      
   return                           % no need to proceed
end

% Assign default values to unspecified parameters
if (nargin < 6) | isempty(restart) | (restart == n)
    restarted = 0;
else
    restarted = 1;
end
if (nargin < 7) | isempty(tol)
   tol = 1e-6;
end
if (nargin < 8 | isempty(maxit))
    if restarted
        maxit = min(ceil(n/restart),10);
    else
        maxit = min(n,10);
    end
end

if restarted
    outer = maxit;
    inner = restart;
else
    outer = 1;
    inner = maxit;
end
if ((nargin >= 9) & ~isempty(M1))
   existM1 = 1;
else
   existM1 = 0;
end

if ((nargin >= 10) & ~isempty(D))
   existD = 1;
else
   existD = 0;
end

if ((nargin >= 11) & ~isempty(M2))
   existM2 = 1;
else
   existM2 = 0;
end

if ((nargin >= 12) & ~isempty(x0))
   if ~isequal(size(x0),[m,1])
      es = sprintf(['Initial guess must be a column vector of' ...
            ' length %d to match the problem size.'],n);
      error(es);
   end
else
   x0 = zeros(m,1);
end
x = x0;

% Set up for the method
flag = 1;
xmin = x;                          % Iterate which has minimal residual so far
imin = 0;                          % "Outer" iteration at which xmin was computed
jmin = 0;                          % "Inner" iteration at which xmin was computed
tolb = tol * n2b;                  % Relative tolerance
r = b - schur_Ax_unsym(L,U,B,C,x);       % Zero-th residual
normr = norm(r);                   % Norm of residual

if (normr <= tolb)                 % Initial guess is a good enough solution
   flag = 0;
   relres = normr / n2b;
   iter = [0 0];
   resvec = normr;
   return                         % The initial guess is good enough.
end


resvec = zeros(inner*outer+1,1); % Preallocate vector for norm of residuals
resvec(1) = normr;                 % resvec(1) = norm(b-A*x0)
normrmin = normr;                  % Norm of residual from xmin
rho = 1;
stag = 0;                          % stagnation of the method

% loop over "outer" iterations (unless convergence or failure)

for iouter = 1 : outer
   V = zeros(m,inner+1);          % Arnoldi vectors
   h = zeros(inner+1,1);          % upper Hessenberg st A*V = V*H ...
   QT = zeros(inner+1,inner+1);   % orthogonal factor st QT*H = R
   R = zeros(inner,inner);        % upper triangular factor st H = Q*R
   f = zeros(inner,1);            % y = R\f => x = x0 + V*y
   W = zeros(m,inner);            % W = V*inv(R)
   iinner = 0;                    % "inner" iteration counter
   vh = r;
   if existM1
       vh = M1 \ vh;
       if isinf(norm(vh,inf))
         flag = 2;
         break
      end
   end
   if existD
       vh = D \ vh;
       if isinf(norm(vh,inf))
         flag = 2;
         break
      end
   end
   if existM2
       vh = M2 \ vh;
      if isinf(norm(vh,inf))
         flag = 2;
         break
      end
   end
   h(1) = norm(vh);
   V(:,1) = vh / h(1);
   QT(1,1) = 1;
   phibar = h(1);
   
   for iinner = 1 : inner  % inner iteration
       u = schur_Ax_unsym(L,U,B,C,V(:,iinner));
      if existM1
          u = M1 \ u;
         if isinf(norm(u,inf))
            flag = 2;
            break
         end
      end
      if existD
          u = D \ u;
          if isinf(norm(u,inf))
            flag = 2;
            break
         end
      end
      if existM2
          u = M2 \ u;
         if isinf(norm(u,inf))
            flag = 2;
            break
         end
      end
      for k = 1 : iinner  % orthogonalization
         h(k) = V(:,k)' * u;
         u = u - h(k) * V(:,k);
      end
      h(iinner+1) = norm(u);
      V(:,iinner+1) = u / h(iinner+1);
      R(1:iinner,iinner) = QT(1:iinner,1:iinner) * h(1:iinner);
      rt = R(iinner,iinner);
      
      % find cos(theta) and sin(theta) of Givens rotation
      if h(iinner+1) == 0
         c = 1.0;                      % theta = 0
         s = 0.0;
      elseif abs(h(iinner+1)) > abs(rt)
         temp = rt / h(iinner+1);
         s = 1.0 / sqrt(1.0 + abs(temp)^2); % pi/4 < theta < 3pi/4
         c = - temp * s;
      else
         temp = h(iinner+1) / rt;
         c = 1.0 / sqrt(1.0 + abs(temp)^2); % -pi/4 <= theta < 0 < theta <= pi/4
         s = - temp * c;
      end
      R(iinner,iinner) = c' * rt - s' * h(iinner+1);

      q = QT(iinner,1:iinner);
      QT(iinner,1:iinner) = c' * q;
      QT(iinner+1,1:iinner) = s * q;
      QT(iinner,iinner+1) = -s';
      QT(iinner+1,iinner+1) = c;
      f(iinner) = c' * phibar;
      phibar = s * phibar;
      
      if iinner < inner
         if f(iinner) == 0                 % stagnation of the method
            stag = 1;
         end
         W(:,iinner) = (V(:,iinner) - W(:,1:iinner-1) * R(1:iinner-1,iinner))/ R(iinner,iinner);
         % Check for stagnation of the method
         if stag == 0
            stagtest = zeros(n,1);
            ind = (x ~= 0);
            if ~(iouter==1 & iinner==1)
               stagtest(ind) = W(ind,iinner) ./ x(ind);
               stagtest(~ind & W(:,iinner) ~= 0) = Inf;
               if abs(f(iinner))*norm(stagtest,inf) < eps
                  stag = 1;
               end
            end
         end
         x = x + f(iinner) * W(:,iinner);       % form the new inner iterate
      else % j == inner
         vrf = V(:,1:iinner)*(R(1:iinner,1:iinner)\f(1:iinner));
         % Check for stagnation of the method
         if stag == 0
            stagtest = zeros(n,1);
            ind = (x0 ~= 0);
            stagtest(ind) = vrf(ind) ./ x0(ind);
            stagtest(~ind & vrf ~= 0) = Inf;
            if norm(stagtest,inf) < eps
               stag = 1;
            end
         end
         x = x0 + vrf;                % form the new outer iterate
      end 
      r = b - schur_Ax_unsym(L,U,B,C,x);
      normr = norm(r);
      resvec((iouter-1)*inner+iinner+1) = normr;
      
      if normr <= tolb               % check for convergence
         if iinner < inner
            y = R(1:iinner,1:iinner) \ f(1:iinner);
            x = x0 + V(:,1:iinner) * y;     % more accurate computation of xj
%             r = b - A * x;
%             normr = norm(r);
            resvec((iouter-1)*inner+iinner+1) = normr;
         end
         if normr <= tolb             % check using more accurate xj
            flag = 0;
            iter = [iouter iinner];
            break
         end
      end
      
      if stag == 1
         flag = 3;
         break
      end
      
      if normr < normrmin            % update minimal norm quantities
         normrmin = normr;
         xmin = x;
         imin = iouter;
         jmin = iinner;
      end
   end                              % for j = 1 : inner
   
   if flag == 1
      x0 = x;                        % save for the next outer iteration
      r = b - schur_Ax_unsym(L,U,B,C,x0);
  else
      break
   end
   
end                                % for i = 1 : maxit

% returned solution is that with minimum residual
if flag == 0
   relres = normr / n2b;
else
   x = xmin;
   iter = [imin jmin];
   relres = normrmin / n2b;
end

% truncate the zeros from resvec
if flag <= 1 | flag == 3
   resvec = resvec(1:(iouter-1)*inner+iinner+1);
else
   if iinner == 0
      resvec = resvec(1:(iouter-1)*inner+1);
   else
      resvec = resvec(1:(iouter-1)*inner+iinner);
   end
end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -