Haskell で行列計算
今回は行列の演算 (加算・乗算) を行うプログラムを Haskell で書いてみた。
もちろん同じプログラムも C や Perl で書けるが。行列の演算を行う際に、多くの場合2重ループを使って実現すると思うが。Haskell の場合には、リストモナドを使って簡潔に書く事ができる。
以下がそのコード。
[calcMatrix.hs]
実行結果は次のようになる。
上の実行結果は 2*3 行列と 3*2 行列の積算結果だが。これを逆にすると、次のようにちゃんと 3*3 行列が出てくる。
また上述の main 関数中では使っていないが。他にも行列同士の加算や行列とスカラの乗算を行う演算子を定義した。よかったら、遊んでみてほしい。
もちろん同じプログラムも C や Perl で書けるが。行列の演算を行う際に、多くの場合2重ループを使って実現すると思うが。Haskell の場合には、リストモナドを使って簡潔に書く事ができる。
以下がそのコード。
[calcMatrix.hs]
mxA = [[1,2],
[3,4],
[5,6]]
mxB = [[2,3,4],
[3,4,5]]
main = print $ mxB /**/ mxA
-- 行列とスカラの積算
(/*/) :: Int -> [[Int]] -> [[Int]]
(/*/) a mx = map (\x -> a /* x) mx
-- 行列どうしの積算
(/**/) :: [[Int]] -> [[Int]] -> [[Int]]
(/**/) mx my = let tmy = transpose my
in if length tmy == length mx
then cutArray (length mx) $ inMulti mx $ transpose my
else []
where
inMulti :: [[Int]] -> [[Int]] -> [Int]
inMulti mx my = do x <- mx
y <- my
[x /** y]
-- 配列から行列への変換
cutArray :: Int -> [Int] -> [[Int]]
cutArray len xs | xs == [] = []
| True = [(take len xs)] ++ (cutArray len $ reverse $ take ((length xs) - len) $ reverse xs)
-- 行列どうしの加算
(/++/) :: [[Int]] -> [[Int]] -> [[Int]]
(/++/) mx my = if (length mx) == (length my) then mxAdd mx my else []
where
mxAdd :: [[Int]] -> [[Int]] -> [[Int]]
mxAdd (xs:mx) (ys:my) | mx == [] || my == [] = [xs /++ ys]
| True = [xs /++ ys] ++ (mxAdd mx my)
-- ベクトルとスカラの積算
(/*) :: Int -> [Int] -> [Int]
(/*) a xs = map (\x -> x * a) xs
-- ベクトルどうしの加算
(/++) :: [Int] -> [Int] -> [Int]
(/++) xs ys = if (length xs) == (length ys) then aryAdd xs ys else []
where
aryAdd :: [Int] -> [Int] -> [Int]
aryAdd (x:xs) (y:ys) | xs == [] || ys == [] = [x + y]
| True = [x + y] ++ (aryAdd xs ys)
-- ベクトルどうしの積算
(/**) :: [Int] -> [Int] -> Int
(/**) (x:xs) (y:ys) | xs == [] || ys == [] = (x * y)
| True = (x * y) + (xs /** ys)
-- 行列 A の転置行列を求める
transpose :: [[Int]] -> [[Int]]
transpose matrix = transpose' matrix 1
where
transpose' :: [[Int]] -> Int -> [[Int]]
transpose' mx iterater | iterater > (length $ head mx) = []
| True = map (\x -> head $ reverse $ take iterater x) mx : transpose' mx (iterater + 1)
実行結果は次のようになる。
$ ghc calcMatrix.hs
$ ./a.out
[[31,40],[40,52]]
上の実行結果は 2*3 行列と 3*2 行列の積算結果だが。これを逆にすると、次のようにちゃんと 3*3 行列が出てくる。
$ ghc calcMatrix.hs
$ ./a.out
[[8,11,14],[18,25,32],[28,39,50]]
また上述の main 関数中では使っていないが。他にも行列同士の加算や行列とスカラの乗算を行う演算子を定義した。よかったら、遊んでみてほしい。
2010-07-08 20:37
nice!(0)
コメント(0)
トラックバック(0)
コメント 0