2010/07/12
Haskell で行列式を求める
前回紹介した、数の組み合わせのリストを返す処理を使って、正方行列の行列式を求めるプログラムを作成する。
ここでは、行列式の定義 [1] から求めているので、基本変形等を用いた手法よりも若干効率が悪いかもしれない。
コードの全文は次のようになる。
mxA = [[1,3,-4,2],
[2,9,1,1],
[0,-2,6,1],
[-1,3,9,2]]
main = print $ determinant mxA
determinant :: [[Int]] -> Int
determinant mx = arrayAdd $ map (\xs -> (arrayMul $ selectArray 1 xs) * (oversetSign xs)) $
makePerm $ length mx
where
selectArray :: Int -> [Int] -> [Int]
selectArray cnt xs | null xs = []
| True = (head $ reverse $ take (head xs) $ head $ reverse $ take cnt mx):
selectArray (cnt+1) (tail xs)
-- 配列の転倒数から符号を求める
oversetSign :: [Int] -> Int
oversetSign xs = if (mod (oversetNum xs) 2) > 0 then -1 else 1
where
oversetNum :: [Int] -> Int
oversetNum (x:xs) | xs == [] = 0
| True = arrayAdd (map (\y -> if x > y then 1 else 0) xs) + oversetNum xs
-- 配列の合計値を求める
arrayAdd :: [Int] -> Int
arrayAdd (x:xs) | xs == [] = x
| True = x + (arrayAdd xs)
-- 配列の各要素の積算
arrayMul :: [Int] -> Int
arrayMul (x:xs) | xs == [] = x
| True = x * (arrayMul xs)
makePerm :: Int -> [[Int]]
makePerm n = (perm $ makeArray n) n
where
perm :: [Int] -> Int -> [[Int]]
perm [] _ = []
perm xs 0 = [[]]
perm xs 1 = map (:[]) xs
perm xs n = concatMap (pm n) $ divid xs
where pm _ (_,[]) = []
pm n (hs,(t:ts)) = map (t:) $ perm (hs ++ ts) (n-1)
divid :: [Int] -> [([Int],[Int])]
divid xxs@(x:xs) = ([],xxs) : [(x:ys,zs) | (ys,zs) <- divid xs]
divid [] = [([],[])]
makeArray :: Int -> [Int]
makeArray i | i == 0 = []
| True = i:(makeArray (i-1))
makePerm 関数が、前回までに話した、数の組み合わせのリストを求める関数である。
determinant が行列式を求めるメイン処理になり、makePerm 関数によって得たリストを map 関数に渡し、各要素について selectArray 関数を呼び出している。
ここでは makePerm によって得た組み合わせの数をインデックスとた配列を、行列の中から取得するという処理である。具体的に [2,4,3,1] が渡された場合には、行列 M の [m12, m24, m33, m31] を返す。
そして arrayMul 関数で受け取ったリストの各項目に対する積算を行う。そして、oversetSign 関数で makePerm 関数から得た数列の転倒数から符号を設定し、最後に各項目に対する加算を arrayAdd 関数で行っている。
[1] http://ja.wikipedia.org/wiki/%E8%A1%8C%E5%88%97%E5%BC%8F
- Category(s)
- 学習経過
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/haskell-884c52175f0f30926c423081308b/tbping