LoginSignup
8
6

More than 5 years have passed since last update.

Haskellの行列計算 - 保存と読み出し、複素行列について

Last updated at Posted at 2018-03-25

hmatrix について(前書き)

高速な行列計算ライブラリーです。基本的な使い方はほかの方のqiita記事にも詳しく書いてありますので省略しますが、私が躓いたところに関して、身の丈に合った解説をします。

一言だけ初歩的解説しますと、import Numeric.LinearAlgebraで呼び出します。

大きく2点躓きました。1つは複素行列の定義、2つは外部ファイルからの行列読み込みです。そしてそれらの合成にも躓きました。

複素行列

複素行列の定義

hmatrixは複素行列の計算にも対応しいる。(というより、していないと閉じない計算が多い)
定義する場合は、後で複素行列であることを明示すればよい。

let a = (2><2)[1,2,3,4] :: Matrix (Complex Double)
let b = (2><2)[1:+2,2,3,4:+(-4)] :: Matrix (Complex Double)

よくある間違いとして(私がよくやる間違い)

let a = (2><2)[1..4] :: Matrix (Complex Double)
--複素数なので".."表現が使えない。
let b = (2><2)[1:+2,2,3,4:+(-4)]
--Matrix Double として扱おうとしてエラーになる。ちょま、

実行列と複素行列の混ざった計算

haskellはコンパイラが型推論してくれるが、Matrixに関しては自分で変換する必要がある。
実行列 a と複素行列 b の積は

let a = (2><2)[1,0,0,1]::Matrix Double
let b = (2><2)[-1,0,0,1]::Matrix (Complex Double)

let c = (complex a) <> b

とする。ちなみに、Complex Doubleに complex b などと書いても大丈夫なので、場合によっては複素行列になるといった場合にも対応できる(可読性は下がる)。

行列の保存

saveMatrix

saveMatrix "FilePath" "%lf" a

列は半角スペース区切り行は改行区切りで"FilePath"に出力される。カンマでも区切りたいなら、

saveMatrix "FilePath" "%lf," a

のようにする。こうすると半角スペース、改行に加えカンマが毎回挿入される。同様に任意の区切りが可能。

行列の読み出し

ファイルから行列をロードする方法

let a = loadMatrix "FilePath"

でとることができる。しかし、a の型は IO (Matrix Double) のようなIO型になるため、

svd a
a + a

のようなことはできない。そこでIO型からMatrix Doubleを取り出すため、"<-"を用います。
(System.IO.UnsafeのunsafePerformIOという関数を用いる方法もあります。)

a <- loadMatrix "FilePath"
svd a

これにより、ファイルから読み込んだ行列用いて計算し行くことができる。
大きさは自動で判別されるが、列は半角スペース、行は改行で区切られている必要がある。(カンマ区切りはダメ)

複素行列の保存と読み出し

saveMatrix, LoadMatrixは実行列Matrix Doubleにしか対応していない。複素行列を保存する場合、自前で作るか、実部、虚部を分けるかする必要がある。ここでは後者を紹介する。

toComplex, fromComplexを用いると比較的簡単に書くことができる。

save

let a = (2><2)[1:+2,2,3,4]::Matrix(Complex Double)
let (a_r,a_c) = fromComplex a
saveMatrix "real.txt" "%lf" a_r
saveMatrix "complex.txt" "%lf" a_c

2行で書くと

let a = (2><2)[1:+2,2,3,4]::Matrix(Complex Double)
saveMatrix "real.txt" "%lf" (fst$fromComplex a)
saveMatrix "complex.txt" "%lf" (snd$fromComplex a)

プチ解説するとfst, sndは2要素のタプルに対して、第1成分と第2成分を取るものです。

load

a_r <-loadMatrix "real.txt"
a_c <-loadMatrix "complex.txt"
let a = toComplex (a_r,a_c)

あとがき

今後も、このテーマに関して新たな見地を得たら加筆修正しようと思います。忌憚なきご意見を頂ければ幸いです。(近いうちに複素行列を使う例を挙げようと思います。)

修正歴

大きな修正は記録しておきます。(加筆はここには書きません)

  • IO モナドから中身を取り出すなら、unsafePerformIO でもいいですが単純に"<-"で良いのでそこを修正しました。
8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6