Сходимость классических итерационных решателей для линейных систем определяется спектральным радиусом итерационной матрицы . Для обычной линейной системы трудно определить оптимальный (или даже хороший) параметр SOR из-за сложности определения спектрального радиуса итерационной матрицы. Ниже я включил много дополнительных деталей, включая пример реальной проблемы, когда известен оптимальный вес SOR.ρ(G)
Спектральный радиус и сходимость
Спектральный радиус определяется как абсолютное значение собственного значения наибольшей величины. Метод будет сходиться, если и меньший спектральный радиус означает более быструю сходимость. SOR работает, изменяя расщепление матрицы, используемое для выведения итерационной матрицы, основываясь на выборе весового параметра , надеясь уменьшить спектральный радиус результирующей итерационной матрицы.ρ<1ω
Матричное разбиение
Для обсуждения ниже я буду предполагать, что решаемая система определяется
Ax=b,
с итерацией вида
x(k+1)=v+Gx(k),
где - вектор, а номер итерации обозначается .vkx(k)
SOR принимает средневзвешенное значение старой итерации и итерации Гаусса-Зейделя. Метод Гаусса-Зейделя основан на матричном расщеплении вида
A=D+L+U
где - диагональ , - нижняя треугольная матрица, содержащая все элементы строго ниже диагонали, а - верхняя треугольная матрица содержащий все элементы строго выше диагонали. Затем итерация Гаусса-ЗейделяDALARA
x(k+1)=(D+L)−1b+GG−Sx(k)
и итерационная матрица
GG−S=−(D+L)−1U.
SOR может быть записан как
x(k+1)=ω(D+ωL)−1b+GSORx(k)
где
GSOR=(D+ωL)−1((1−ω)D−ωU).
Определение скорости сходимости итерационной схемы действительно сводится к определению спектрального радиуса этих итерационных матриц. В общем, это сложная проблема, если вы не знаете что-то конкретное о структуре матрицы. Мне известно лишь несколько примеров, где вычисляется оптимальный весовой коэффициент. На практике необходимо определять на лету на основе наблюдаемой (предполагаемой) сходимости алгоритма бега. Это работает в некоторых случаях, но не в других.ω
Оптимальный СОР
Один реалистический пример, где известен оптимальный весовой коэффициент, возникает в контексте решения уравнения Пуассона:
∇2u=f in Ωu=g on ∂Ω
Дискретизация этой системы в квадратной области в 2D с использованием конечных разностей второго порядка с равномерным шагом сетки приводит к симметричной полосовой матрице с 4 по диагонали, -1 непосредственно выше и ниже диагонали и еще двумя полосами -1 на некотором расстоянии от диагональ. Есть некоторые различия из-за граничных условий, но это основная структура. Учитывая эту матрицу, доказуемо оптимальный выбор для коэффициента SOR дается
ω=21+sin(πΔx/L)
где - интервал сетки, а - размер домена. В этом случае для простого случая с известным решением выдается следующая ошибка в зависимости от числа итераций для этих двух методов:ΔxL
Как вы можете видеть, SOR достигает точности машины примерно за 100 итераций, когда Гаусс-Зейдель на 25 порядков хуже. Если вы хотите поиграть с этим примером, я включил код MATLAB, который использовал ниже.
clear all
close all
%number of iterations:
niter = 150;
%number of grid points in each direction
N = 16;
% [x y] = ndgrid(linspace(0,1,N),linspace(0,1,N));
[x y] = ndgrid(linspace(-pi,pi,N),linspace(-pi,pi,N));
dx = x(2,1)-x(1,1);
L = x(N,1)-x(1,1);
%desired solution:
U = sin(x/2).*cos(y);
% Right hand side for the Poisson equation (computed from U to produce the
% desired known solution)
Ix = 2:N-1;
Iy = 2:N-1;
f = zeros(size(U));
f(Ix,Iy) = (-4*U(Ix,Iy)+U(Ix-1,Iy)+U(Ix+1,Iy)+U(Ix,Iy-1)+U(Ix,Iy+1));
figure(1)
clf
contourf(x,y,U,50,'linestyle','none')
title('True solution')
%initial guess (must match boundary conditions)
U0 = U;
U0(Ix,Iy) = rand(N-2);
%Gauss-Seidel iteration:
UGS = U0; EGS = zeros(1,niter);
for iter=1:niter
for iy=2:N-1
for ix=2:N-1
UGS(ix,iy) = -1/4*(f(ix,iy)-UGS(ix-1,iy)-UGS(ix+1,iy)-UGS(ix,iy-1)-UGS(ix,iy+1));
end
end
%error:
EGS(iter) = sum(sum((U-UGS).^2))/sum(sum(U.^2));
end
figure(2)
clf
contourf(x,y,UGS,50,'linestyle','none')
title(sprintf('Gauss-Seidel approximate solution, iteration %d', iter))
drawnow
%SOR iteration:
USOR = U0; ESOR = zeros(1,niter);
w = 2/(1+sin(pi*dx/L));
for iter=1:niter
for iy=2:N-1
for ix=2:N-1
USOR(ix,iy) = (1-w)*USOR(ix,iy)-w/4*(f(ix,iy)-USOR(ix-1,iy)-USOR(ix+1,iy)-USOR(ix,iy-1)-USOR(ix,iy+1));
end
end
%error:
ESOR(iter) = sum(sum((U-USOR).^2))/sum(sum(U.^2));
end
figure(4)
clf
contourf(x,y,USOR,50,'linestyle','none')
title(sprintf('Gauss-Seidel approximate solution, iteration %d', iter))
drawnow
figure(5)
clf
semilogy(EGS,'b')
hold on
semilogy(ESOR,'r')
title('L2 relative error')
xlabel('Iteration number')
legend('Gauss-Seidel','SOR','location','southwest')
Эта сторона вещей на самом деле не моя специальность, но я не думаю, что это супер-честный тест для многих реалистичных приложений.
Я не уверен, какие значения вы использовали для c и r , но я подозреваю, что вы работали с крайне плохо обусловленными матрицами. (Ниже приведен код Python, показывающий, что это могут быть не самые обратимые матрицы.)
Если вам действительно нужно инвертировать матрицы, которые плохо обусловлены, вы бы: а) использовали специализированный метод, и б), вероятно, просто пошли бы искать новое поле.
Для хорошо подготовленных матриц любого размера SOR, вероятно, будет быстрее. Для реальных проблем, где важна скорость, было бы редко использовать SOR - со сложной стороны, сейчас намного лучше; На медленной, но надежной стороне SOR - не лучшее, что вы можете сделать.
источник
Итак, для симметричных матриц этого короля:
SOR сходится быстрее, чем Gauss-Seidel, если число s в каждом ряду мало (намного меньше, чем размерность A) и если все s одинаковы. Я использовал s, сгенерированный так:t t t
Если s сильно варьируются и центрированы вокруг 0 ( ), то Гаусс-Зайдель быстрее. Гаусс-Зайдель также быстрее, если каждый ряд более чем наполовину заполнен s. Это также означает, что SOR лучше для очень больших и очень разреженных матриц.t c=0,r=0.1 t
(Это просто эмпирическое наблюдение, ничего строгого)
источник