Литература / Козин Р.Г. Алгоритмы численных методов линейной алгебры и их программная реализация
.pdfили в покомпонентной записи
B11 y1 |
b1 |
B21 y1 B22 y2 |
b2 |
... |
|
Bi1 y1 Bi 2 y2 ... Bii yi bi |
|
... |
|
Bii xi Bi 1i xi 1 |
.... Bni xn yi |
... |
|
Bn 1n 1xn 1 Bnn 1xn yn 1 Bnn xn yn
Их решение рассчитывается элементарно
|
|
|
|
i 1 |
|
|
|
b1 |
|
|
bi Bij y j |
||
y1 |
для i 2, n |
yi |
j 1 |
, |
||
B11 |
Bii |
|||||
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
n |
|
|
|
y |
|
|
|
yi Bji xj |
||
|
n |
для i (n 1),1 |
|
j i 1 |
|
||
xn |
|
xi |
|
. |
|||
Bnn |
Bii |
||||||
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Последовательное вычисление компонент промежуточного вектора y можно выполнять в алгоритме (2.42) после определения компонент соответствующей строки матрицы B (см. приведенный ранее алгоритм). При этом для экономии памяти матрицу B можно хранить на месте исходной матрицы A, а вектор y формировать на месте вектора x. Необходимо помнить, что все суммы, встречающиеся в алгоритмах, вычисляются путем введения соответствующих внутренних циклов.
121
В заключение привем листинг на языке Visual Basic процедурыфункции, реализующей метод квадратного корня с использованием
приведенных алгоритмов:
Function kvroot () As Integer Dim i%, j%, k%
kvroot = 0 'матрица положительно-определенная
If Not (a(0, 0) > 0) Then
kvroot = 1 'матрица не положительно-определенная
Exit Function End If
a(0, 0) = Sqr(a(0, 0)) x(0) = a(0, n) / a(0, 0) a(1, 0) = a(1, 0) / a(0, 0)
x(1) = a(1, n)
a(1, 1) = a(1, 1) - a(1, 0) * a(1, 0) If Not (a(1, 1) > 0) Then
kvroot = 1 'матрица не положительно-определенная
Exit Function End If
a(1, 1) = Sqr(a(1, 1))
x(1) = (x(1) - a(1, 0) * x(0)) / a(1, 1) If n = 2 Then GoTo cont
For k = 2 To n - 1
a(k, 0) = a(k, 0) / a(0, 0)
x(k) = a(k, n) - a(k, 0) * x(0) For i = 1 To k - 1
For j = 0 To i - 1
a(k, i) = a(k, i) - a(k, j) * a(i, j) Next j
a(k, i) = a(k, i) / a(i, i)
x(k) = x(k) - a(k, i) * x(i) Next i
For j = 0 To k - 1
a(k, k) = a(k, k) - a(k, j) * a(k, j) Next j
If Not (a(k, k) > 0) Then
kvroot = 1 'матрица не положительно-определенная
Exit Function End If
a(k, k) = Sqr(a(k, k)) x(k) = x(k) / a(k, k)
Next k cont:
x(n - 1) = x(n - 1) / a(n - 1, n - 1)
For i = n - 2 To 0 Step -1
For j = i + 1 To n - 1 x(i) = x(i) - a(j, i) * x(j)
Next j
x(i) = x(i) / a(i, i) Next i
End Function
Здесь систама Ax b хранится в расширенной матрице с компо-
нентами: a(0, 0), …, a(n – 1, n).
122
На рис. 2.26 представлен скриншот программы, которая позволяет найти решение проивольной системы линейных уравнений как вторым методом ортогонализации, так и методом квадратного корня. Для преобразования произвольной системы в равносильную систему с симметричной и положительно определенной матрицей следует использовать кнопку «Умножить систему на А(т)» – умножить систему на транспонированную исходную матрицу. Имеется возможность задать систему уравнений случайным образом. Последнее позволяет провести сравнительный анализ точности (по норме невязки полученного решения) используемых методов.
Рис. 2.26. Экранная форма программы, которая реализует два метода, используемые для положительно определенной симметричной матрицы
Дополнительно покажем, как этот алгоритм может быть реализован на языке С в среде CodeBlocks:
#include<stdio.h> #include <stdlib.h> #include <windows.h> #include <math.h> #include <time.h>
#define B(i,j) MM[i*(n+1)+j]
#define A(i,j) M[i*(n+1)+j] //преобразованная система – умножена на AT
123
float *MM,*M; int n,n1;
int root_2(); void var_M(); void Ax_b();
int main() |
|
{ |
|
inti,j,code,c; |
|
chars[2]; |
|
SetConsoleCP(1251); |
//чтобы воспринимала русские буквы |
SetConsoleOutputCP(1251); |
|
printf(" *** Программа находит решение системы Ax=b методом квадратного корня ***
");
printf("\nВведите размерность системы: ");
scanf("%d",&n); n1=n-1; |
|
M=malloc(n*(n+1)*sizeof(float)); |
//добавлена правая часть |
MM=malloc(n*(n+1)*sizeof(float)); |
//добавляем правую часть - исходная система |
printf("Введите 0/1 - задать систему случайным образом / вручную "); scanf("%d",&c);
switch (c){ case 0:
//инициализация датчика п.с. чисел текущим временем srand(time(NULL)); for(i=0;i<n;i++)for(j=0;j<n+1;j++)B(i,j)=0.5-rand()/(RAND_MAX+1.0); break;
default:
for (i=0;i<n;i++){ for (j=0;j<n;j++){
printf("Введите A(%d,%d): ",i,j); scanf("%f",&B(i,j));
}
printf("Введите b(%d): ",i); scanf("%f",&B(i,n));
}
break;
}
printf("Исходная система:\n"); for (i=0;i<n;i++){
for (j=0;j<n;j++){ printf("%f ",B(i,j));
}
printf("%f\n",B(i,n));
}
var_M(); //преобразуем исходную систему printf("Преобразованная система Bt*B:\n"); for (i=0;i<n;i++){
for (j=0;j<=n;j++){ printf("%f ",A(i,j));
}
printf("\n");
}
124
code=root_2();
if (code==1) printf("\nМатрица системы ПЛОХАЯ !"); else{
printf("\nРешение:\n"); for(i=0;i<n;i++){
printf("%f ",A(i,n));
}
Ax_b(); printf("\nНевязка:\n"); for(i=0;i<n;i++){
printf("%f ",B(i,n));
}
}
printf("\nДля завершения программы нажмите любую клавишу и ENTER "); scanf("%s",s); printf("\n");
return 0;
}
//п/п реализует метод квадратного корня - находит решение int root_2(){
int i,j,k;
//строим нижнюю треугольную матрицу
if (A(0,0)<=0) return 1; //матрица системы плохая A(0,0)=sqrt(A(0,0));
A(0,n)=A(0,n)/A(0,0); // y(0) A(1,0)=A(1,0)/A(0,0); A(1,1)=A(1,1)-A(1,0)*A(1,0);
if (A(1,1)<=0) return 1; //матрица системы плохая A(1,1)=sqrt(A(1,1)); A(1,n)=(A(1,n)-A(1,0)*A(0,n))/A(1,1); // y(1)
if (n>2){ |
|
for (k=2;k<n;k++){ |
//цикл по следующим уравнениям |
A(k,0)=A(k,0)/A(0,0);
A(k,n)=A(k,n)-A(k,0)*A(0,n); //y(k)=b(k)-B(k,0)y(0)....
for (i=1;i<k;i++){ for (j=0;j<i;j++){
A(k,i)=A(k,i)-A(k,j)*A(i,j);
}
A(k,i)=A(k,i)/A(i,i);
A(k,n)=A(k,n)-A(k,i)*A(i,n); //y(k)=(k)-B(k,i)y(i)...
}
for (j=0;j<k;j++){ A(k,k)=A(k,k)-A(k,j)*A(k,j);
}
if (A(k,k)<=0) return 1; //матрица системы плохая A(k,k)=sqrt(A(k,k));
A(k,n)=A(k,n)/A(k,k); //конецвычисления y(k)
}
}
//находим x(i) A(n1,n)=A(n1,n)/A(n1,n1); //x(n-1) for (i=n-2;i>-1;i--){
125
for (j=i+1;j<n;j++){ A(i,n)=A(i,n)-A(j,i)*A(j,n);
}
A(i,n)=A(i,n)/A(i,i);
}
return 0;
}
//п/п вычисляет A=BT*B - симметричная положительно определенная void var_M(){
inti,j,k;
for(i=0;i<n;i++){
for(j=0;j<=n;j++){
A(i,j)=0.;
for (k=0;k<n;k++) A(i,j)=A(i,j)+B(k,i)*B(k,j);
}
}
}
//п/п вычисляет невязку d=b-Ax void Ax_b(){
inti,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++) B(i,n)=B(i,n)-B(i,j)*A(j,n);
}
}
Скриншот с результатами работы этой программы:
126
2.2.8. Метод прогонки
Метод прогонки является самым экономичным способом решения систем с трех диагональной матрицей
b1x1 c1x2 d1;
...;
ak xk 1 bk xk ck xk 1 dk , k 2,n 1; (2.43)
...;
an xn 1 bn xn dn .
Здесь для хранения системы использовано четыре вектора a, b, c, d , причем компоненты a1 cn 0 не используются.
К таким системам сводится разностное решение краевых задач для дифференциальных уравнений второго порядка.
Введем рекуррентные зависимости
xk k xk 1 k , |
k 1, n 1. |
(2.44) |
Найдем формулы для расчета входящих в (2.44) неизвестных
параметров k , k .
Сравнивая первое уравнение в (2.43) с соотношением (2.44), получаем
c1 |
, |
d1 . |
(2.45) |
||
1 |
b1 |
|
1 |
b1 |
|
|
|
|
|
||
Далее, заменим в k-м уравнении системы (2.43) неизвестное xk 1 согласно формуле (2.44)
ak ( k 1xk k 1 ) bk xk ck xk 1 dk .
Отсюда легко выводим рекуррентные формулы для последовательного определения остальных неизвестных параметров k , k :
k ck , |
k dk ak k 1 , |
k 2, n 1, |
(2.46) |
tk |
tk |
|
tk bk ak k 1.
Вычисления по формулам (2.45), (2.46) называется прямым хо-
дом прогонки.
127
Теперь, подставляя в последнее уравнение (2.43) соотношение (2.44) с k n 1 , получим
a |
( |
x |
|
n 1 |
) b x |
d |
k |
|
x |
dn an n 1 . |
(2.47) |
|
n |
|
n 1 n |
|
n n |
|
|
n |
bn an n 1 |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
Формулы (2.47) и (2.44) (с k n 1,n 2, ...,1 ) позволяют рассчитать все компоненты xk неизвестного решения системы (2.43). Эти
расчеты называются обратнымходом прогонки.
Покажем методом индукции, что для устойчивости метода прогонки ( bk ak k 1 0 ) достаточно выполнения следующих соотношений между параметрами системы:
|
|
|
|
|
|
|
|
|
|
bk |
|
|
|
ak |
|
|
|
ck |
|
|
0 |
при k . |
|
(2.48) |
||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||
|
|
При соблюдении условия (2.48) |
имеем (см. (2.45)) |
|
b1 |
|
0 и |
|||||||||||||||||||||||||||||||||
|
|
|
|
|||||||||||||||||||||||||||||||||||||
|
1 |
|
1. Предположим, что |
|
k 1 |
|
1. Тогда |
|
|
|
bk |
ak k 1 |
|
0 . Кроме |
||||||||||||||||||||||||||
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||||
того, |
|
bk ak k 1 |
|
|
|
ck |
|
и, следовательно, |
|
k |
|
1 |
и т.д. |
|
|
|
|
|
|
|||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||
Заметим, что метод прогонки легко обобщается на системы с пяти (и более) диагональными матрицами. В этом случае исходное рекуррентное соотношение следует брать в виде
xk k xk 1 k xk 2 k .
Замечание. При программной реализации метода, в целях экономии памяти, параметры k , k можно сохранять на месте компонент векторов bk , dk , а реше-
ние вернуть в векторе c. В этом случае алгоритм метода будет иметь следующий вид:
прямой ход прогонки
d1 d1 , b1 c1 b1 b1
для k 2, (n 1)
{
t bk akbk 1
dk dk ak dk 1 t
bk ctk
}
обратный ход прогонки
сn dn andn 1
bn anbn 1
для k (n 1), 1
{
ck bkck 1 dk
}
128
В заключение рассмотрим пример, в котором метод прогонки используется для нахождения решения краевой задачи для диффренциального уравнения второго порядка.
Пример. Распределение стационарной температуры в тепловыделяющем стержне с теплоизолированными боковыми стенками, один торец которого теплоизолирован, а через другой происходит теплообмен, в безрамерном виде задается уравнением и граничными условиями:
d 2 y |
q(x), |
x [0,1]; |
|
|||
dx2 |
|
|||||
|
|
|
|
|
|
|
dy 0 при |
x 0, |
dy |
y при |
x 1. |
||
dx |
|
|
|
dx |
|
|
Рис. 2.27. Разностная сетка, используемая в разностной задаче
Разностный аналог этой задачи, аппроксимирующий ее с квад-
ратичной точность относительно шага |
разностной сетки h |
1 |
||||||
(рис. 2.27), записывается в виде |
|
|
n |
|||||
|
|
|
||||||
y |
2y y |
i 1 |
h2q , |
i 0, n; |
|
|||
|
i 1 |
|
i |
i |
|
|
||
|
y1 y 1 |
0, |
|
|
yn 1 yn 1 |
yn . |
|
|
|
2h |
|
|
2h |
|
|||
|
|
|
|
|
|
|||
Отсюда для определения неизвестных значений yi для i 0, n по-
лучаем следующую систему линейных уравнений с трех диагональной матрицей
|
|
y y |
|
q |
h2 |
|
|
|||
|
|
|
0 |
|
; |
|
|
|||
|
|
0 |
1 |
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
y |
2 y |
y |
h2q |
, |
|
i 1, (n 1); |
(2.49) |
|||
i 1 |
i |
i 1 |
|
|
i |
|
|
|
|
|
|
yn 1 |
(1 h)yn |
q |
h2 |
|
|||||
|
n |
. |
|
|||||||
|
|
|
|
|
|
|
|
2 |
|
|
129
Листинг программы в языке пакета Maxima, которая решает эту систему методом прогоки для q(x) x и 1, приведен на
рис. 2.28, а результаты ее выполнения – на рис. 2.29.
kill(all);
/* подпрограмма, реализующая метод прогонки; a,b,c,d – списки с коэффициентами */
/* системы, n – порядок системы; решение возвращается в списке с */ progonka(a,b,c,d,n):=block
( [k,t],
/* прямой ход прогонки */ d[1]:d[1]/b[1], b[1]:-c[1]/b[1],
for k:2 thru n-1 do (t:b[k]+a[k]*b[k-1], d[k]:(d[k]-a[k]*d[k-1])/t, b[k]:-c[k]/t), /* обратный ход прогонки */
c[n]:(d[n]-a[n]*d[n-1])/(b[n]+a[n]*b[n-1]),
for k:(n-1) thru 1 step -1 do c[k]:b[k]*c[k+1]+d[k]
); /* главная программа */
numer:true;
fpprintprec:6;
define(q(x),x); /* правая часть исходного уравнения */ /* формирование коэффициентов системы */
n:11; h:1/(n-1); alf:1;
a:[]; b:[]; c:[]; d:[]; t:[]; /* инициализация списков */
t:append(t,[0]); a:append(a,[0]); b:append(b,[-1]); c:append(c,[1]); d:append(d,[- h^2*q(0)/2]);
for i:2 thru n-1 do
(
t:append(t,[h*(i -1)]), a:append(a,[1]), b:append(b,[-2]), c:append(c,[1]), d:append(d,[-h^2*q(t[i])])
);
t:append(t,[1]); a:append(a,[1]); b:append(b,[-(1+h*alf)]); c:append(c,[0]); d:append(d,[- h^2*q(1)/2]);
progonka(a,b,c,d,n);
c; /* выводим список значений сеточного решения, полученного методом прогонки */
r(x):=(4-x^3)/6; /* точное решение исходной задачи */ c1:[]; for i thru n do c1:append(c1,[r(t[i])]);
c1; /* выводим список значений точного решения */
/* строим график точного решений и значения сеточного уравнения */ plot2d([[discrete, t,c], r(x)], [x,0,1],
[style, points, lines], [color, red, blue], [point_type, asterisk], [legend, "разностное решение", "точное"],
[xlabel, "длина - x"], [ylabel, "температура"]);
Рис. 2.28. Листинг программы, решаюшей разностную задачуметодом прогоки
130
