Это не официальный сайт wikipedia.org 01.01.2023

Метод Гаусса — Зейделя решения системы линейных уравнений — Википедия

Метод Гаусса — Зейделя решения системы линейных уравнений

Метод Гаусса — Зейделя (метод Зейделя, процесс Либмана, метод последовательных замещений) — является классическим итерационным методом решения системы линейных уравнений.

Назван в честь Зейделя и Гаусса.

Постановка задачиПравить

Возьмём систему: A x = b  , где A = ( a 11 a 1 n a n 1 a n n ) , b = ( b 1 b n )  

Или { a 11 x 1 + + a 1 n x n = b 1 a n 1 x 1 + + a n n x n = b n  

И покажем, как её можно решить с использованием метода Гаусса-Зейделя.

МетодПравить

Чтобы пояснить суть метода, перепишем задачу в виде

{ a 11 x 1 = a 12 x 2 a 13 x 3 a 1 n x n + b 1 a 21 x 1 + a 22 x 2 = a 23 x 3 a 2 n x n + b 2 a ( n 1 ) 1 x 1 + a ( n 1 ) 2 x 2 + + a ( n 1 ) ( n 1 ) x n 1 = a ( n 1 ) n x n + b n 1 a n 1 x 1 + a n 2 x 2 + + a n ( n 1 ) x n 1 + a n n x n = b n  

Здесь в j  -м уравнении мы перенесли в правую часть все члены, содержащие x i  , для i > j  . Эта запись может быть представлена как

( L + D ) x = U x + b ,  

где в принятых обозначениях D   означает матрицу, у которой на главной диагонали стоят соответствующие элементы матрицы A  , а все остальные нули; тогда как матрицы U   и L   содержат верхнюю и нижнюю треугольные части A  , на главной диагонали которых нули.

Итерационный процесс в методе Гаусса — Зейделя строится по формуле

( L + D ) x ( k + 1 ) = U x ( k ) + b , k = 0 , 1 , 2 ,  

после выбора соответствующего начального приближения x ( 0 )  .

Метод Гаусса — Зейделя можно рассматривать как модификацию метода Якоби. Основная идея модификации состоит в том, что новые значения x ( i )   используются здесь сразу же по мере получения, в то время как в методе Якоби они не используются до следующей итерации:

{ x 1 ( k + 1 ) = c 12 x 2 ( k ) + c 13 x 3 ( k ) + + c 1 n x n ( k ) + d 1 x 2 ( k + 1 ) = c 21 x 1 ( k + 1 ) + c 23 x 3 ( k ) + + c 2 n x n ( k ) + d 2 x n ( k + 1 ) = c n 1 x 1 ( k + 1 ) + c n 2 x 2 ( k + 1 ) + + c n ( n 1 ) x n 1 ( k + 1 ) + d n ,  

где

c i j = { a i j a i i , j i , 0 , j = i . d i = b i a i i , i = 1 , , n .  

Таким образом, i-я компонента ( k + 1 )  -го приближения вычисляется по формуле

x i ( k + 1 ) = j = 1 i 1 c i j x j ( k + 1 ) + j = i n c i j x j ( k ) + d i , i = 1 , , n .  

Например, при n = 3  :

x 1 ( k + 1 ) = j = 1 1 1 c 1 j x j ( k + 1 ) + j = 1 3 c 1 j x j ( k ) + d 1  , то есть x 1 ( k + 1 ) = c 11 x 1 ( k ) + c 12 x 2 ( k ) + c 13 x 3 ( k ) + d 1 ,  
x 2 ( k + 1 ) = j = 1 2 1 c 2 j x j ( k + 1 ) + j = 2 3 c 2 j x j ( k ) + d 2  , то есть x 2 ( k + 1 ) = c 21 x 1 ( k + 1 ) + c 22 x 2 ( k ) + c 23 x 3 ( k ) + d 2 ,  
x 3 ( k + 1 ) = j = 1 3 1 c 3 j x j ( k + 1 ) + j = 3 3 c 3 j x j ( k ) + d 3  , то есть x 3 ( k + 1 ) = c 31 x 1 ( k + 1 ) + c 32 x 2 ( k + 1 ) + c 33 x 3 ( k ) + d 3 .  

Условие сходимостиПравить

Приведём достаточное условие сходимости метода.

  Теорема.
Пусть A 2 < 1  , где A 2 = ( L + D ) 1 U , ( L + D ) 1   – матрица, обратная к ( L + D )  . Тогда при любом выборе начального приближения x ( 0 )  :
  1. метод Гаусса-Зейделя сходится;
  2. скорость сходимости метода равна скорости сходимости геометрической прогрессии со знаменателем q = A 2  ;
  3. верна оценка погрешности: x ( k ) x = q k x ( 0 ) x  .

Условие окончанияПравить

Условие окончания итерационного процесса Зейделя при достижении точности ε   в упрощённой форме имеет вид:

x ( k + 1 ) x ( k ) ε  

Более точное условие окончания итерационного процесса имеет вид

A x ( k ) b ε  

и требует больше вычислений. Хорошо подходит для разреженных матриц.

Пример реализации на C++Править

#include <iostream>
#include <cmath>

using namespace std;

// Условие окончания
bool converge(double xk[10], double xkp[10], int n, double eps)
{
	double norm = 0;
	for (int i = 0; i < n; i++)
		norm += (xk[i] - xkp[i]) * (xk[i] - xkp[i]);
	return (sqrt(norm) < eps);
}

double okr(double x, double eps)
{
	int i = 0;
	double neweps = eps;
	while (neweps < 1)
	{
		i++;
		neweps *= 10;
	}
	int okr = pow(double(10), i);
	x = int(x * okr + 0.5) / double(okr);

	return x;
}

bool diagonal(double a[10][10], int n)
{
	int i, j, k = 1;
	double sum;
	for (i = 0; i < n; i++) {
		sum = 0;
		for (j = 0; j < n; j++) sum += abs(a[i][j]);
		sum -= abs(a[i][i]);
		if (sum > a[i][i]) 
		{
			k = 0; 
			cout << a[i][i] << " < " << sum << endl;
		}
		else
		{
			cout << a[i][i] << " > " << sum << endl;
		}
		

	}

	return (k == 1);

}




int main()
{
	setlocale(LC_ALL, "");

	double eps, a[10][10], b[10], x[10], p[10];
	int n, i, j, m = 0;
	int method;
	cout << "Введите размер квадратной матрицы: ";
	cin >> n;
	cout << "Введите точность вычислений: ";
	cin >> eps;
	cout << "Заполните матрицу А: " << endl << endl;
	for (i = 0; i < n; i++)
		for (j = 0; j < n; j++)
		{
			cout << "A[" << i << "][" << j << "] = ";
			cin >> a[i][j];
		}
	cout << endl << endl;
	cout << "Ваша матрица А: " << endl << endl;
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
			cout << a[i][j] << " ";
		cout << endl;
	}

	cout << endl;

	cout << "Заполните столбец свободных членов: " << endl << endl;
	for (i = 0; i < n; i++)
	{
		cout << "В[" << i + 1 << "] = ";
		cin >> b[i];
	}

	cout << endl << endl;


	/*
	Ход метода, где:
	a[n][n] - Матрица коэффициентов
	x[n], p[n] - Текущее и предыдущее решения
	b[n] - Столбец правых частей
	Все перечисленные массивы вещественные и
	должны быть определены в основной программе,
	также в массив x[n] следует поместить начальное
	приближение столбца решений (например, все нули)
	*/

	for (int i = 0; i < n; i++)
		x[i] = 1;

	cout << "Диагональное преобладание: " << endl;
	if (diagonal(a, n)) {
		do
		{
			for (int i = 0; i < n; i++)
				p[i] = x[i];
			for (int i = 0; i < n; i++)
			{
				double var = 0;
				for (int j = 0; j < n; j++)
                    if(j!=i) var += (a[i][j] * x[j]);
				
				x[i] = (b[i] - var) / a[i][i];
			}
			m++;
		} while (!converge(x, p, n, eps));



		cout << "Решение системы:" << endl << endl;
		for (i = 0; i < n; i++) cout << "x" << i << " = " << okr(x[i], eps) << "" << endl;
		cout << "Итераций: " << m << endl;
	}
	else {
		cout << "Не выполняется преобладание диагоналей" << endl;
	}

	system("pause");
	return 0;
}


Пример реализации на PythonПравить

import numpy as np

def seidel(A, b, eps):
    n = len(A)
    x = np.zeros(n)  # zero vector

    converge = False
    while not converge:
        x_new = np.copy(x)
        for i in range(n):
            s1 = sum(A[i][j] * x_new[j] for j in range(i))
            s2 = sum(A[i][j] * x[j] for j in range(i + 1, n))
            x_new[i] = (b[i] - s1 - s2) / A[i][i]

        converge = np.linalg.norm(x_new - x) <= eps
        x = x_new

    return x

См. такжеПравить

ПримечанияПравить

СсылкиПравить