Метод прогонки

Матеріал з testwiki
Перейти до навігації Перейти до пошуку

Метод прогонки, також відомий як алгоритм Томаса, дозволяє розв'язувати СЛАР з Тридіагональною матрицею, і є спрощенням методу Гауса для таких обмежень. Працює за лінійний час.

Система має такий вигляд:

aixi1+bixi+cixi+1=di,

де a1=0 та cn=0. В матричній формі це записується так:

[b1c10a2b2c2a3b3cn10anbn][x1x2x3xn]=[d1d2d3dn].

В цілому, метод не є числово стійким, але є таким у декількох випадках, таких як діагонально панівна матриця або додатноозначена матриця.[1]

Розв'язок

Розв'язок проводиться в два кроки, як і в методі Гауса, прямому, та зворотному. В прямому ході ми обчислюємо:

c'1=c1b1; c'i=cibic'i1ai,i=2,n1

та

d'1=d1b1; d'i=did'i1aibic'i1ai,i=2,n

Тепер розв'язок знаходимо зворотнім ходом:

xn=d'n

xi=d'ic'ixi+1; i=n1,n2,,1

Код на C

/* Розв'язок повертається в x. c та d модифікуються!*/

void TridiagonalSolve (const double *a, const double *b, double *c, double *d, double *x, unsigned int n){
 
	/* Modify the coefficients. */
	c[0] /= b[0];	/* Division by zero risk. */
	d[0] /= b[0];	/* Division by zero would imply a singular matrix. */
	for (unsigned int i = 1; i < n; i++){
		double id = 1 / (b[i] - c[i-1] * a[i]);  /* Division by zero risk. */
		c[i] *= id;	                         /* Last value calculated is redundant. */
		d[i] = (d[i] - d[i-1] * a[i]) * id;
	}
 
	/* Now back substitute. */
	x[n - 1] = d[n - 1];
	for (int i = n - 2; i >= 0; i--)
		x[i] = d[i] - c[i] * x[i + 1];
}

Доведення

Доведення методу вимагає ручного виконання деяких спеціалізованих Гаусових вилучань.

Припустимо, що невідомі - це x1,,xn, і що рівняння до розв'язання такі:

b1x1+c1x2=d1;i=1aixi1+bixi+cixi+1=di;i=2,,n1anxn1+bnxn=dn;i=n.

Розглянемо таку зміну другого (i=2) рівняння за допомогою першого рівняння:

(equation 2)b1(equation 1)a2

що дасть:

(a2x1+b2x2+c2x3)b1(b1x1+c1x2)a2=d2b1d1a2
(b2b1c1a2)x2+c2b1x3=d2b1d1a2

у висліді маємо, що x1 було вилучено з другого рівняння. Використовуючи подібну тактику зі зміненим другим рівнянням, щодо третього маємо:

(a3x2+b3x3+c3x4)(b2b1c1a2)((b2b1c1a2)x2+c2b1x3)a3=d3(b2b1c1a2)(d2b1d1a2)a3
(b3(b2b1c1a2)c2b1a3)x3+c3(b2b1c1a2)x4=d3(b2b1c1a2)(d2b1d1a2)a3.

Цього разу було вилучено x2, якщо повторювати цю процедуру до рядка n; (змінене) рівняння n міститиме лише одну змінну, xn. Таке рівняння ми можемо розв'язати і використати результат для того, щоб розв'язати рівняння (n1), і так далі допоки всі невідомі не знайдені.

Очевидно, що коефіцієнти у змінених рівняннях ставатимуть все більш заплутаними якщо розписувати їх явно. Але змінені коефіцієнти (з тильдою) можна виразити рекурсивно:

a~i=0
b~1=b1
b~i=bib~i1c~i1ai
c~1=c1
c~i=cib~i1
d~1=d1
d~i=dib~i1d~i1ai.

Для дальшого пришвидшення процесу, b~i можна нормувати діленням (якщо немає ризику ділення на число занадто близьке до нуля), тепер змінені коефіцієнти позначені рисочкою будуть:

a'i=0
b'i=1
c'1=c1b1
c'i=cibic'i1ai
d'1=d1b1
d'i=did'i1aibic'i1ai.

це дає нам наступну систему з тими самими невідомими і коефіцієнтами вираженими через початкові:

b'ixi+c'ixi+1=d'i; i=1,,n1b'nxn=d'n; i=n.

Останнє рівняння містить лише одне невідоме. Розв'язуючи його, приводимо наступне останнє рівняння до одного невідомого. І так далі:

xn=d'n/b'n
xi=(d'ic'ixi+1)/b'i; i=n1,n2,,1.

Примітки

Шаблон:Reflist