Metoda Gauss-Seidel pentru rezolvarea unui sistem de ecuații liniare
Metoda Gauss-Seidel (metoda Seidel, procesul Libman, metoda substituției succesive) este o metodă iterativă clasică pentru rezolvarea unui sistem de ecuații liniare .
Numit după Seidel și Gauss .
Enunțul problemei
Luați sistemul:
, unde
Sau
Și vom arăta cum poate fi rezolvată folosind metoda Gauss-Seidel.
Metoda
Pentru a clarifica esența metodei, rescriem problema în formă
Aici, în a- a ecuație, am transferat în partea dreaptă toți termenii care conțin , pentru . Această intrare poate fi reprezentată ca
unde, în notația acceptată, înseamnă o matrice a cărei diagonală principală conține elementele corespunzătoare ale matricei și toate celelalte zerouri; în timp ce matricele și conțin părți triunghiulare superioare și inferioare , pe diagonala principală a cărora sunt zerouri.
Procesul iterativ din metoda Gauss-Seidel este construit conform formulei
după alegerea aproximării iniţiale adecvate .
Metoda Gauss-Seidel poate fi privită ca o modificare a metodei Jacobi . Ideea principală a modificării este că noile valori sunt folosite aici de îndată ce sunt primite, în timp ce în metoda Jacobi nu sunt utilizate până la următoarea iterație:
Unde
Astfel, componenta i -a a aproximării -a este calculată prin formula
De exemplu, când :
, acesta este
, acesta este
, acesta este
Condiție de convergență
Să prezentăm o condiție suficientă pentru convergența metodei.
|
Teorema . Fie, undeeste matricea inversă cu. Apoi, pentru orice alegere de aproximare inițială:
- metoda Gauss-Seidel converge;
- rata de convergenţă a metodei este egală cu rata de convergenţă a unei progresii geometrice cu numitorul ;
- estimarea corectă a erorii: .
|
|
Condiție de încetare
Condiția pentru încheierea procesului iterativ Seidel atunci când precizia este atinsă într-o formă simplificată are forma:
O condiție mai precisă pentru terminarea procesului iterativ o are forma
și necesită mai multe calcule. Bun pentru matrici rare .
Exemplu de implementare în C++
#include <iostream>
#include <cmath>
folosind namespace std ;
// Încheierea condiției
bool converge ( dublu xk [ 10 ], dublu xkp [ 10 ], int n , dublu eps )
{
dubla norma = 0 ;
pentru ( int i = 0 ; i < n ; i ++ )
norma += ( xk [ i ] - xkp [ i ]) * ( xk [ i ] - xkp [ i ]);
return ( sqrt ( norm ) < eps );
}
dublu okr ( dublu x , dublu eps )
{
int i = 0 ;
double neweps = eps ;
în timp ce ( neweps < 1 )
{
i ++ ;
neweps *= 10 ;
}
int okr = pow ( dublu ( 10 ), i );
x = int ( x * okr + 0,5 ) / dublu ( okr );
întoarce x ;
}
diagonala bool ( dublu a [ 10 ][ 10 ], int n )
{
int i , j , k = 1 ;
sumă dublă ;
pentru ( i = 0 ; i < n ; i ++ ) {
suma = 0 ;
pentru ( j = 0 ; j < n ; j ++ ) suma += abs ( a [ i ][ j ]);
sum -= abs ( a [ i ][ i ]);
dacă ( suma > a [ i ][ i ])
{
k = 0 _
cout << a [ i ][ i ] << " < " << sum << endl ;
}
altfel
{
cout << a [ i ][ i ] << " > " << sum << endl ;
}
}
return ( k == 1 );
}
int main ()
{
setlocale ( LC_ALL , "" );
dublu eps , a [ 10 ][ 10 ], b [ 10 ], x [ 10 ], p [ 10 ];
int n , i , j , m = 0 ;
metoda int _
cout << "Introduceți dimensiunea matricei pătrate: " ;
cin >> n ;
cout << "Introduceți precizia de calcul: " ;
cin >> eps ;
cout << "Completați matricea A: " << endl << endl ;
pentru ( i = 0 ; i < n ; i ++ )
pentru ( j = 0 ; j < n ; j ++ )
{
cout << "A[" << i << "][" << j << "] = " ;
cin >> a [ i ][ j ];
}
cout << endl << endl ;
cout << "Matricea ta A este: " << endl << endl ;
pentru ( i = 0 ; i < n ; i ++ )
{
pentru ( j = 0 ; j < n ; j ++ )
cout << a [ i ][ j ] << " " ;
cout << endl ;
}
cout << endl ;
cout << "Completează coloana pentru membri gratuiti: " << endl << endl ;
pentru ( i = 0 ; i < n ; i ++ )
{
cout << "B[" << i + 1 << "] = " ;
cin >> b [ i ];
}
cout << endl << endl ;
/*
Progresul metodei, unde:
a[n][n] - Matricea coeficienților
x[n], p[n] - Soluții curente și anterioare
b[n] - Coloana părților drepte
Toate tablourile de mai sus sunt reale și
trebuie definite în programul principal,
de asemenea, în tabloul x[n] ar trebui să puneți inițiala
aproximarea coloanei cu soluție (de exemplu, toate zerourile)
*/
pentru ( int i = 0 ; i < n ; i ++ )
x [ i ] = 1 ;
cout << "Dominanță diagonală: " << endl ;
dacă ( diagonala ( a , n )) {
do
{
pentru ( int i = 0 ; i < n ; i ++ )
p [ i ] = x [ i ];
pentru ( int i = 0 ; i < n ; i ++ )
{
var dublu = 0 ;
pentru ( int j = 0 ; j < n ; j ++ )
if ( j != i ) var += ( a [ i ][ j ] * x [ j ]);
x [ i ] = ( b [ i ] - var ) / a [ i ][ i ];
}
m ++ ;
} în timp ce ( ! converge ( x , p , n , eps ));
cout << "Decizie de sistem:" << endl << endl ;
for ( i = 0 ; i < n ; i ++ ) cout << "x" << i << " = " << okr ( x [ i ], eps ) << "" << endl ;
cout << "Iterații: " << m << endl ;
}
else {
cout << "Fără dominanță diagonală" << endl ;
}
sistem ( „pauză” );
returnează 0 ;
}
Exemplu de implementare în Python
import numpy ca np
def seidel ( A , b , eps ):
n = len ( A )
x = np . zerouri ( n ) # vector zero
converge = Fals
în timp ce nu converge :
x_new = np . copie ( x )
pentru i în interval ( n ):
s1 = sumă ( A [ i ][ j ] * x_new [ j ] pentru j în interval ( i ))
s2 = sumă ( A [ i ][ j ] * x [ j ] pentru j în interval ( i + 1 , n ))
x_new [ i ] = ( b [ i ] - s1 - s2 ) / A [ i ][ i ]
converge = np . sqrt ( suma (( x_new [ i ] - x [ i ]) ** 2 pentru i în interval ( n ))) <= eps
x = x_new
întoarce x
Vezi și
Note
Link -uri
Metode de rezolvare a SLAE |
---|
Metode directe |
|
---|
Metode iterative |
|
---|
General |
|
---|