Linear systems#
Система линейных алгебраических уравнений (СЛАУ) из \(m\) уравнений с \(n\) неизвестными имеет вид
где коэффициенты \(a_{ij}\) и числа в правой части \(b_i\) считаются известными, а найти надо неизвестные переменные \(x_j\). Записывать систему линейных уравнений в таком громоздком виде не очень удобно, вместо этого чаще используют матричную запись. Коэффициенты \(a_{ij}\) естественным образом образуют матрицу \(\boldsymbol A\in\mathbb R^{m\times n}\), правая часть — вектор \(\boldsymbol b \in \mathbb R^m\), а искомые переменные — вектор \(\boldsymbol x \in \mathbb R^n\). И тогда СЛАУ переписывается в чрезвычайно простом и коротком виде
In NumPy a linear system of equations with \(m=n\) can be solved by np.linalg.solve
:
import numpy as np
from scipy.linalg import pascal
A = pascal(4, kind='lower')
A
array([[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 2, 1, 0],
[1, 3, 3, 1]], dtype=uint64)
b = np.array([1, -1, 1, -1])
np.linalg.solve(A, b)
array([ 1., -2., 4., -8.])
Gaussian elimintaion#
Если матрица СЛАУ диагональная, \(\boldsymbol A = \mathrm{diag}\{a_1, \ldots, a_n\}\), причём все \(a_k\ne 0\), то решить систему не составляет труда: \(x_k = \frac{b_k}{a_k}\). В этом случае решение единственно. Если же \(a_k = 0\) при некотором \(k\), то наличие решения зависит от значения \(b_k\): при \(b_k\ne 0\) система несовместна (решений нет), а при \(b_k = 0\) решений бесконечно много, так как любое значение \(x_k\) удовлетворяет системе уравнений.
Метод Гаусса заключается в преобразовании квадратной матрицы сначала к верхнему треугольному виду, а затем и к диагональному, с помощью элементарных шагов, не меняющих решение СЛАУ.
Transform to upper triangular form#
Идея проста: если \(a_{11} \ne 0\), занулим все остальные коэффициенты первого столбца матрицы \(\boldsymbol A\) с помощью основных элементарных преобразований
В векторном виде их можно записать как
Теперь в первом столбце все элементы нулевые, кроме первого. Применяя этот процесс последовательно к каждому следующему столбцу, приходим к искомому верхнедиагональному виду.
Единственная проблема данного алгоритма в том, что некоторые диагональные элементы \(a_{ii}\) могут оказаться нулевыми. Если это произошло, то поищем ненулевой элемент \(a_{ij}\) ниже в том же столбце. В случае успеха обменяем \(i\)-ю и \(j\)-ю строки. Такой обмен эквивалентен умножению слева на матрицу перестановки \(\boldsymbol P_{ij}\), и он не изменяет решение системы.
Если же \(a_{ij} = 0\) при всех \(j \geqslant i\), то сделать с \(i\)–м столбцом уже ничего нельзя, так как матрица оказалась вырожденной. Подробнее о вырожденных матрицах см. ниже, пока ограничимся СЛАУ с невырожденными матрицами. Такие матрицы методом Гаусса приводятся к верхнетреугольному виду с ненулевыми элементами на главной диагонали.
Оценим алгоритмическую сложность такого преобразования. Элементарное преобразование (1) требует \(O(n)\) арфметических операций, при занулении элементов \(i\)-го столбца надо произвести \(n-i\) таких преобразований. Перестановка строк требует не более \(O(n)\) операций. Поэтому суммарная сложность равна
Backward pass#
В результате прямого хода метода Гаусса невырожденная квадратная матрица \(\boldsymbol A\) превращается в верхнюю треугольную матрицу
с ненулевыми элементами на главной диагонали. Система линейных уравнений \(\boldsymbol{Ax} = \boldsymbol b\) при этом переводится в эквивалентную ей систему \(\boldsymbol{Ux} = \boldsymbol c\). Для решения последней системы используют обратный ход метода Гаусса, который состоит в последовательном исключении неизвестных, начиная с последней строки:
Вычисление переменной \(x_i\) требует \(O(n + 1 -i)\) арифметических операций, поэтому общая сложность обратного хода метода Гаусса составляет
Таким образом, суммарная сложность прямого и обратного хода метода Гаусса равна \(O(n^3) + O(n^2) = O(n^3)\).