Требуется реализовать алгоритм Зейделя для решения СЛАУ. Хочу реализовать на Хаскеле. Я Хаскель только учу и уверен, что я всё сделал не так, как сделали бы нормальные люди. Прошу поправить.
Про метод Зейделя (из Канатников, Крищенко "Линейная алгебра"):
Если имеется СЛАУ
, то мы сначала приводим её к нормальному виду
, т. к. чтобы алгоритм сходился, нужно, чтобы
была положительно определённой и симметрической.
такой является, и если исходная СЛАУ имеет решение, то и нормальная СЛАУ будет иметь такое же. Пускай СЛАУ
уже нормальная. Тогда сам алгоритм:
где
-- число уравнений в СЛАУ. (В правой части есть
, но когда считается
, он уже подсчитан.)
(Код)
Код:
-- Тут можно не читать, я просто определяю некоторые матричные операции
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]
Но очень медленно (уже для
и
в ghci работает несколько секунд). Наверное я неправильно подошёл к реализации функции
. Она у меня сейчас возвращает список и, я боюсь, много раз вычисляется одно и то же. Была идея сделать бесконечный список решений
, чтобы при вычислении
функция ссылаться к предыдущему элементу списка. Ничего не вышло