NMatrix, NVector


NMatrix

NArrayのサブクラスです。最初の2次元がMatrix用の次元です。 残りの次元は多次元配列として、NArrayの次元と同様に扱われます

NArrayの次元が FORTRAN style なので、NMatrixの次元の順序は 数学表記の添字の順序とは逆になります。

NVector

NArrayのサブクラスです。最初の1次元がVector用の次元です。 残りの次元は多次元配列です。


クラス次元

NMatrix および NVector の次元をクラス次元 と呼びます。これはサブクラスを作る時に クラス定数 CLASS_DIMENSION で指定します。

各クラスのクラス次元は次のようになります。


演算

NArrayの演算は Element-wize ですが、 NMatrix, NVectorクラスは 当然 Matrix, Vector の演算になります。

NMatrix/NVector と NArray の演算では、NArray は Scalarとして機能します。 オブジェクトの持つ次元からクラス次元を引いた残りは NArrayの多次元配列と同じように機能します。 (サイズ1の次元の繰り返しなど。)

これにより、3次元 Vector の 100x100 の 2次元配列に Matrix を掛けて座標変換、というような場合でも、 スクリプトでループを書く必要がないので、非常に高速に処理できます。

例:
  
% irb -r nmatrix

irb(main):001:0> m = NMatrix.float(2,2).indgen!
NMatrix.float(2,2):
[ [ 0.0, 1.0 ],
  [ 2.0, 3.0 ] ]

irb(main):002:0> a = NArray.float(2).indgen!+1
NArray.float(2):
[ 1.0, 2.0 ]

irb(main):003:0> a * m
NMatrix.float(2,2,2):
[ [ [ 0.0, 1.0 ],
    [ 2.0, 3.0 ] ],
  [ [ 0.0, 2.0 ],
    [ 4.0, 6.0 ] ] ]

irb(main):004:0> a + m
TypeError: Illegal operation: NArray + NMatrix
./nmatrix.rb:109:in `coerce_rev'
(irb):4:in `+'
(irb):4:in `irb_binding'


Slicing

NArrayと同様に NMatrix、NVectorも a[1,2] というように 要素または範囲取り出しが出来ます。 ただし、クラス次元 における取り出しは、 NArrayの規則とは少し異なります。 例:
  
% irb -r nmatrix

irb(main):001:0> m = NMatrix.float(2,2,2).indgen!
NMatrix.float(2,2,2):
[ [ [ 0.0, 1.0 ],
    [ 2.0, 3.0 ] ],
  [ [ 4.0, 5.0 ],
    [ 6.0, 7.0 ] ] ]

irb(main):002:0> m[1,1,true]
NArray.float(2):
[ 3.0, 7.0 ]

irb(main):003:0> m[0..1,1,true]
NMatrix.float(2,1,2):
[ [ [ 2.0, 3.0 ] ],
  [ [ 6.0, 7.0 ] ] ]

線形方程式を解く

m が square NMatrix, x, y が NVector で、 m, y が与えられているとき、
  
  y = m * x
を解いて xを求めたい時は、
  
  x = y / m
により答が得られます。これは
  
  x = m.lu.solve(y)
と書くのと同等です。つまり、NMatrix#lu メソッドにより m をLU分解し、 その結果を NMatrixLU クラスのインスタンス として返します。さらに NMatrixLU#solve メソッドにより解を計算します。 もし同じMatrixで複数のVectorを解きたい時は、/ 演算子を使わず、 一度だけ m.lu を計算して NMatrixLU#solve メソッドを使う方が 効率的です。

また、
  
  x = y / m
は、数学的には
  
  x = m**-1 * y
と同等なので、順序が逆になることに注意して下さい。 (Octaveなどではバックスラッシュを使って同じ順序にしていますが、 Rubyにはないので ^^;;; )

なお、LU分解は Ruby Object 型 配列でも使えます。
  
% irb -r nmatrix -r rational

irb(main):001:0> m = NMatrix.object(4,4).collect!{Rational(rand(10))}
NMatrix.object(4,4):
[ [ Rational(3, 1), Rational(6, 1), Rational(5, 1), Rational(3, 1) ],
  [ Rational(1, 1), Rational(6, 1), Rational(2, 1), Rational(0, 1) ],
  [ Rational(0, 1), Rational(3, 1), Rational(1, 1), Rational(7, 1) ],
  [ Rational(2, 1), Rational(8, 1), Rational(9, 1), Rational(1, 1) ] ]

irb(main):002:0> m/m
NMatrix.object(4,4):
[ [ Rational(1, 1), Rational(0, 1), Rational(0, 1), Rational(0, 1) ],
  [ Rational(0, 1), Rational(1, 1), Rational(0, 1), Rational(0, 1) ],
  [ Rational(0, 1), Rational(0, 1), Rational(1, 1), Rational(0, 1) ],
  [ Rational(0, 1), Rational(0, 1), Rational(0, 1), Rational(1, 1) ] ]


Back to Numerical Ruby
Masahiro Tanaka Last modified: May 13, 2001