- •Реферат
- •Метод Гауса - Жордана
- •Метод Гаусса розв'язання системи лінійних рівнянь
- •Метод Гаусса розв'язання системи лінійних рівнянь
- •Базовая схема
- •Пошук опорного елемента (pivoting)
- •Вироджені випадки
- •Реалізація
- •Асимптотика
- •Більш точна оцінка числа дій
- •Метод Гауса на java
- •Блок схема алгоритму методу Гауса
Реалізація
Наведемо тут реалізацію алгоритму Гауса-Жордана з евристикою partial pivoting (вибором опорного елемента як максимуму за стовпцем).
На вхід функції gauss() передається сама матриця системи a. Останній стовпець матриці a — це в наших старих позначеннях стовпець b вільних коефіцієнтів (так зроблено для зручності програмування — т. к. в самому алгоритмі всі операції з вільними коефіцієнтами b повторюють операції з матрицею A).
Функція повертає число розв'язків системи (0, 1 або ∞) (нескінченність позначена в коді спеціальної константою INF, якій можна задати будь-яке велике значення). Якщо хоча б одне рішення існує, то воно повертається у векторі ans.
int gauss (vector < vector<double> > a, vector<double> & ans) {
int n = (int) a.size();
int m = (int) a[0].size() - 1;
vector<int> where (m, -1);
for (int col=0, row=0; col<m && row<n; ++col) {
int sel = row;
for (int i=row; i<n; ++i)
if (abs (a[i][col]) > abs (a[sel][col]))
sel = i;
if (abs (a[sel][col]) < EPS)
continue;
for (int i=col; i<=m; ++i)
swap (a[sel][i], a[row][i]);
where[col] = row;
for (int i=0; i<n; ++i)
if (i != row) {
double c = a[i][col] / a[row][col];
for (int j=col; j<=m; ++j)
a[i][j] -= a[row][j] * c;
}
++row;
}
ans.assign (m, 0);
for (int i=0; i<m; ++i)
if (where[i] != -1)
ans[i] = a[where[i]][m] / a[where[i]][i];
for (int i=0; i<n; ++i) {
double sum = 0;
for (int j=0; j<m; ++j)
sum += ans[j] * a[i][j];
if (abs (sum - a[i][m]) > EPS)
return 0;
}
for (int i=0; i<m; ++i)
if (where[i] == -1)
return INF;
return 1;
}
У функції підтримуються два покажчика — на поточний стовпець col і поточний рядок row.
Також заводиться вектор where, в якому для кожної змінної записано, в якому рядку повинна вийти (іншими словами, для кожного стовпця записаний номер рядка, в якому цей стовпець відмінний від нуля). Цей вектор потрібен, оскільки деякі змінні могли не "визначитися" в ході рішення (тобто це-незалежні змінні, яким можна присвоїти довільне значення, наприклад, у наведеній реалізації нулі).
Реалізація використовує техніку partial pivoting, виробляючи пошук рядка максимальним за модулем елементом, і переставляючи потім цю рядок у позицію row (хоча явну перестановку рядків можна замінити обміном двох індексів в деякому масиві, на практиці це не дасть реального виграшу, т. к. на обміни витрачається O(n2) операцій).
У цілях простоти поточний рядок не ділиться на опорний елемент — так що в підсумку після закінчення роботи алгоритму матриця стає не одиничною, а діагональною (втім, мабуть, поділ рядка на провідний елемент дозволяє дещо зменшити виникають похибки).
Після знаходження рішення воно підставляється назад в матрицю — щоб перевірити, чи система хоча б одне рішення чи ні. Якщо перевірка знайденого рішення пройшла успішно, то функція повертає 1 або ∞ — в залежності від того, чи є хоча б одна незалежна змінна або немає.
