Goで簡単な行列計算
Golangでの簡単な行列計算。
ライブラリ
gonum/matrix を利用してみる。
実装
Goのバージョンは1.4。
行列の作成
行列は、mat64.NewDense
という関数を利用して宣言する。
下記の例では、[1 2 3]
という行列をx
に代入している。
// matrix.go package main import ( "fmt" "github.com/gonum/matrix/mat64" ) func main() { elem := []float64{1, 2, 3} x := mat64.NewDense(3, 1, elem) fmt.Println(x) }
実行。
$ go run matrix.go &{{3 1 1 [1 2 3]}}
NewDense
の実装を覗いてみる。
// matrix/mat64/dense.go func NewDense(r, c int, mat []float64) *Dense { if mat != nil && r*c != len(mat) { panic(ErrShape) } if mat == nil { mat = make([]float64, r*c) } return &Dense{RawMatrix{ Rows: r, Cols: c, Stride: c, Data: mat, }} }
列数, 行数, 要素を表す配列の3つを引数として渡し、 返り値のインスタンスには、列数, 行数, Stride(=行数), 行列が含まれる。
行列の要素へのアクセス
At
を使い、位置(列と行)を引数に指定。
elem := []float64{1, 2, 3} x := mat64.NewDense(3, 1, elem) fmt.Println(x.At(1, 0)) // => 2
行列の和や積
行列の和や積などの算出。
和はAdd
, 差はSub
という関数を利用。
返り値はなく、メソッドのレシーバに演算結果が代入される。
func main() { elem_x := []float64{1, 2, 3} elem_y := []float64{4, 5, 6} elem_a := make([]float64, 3) x := mat64.NewDense(3, 1, elem_x) y := mat64.NewDense(3, 1, elem_y) a := mat64.NewDense(3, 1, elem_a) a.Add(x, y) fmt.Println(a) // => &{{3 1 1 [5 7 9]}} a.Sub(x, y) fmt.Println(a) // => &{{3 1 1 [-3 -3 -3]}} }
続いて行列積。Mul
を利用。
下記のようにinit
関数を指定しておかないと、panic: mat64: no blas engine registered: call Register()
というpanicが発生した。
package main import ( "fmt" "github.com/gonum/blas/goblas" "github.com/gonum/matrix/mat64" ) func main() { elem_x := []float64{1, 2, 3, 4} elem_y := []float64{5, 6, 7, 8} elem_a := make([]float64, 4) x := mat64.NewDense(2, 2, elem_x) y := mat64.NewDense(2, 2, elem_y) a := mat64.NewDense(2, 2, elem_a) a.Mul(x, y) fmt.Println(a) // => &{{2 2 2 [19 22 43 50]}} } func init() { mat64.Register(goblas.Blas{}) }
2x2行列の積がちゃんと出てる。
逆行列
逆行列の算出には、Inverse
を利用。
func main() { elem_x := []float64{2, 5, 1, 3} x := mat64.NewDense(2, 2, elem_x) inv_x, _ := mat64.Inverse(x) fmt.Println(inv_x) // => &{{2 2 2 [3 -5 -1 2]}} }
[[2, 5], [1, 3]]
の逆行列は、[[3, -5], [-1, 2]]
。OK。
https://github.com/gonum/matrix/blob/master/mat64/matrix.go に、Inverse
の実装が載ってる。
番外: Rubyでやる
上記でやったようなことをRubyでやるとどうなるか。 Rubyのバージョンは、2.2.0preview2。
Matrix
クラスを利用。
# matrix.rb require 'matrix' a = Matrix[[1, 2], [3, 4]] b = Matrix[[5, 6], [7, 8]] sum = a + b # => Matrix[[6, 8], [10, 12]] mul = a * b # => Matrix[[19, 22], [43, 50]] c = Matrix[[2, 5], [1, 3]] c.inverse # => Matrix[[(3/1), (-5/1)], [(-1/1), (2/1)]]
...やっぱり簡単に書ける。
おわり
Goの簡単な行列演算などを試してみた。 はじめから分かってたけど、扱いやすさではRubyやPythonにやはり軍配が上がりますかね。。 あと、行列を転置する方法がよくわからなかったw
数値計算系のライブラリもう少し充実してくれたりすると嬉しいですね。