Требуется реализовать алгоритм Зейделя для решения СЛАУ. Хочу реализовать на Хаскеле. Я Хаскель только учу и уверен, что я всё сделал не так, как сделали бы нормальные люди. Прошу поправить.
Про метод Зейделя (из Канатников, Крищенко "Линейная алгебра"):
Если имеется СЛАУ
![$Ax=b$ $Ax=b$](https://dxdy-03.korotkov.co.uk/f/6/f/f/6ffa573707fca115cad7b243d91a710982.png)
, то мы сначала приводим её к нормальному виду
![$A^\top Ax=A^\top b$ $A^\top Ax=A^\top b$](https://dxdy-02.korotkov.co.uk/f/9/f/3/9f36b72de2c6bc2d690ee3b5b58ab0c782.png)
, т. к. чтобы алгоритм сходился, нужно, чтобы
![$A$ $A$](https://dxdy-02.korotkov.co.uk/f/5/3/d/53d147e7f3fe6e47ee05b88b166bd3f682.png)
была положительно определённой и симметрической.
![$A^\top A$ $A^\top A$](https://dxdy-03.korotkov.co.uk/f/6/2/d/62d30a7f7c1a0d017971b1e8357191ba82.png)
такой является, и если исходная СЛАУ имеет решение, то и нормальная СЛАУ будет иметь такое же. Пускай СЛАУ
![$Ax=b$ $Ax=b$](https://dxdy-03.korotkov.co.uk/f/6/f/f/6ffa573707fca115cad7b243d91a710982.png)
уже нормальная. Тогда сам алгоритм:
![$$x_i^{N+1}=\frac{1}{a_{ii}}\left(-\sum_{j=1}^{i-1} a_{ij} x_j^{N+1}-\sum_{j=i+1}^{n} a_{ij} x_j^N+b_i\right),\quad i=\overline{1,n}.$$ $$x_i^{N+1}=\frac{1}{a_{ii}}\left(-\sum_{j=1}^{i-1} a_{ij} x_j^{N+1}-\sum_{j=i+1}^{n} a_{ij} x_j^N+b_i\right),\quad i=\overline{1,n}.$$](https://dxdy-04.korotkov.co.uk/f/3/9/e/39eace76a46e5c5ea52d6473f0badac482.png)
где
![$n$ $n$](https://dxdy-02.korotkov.co.uk/f/5/5/a/55a049b8f161ae7cfeb0197d75aff96782.png)
-- число уравнений в СЛАУ. (В правой части есть
![$x_j^{N+1}$ $x_j^{N+1}$](https://dxdy-02.korotkov.co.uk/f/d/1/d/d1d7f7aef9ae879d3f9e1bd246983b5782.png)
, но когда считается
![$x_i^{N+1}$ $x_i^{N+1}$](https://dxdy-04.korotkov.co.uk/f/7/3/2/73224957ec995e84841c7102c239747782.png)
, он уже подсчитан.)
(Код)
Код:
-- Тут можно не читать, я просто определяю некоторые матричные операции
type Vector = [Float]
type Matrix = [Vector]
infix 9 !
(!) :: Matrix -> (Int,Int) -> Float
m ! (i,j) = m !! (i-1) !! (j-1)
width :: Matrix -> Int
width m = length $ m !! 0
height :: Matrix -> Int
height = length
mul :: Matrix -> Matrix -> Matrix
mul a b | width a == height b =
[[sum [a!(i,k) * b!(k,j) | k <- [1..n]] | j <- [1..n]] | i <- [1..m]] where
n = width a
m = height b
transpose :: Matrix -> Matrix
transpose m = [[m!(i,j) | i <- [1..(height m)]] | j <- [1..(width m)]]
-- Вот сама функция решения СЛАУ
-- a', b' -- это матрицы A и b соответственно. n -- количество итераций (пока задаю сам).
solve :: Matrix -> Vector -> Int -> Vector
solve a' b' n | width a' == length b' = x n where
t = transpose a' -- A^T
a = t `mul` a' -- A^T A
b = (transpose $ mul t $ transpose [b']) !! 0 -- A^T b
r = length b -- n
x 0 = replicate r 0
x (n+1) = [(b!!(i-1) - sum [ a!(i,j) * (x (n+1))!!(j-1) | j <- [1..(i-1)]]
- sum [ a!(i,j) * (x n)!!(j-1) | j <- [(i+1)..r]]) / a!(i,i)
| i <- [1..r]]
Код работает:
Код:
-- {x+2y=4, 3x-4y=-2}, {x=1.2, y=1.4}
*Main> solve [[1,2],[3,-4]] [4,-2] 10
[1.1972656,1.3986328]
Но очень медленно (уже для
![$n=4$ $n=4$](https://dxdy-02.korotkov.co.uk/f/1/8/0/180bde3f581b83f9e0205ff90404a62d82.png)
и
![$N=8$ $N=8$](https://dxdy-04.korotkov.co.uk/f/f/3/9/f394301d18d808196f75d7c6763b621682.png)
в ghci работает несколько секунд). Наверное я неправильно подошёл к реализации функции
![$x$ $x$](https://dxdy-04.korotkov.co.uk/f/3/3/2/332cc365a4987aacce0ead01b8bdcc0b82.png)
. Она у меня сейчас возвращает список и, я боюсь, много раз вычисляется одно и то же. Была идея сделать бесконечный список решений
![$(x(0),x(1),\ldots)$ $(x(0),x(1),\ldots)$](https://dxdy-04.korotkov.co.uk/f/3/8/8/3881631c86fbaf2ae7b12902eb0ec80c82.png)
, чтобы при вычислении
![$x(n+1)$ $x(n+1)$](https://dxdy-04.korotkov.co.uk/f/b/f/a/bfa03e1b73d4cba50a3eef37c4f20d5782.png)
функция ссылаться к предыдущему элементу списка. Ничего не вышло
![Sad :-(](./images/smilies/icon_sad.gif)