Метод GMRES с заданными вращениями в MATLAB

У меня есть следующая реализация алгоритма

function[x,error,iter,flag,vetnorm_r]=gmres_givens(A,x,b,restart,maxit,tol)


% input   A        REAL nonsymmetric positive definite matrix
%         x        REAL initial guess vector
%         b        REAL right hand side vector
%         M        REAL preconditioner matrix
%         restart  INTEGER number of iterations between restarts
%         maxit    INTEGER maximum number of iterations
%         tol      REAL error tolerance
%
% output  x        REAL solution vector
%         error    REAL error norm
%         iter     INTEGER number of iterations performed
%         flag     INTEGER: 0 = solution found to tolerance
%                           1 = no convergence given maxit

iter = 0;          % initialization                               
flag = 0;

bnrm2=norm(b);
if(bnrm2==0), bnrm2=1.0; end

r=b-A*x;
error=norm(r)/bnrm2;

if(error < tol) return, end

[n,n]=size(A);                   % initialize workspace                
m=restart;
V(:,1:m+1)=zeros(n,m+1);
H(1:m+1,1:m)=zeros(m+1,m);
c(1:m)=zeros(m,1);
s(1:m)=zeros(m,1);
e1=zeros(n,1);
e1(1)=1;
vetnorm_r=zeros(m+1,1);

for iter=1:maxit                         % begin iteration         
r=(b-A*x);
V(:,1)=r/norm(r);
g=norm(r)*e1;
vetnorm_r(1)=norm(r);
for i=1:m                                % construct orthonormal system 
w=(A*V(:,i));                            
for k=1:i
H(k,i)=w'*V(:,k);                        % basis using Gram-Schmidt
w=w-H(k,i)*V(:,k);
end
H(i+1,i)=norm(w);
V(:,i+1)=w/H(i+1,i);

for k=1:i-1                                    % apply Givens rotation
temp=c(k)*H(k,i)+s(k)*H(k+1,i);
H(k+1,i)=-s(k)*H(k,i)+c(k)*H(k+1,i);
H(k,i)=temp;
end
[c(i),s(i)]=givens(H(i,i),H(i+1,i));         % form i-th rotation matrix
temp=c(i)*g(i);                              % approximate residual norm
g(i+1)=-s(i)*g(i);        
g(i)=temp;
H(i,i)=c(i)*H(i,i)+s(i)*H(i+1,i);
H(i+1,i)=0;
error=abs(g(i+1))/bnrm2;
vetnorm_r(i+1)=abs(g(i+1));

if (error <= tol)                           % update approximation
y=H(1:i,1:i)\g(1:i);                        % and exit
x=x+V(:,1:i)*y;
break;
end  
end

if(error <= tol), break, end
y=H(1:m,1:m)\g(1:m);                          % update approximation
x=x+V*y;                                      % compute residual
r=b-A*x                                    
g(i+1)=norm(r);
error=g(i+1)/bnrm2;                         % check convergence
if(error <= tol), break, end;
end

if (error>tol) flag=1; end;        

end

where

function [c,s]=givens(a,b)

if(b==0)
c=1;
s=0;
elseif (abs(b) > abs(a)),
temp=a/b;
s=1/sqrt(1+temp^2);
c=temp*s;
else
temp=b/a;
c=1/sqrt(1+temp^2);
s=temp*c;
end

Моя проблема состоит в том, чтобы получить вектор (возможно, матрицу) vetnorm_r, который содержит все нормы остатка (в качестве вывода) на каждой итерации (и, возможно, при каждом перезапуске). Я не знаю, как построить этот вектор или матрицу.

% ввод A REAL несимметричная положительно определенная матрица % x REAL вектор начального приближения % b REAL вектор правой стороны % M REAL матрица предобуславливателя % перезапуск INTEGER количество итераций между перезапусками % maxit INTEGER максимальное количество итераций % tol REAL допустимая ошибка % % вывод x РЕАЛЬНЫЙ вектор решения % ошибка РЕАЛЬНАЯ норма ошибки % iter INTEGER число выполненных итераций % флаг INTEGER: 0 = найдено решение с допуском % 1 = нет сходимости при данном maxit

Спасибо за любой ответ


person robert10    schedule 08.12.2017    source источник


Ответы (1)


Вероятно, вам не следует копировать код, который вы не понимаете. Остаток - это то, где он говорит проверить сходимость.

if(error <= tol), break, end
y=H(1:m,1:m)\g(1:m);                          % update approximation
x=x+V*y;                                      % compute residual
r=b-A*x                                    
g(i+1)=norm(r);
error=g(i+1)/bnrm2;                         % check convergence
if(error <= tol), break, end;
end

Я не уверен, что вы просите. Вы можете либо кодировать так, чтобы он не ломался по допуску, а выполнял только несколько итераций, чтобы вектор остатков был предварительно сохранен, что я бы и сделал. Или вы можете установить остаточную длину вектора длинной, а затем, когда она приближается к разрыву, добавить к ней больше.

person Community    schedule 24.01.2018