module Matrix.Pivot (split1, permute, permuteLL, vswap, mswap) where
--TODO Find better home for split1 and maybe others
import Data.Array
import Data.List
--
-- Trivial Pivoting Routines
--
mswap :: [Int] -> Array (Int,Int) Double -- ^ A
-> Array (Int,Int) Double -- ^ LU(A)
mswap n a = a'
where a' = array bnds [ ((i,j), luij i j) | (i,j) <- range bnds ]
luij i j = a!(ie i,j)
bnds = bounds a
ie i = n!!(i - 1)
vswap :: [Int] -> Array Int Double -- ^ A
-> Array Int Double -- ^ LU(A)
vswap n a = a'
where a' = array bnds [ (j, luij j) | j <- range bnds ]
luij j = a!(ie j)
bnds = bounds a
ie j = n!!(j - 1)
rows1 :: Int -> [Double] -> [Int]
rows1 _ [] = []
rows1 n (x:xs) | abs (x) > 0 = (n + 1) : rows1 (n + 1) xs
| otherwise = rows1 (n + 1) xs
rowz l = rows1 0 l
split1 _ [] = []
split1 n l = (take n l) : (split1 n $ drop n l)
permuteLL a = rowlist $ map rowz $ transpose $ split1 b $ elems a
where b = fst $ snd $ bounds a
permute a | l == [] = error "singular matrix detected"
| otherwise = tt
where tt = l!!(head $ findIndices ( == (maximum n)) n)
n = map zz (dd a l)
zz a = foldr1 (+) (map abs (elems (diag a)))
dd a d | d == [] = []
| otherwise = mswap (head d) a : dd a (tail d)
l = permuteLL a
rowlist :: Eq a => [[a]] -> [[a]]
rowlist [] = [[]]
rowlist (set:sets) = [x:xs | xs <- rowlist sets, x <- set, not(x `elem` xs)]
diag :: Array (Int,Int) Double -- ^ A
-> Array (Int,Int) Double -- ^ LU(A)
diag a = a'
where a' = array bnds [ ((i,j), luij i j) | (i,j) <- range bnds ]
luij i j | i == j = a!(i,j)
| otherwise = 0
bnds = bounds a
|