Haskell プログラム集


行列の積

Data.List

線形代数の教科書を読むときなど、小さい行列の計算ができると便利だ。Haskell でやってみる。Data.List モジュールの転置行列を作る関数 transpose を利用したいのでインポートしておく。

Prelude> :m Data.List
Prelude Data.List> 

ベクトルの計算

ベクトルはリストで表すことにする。縦ベクトルと横ベクトルがあるが、それは適当に頭の中で読み替えることにする。

Prelude Data.List> a = [1,2,3]; b = [4,5,6]
Prelude Data.List> a
[1,2,3]

ベクトルの加算 add とスカラ積 scala 、ドット積 dot のプログラムは簡単だ。

Prelude Data.List> add x y = zipWith (+) x y
Prelude Data.List> scala a x = map (*a) x
Prelude Data.List> dot x y = sum $ zipWith (*) x y

Prelude Data.List> add a b
[5,7,9]
Prelude Data.List> scala 10 a
[10,20,30]
Prelude Data.List> dot a b
32

行列の計算

行列は行ベクトルのリストで表すことにする。

Prelude Data.List> m1 = [[1,2],[3,4]]; m2 = [[5,6],[7,8]]
Prelude Data.List> m1
[[1,2],[3,4]]

行列の加算はベクトルの加算 add を利用して定義する。

Prelude Data.List> addm m n = zipWith add m n
Prelude Data.List> addm m1 m2
[[6,8],[10,12]]

行列の積はちょっと面倒だが、行列の積の要素は、第1項の行ベクトルと、第2項の列ベクトルであることに注目する。第2項の列ベクトルを取り出すのに transpose 関数を用いて第2項の転置行列を作るのが工夫だ。

Prelude Data.List> elements m n = [dot x y| x <- m, y <- transpose n]
Prelude Data.List> elements m1 m2
[19,22,43,50]

これでは1本の長いリストになってしまうので、これを切り分けて行ベクトルのリストにする関数 slice を作る。

Prelude Data.List> slice _ [] = []; slice n x = take n x : slice n
 (drop n x)
Prelude Data.List> slice 2 [19,22,43,50]
[[19,22],[43,50]]

最終的に両列の積 multm は次のようになる。

Prelude Data.List> multm m n = slice (length m) $ elements m n
Prelude Data.List> multm m1 m2
[[19,22],[43,50]]
Prelude Data.List> multm m1 [[1,0],[0,1]]
[[1,2],[3,4]]

Haskell では行列の積だって for ループを使わないで計算できる。