(Library) NArrayExt: NArrayの拡張ライブラリを動的に作る

概要

NArray は拡張ライブラリであるため、メソッドを使える場合はループが C で回るため、 高速に計算することが出来る。 しかしながら、 インデックスをずらすなど、NArray のメソッドでは対応出来ない計算もあり、 その場合は Ruby でループを回す必要があり、その場合は実効速度が遅い。

そこで、拡張ライブラリを自前で作成したくなることがあるが、 敷居が高い。

以下のページで、1から書くよりも勘弁に拡張ライブラリを作成する方法が紹介されている。

(Tips) NArrayの拡張ライブラリを動的に作る(1)

しかしながら、これでもまだ敷居が高いのではと思われる。

そこで、より簡単に C で計算するための DSL を作成した。 制限はあるものの、Ruby で記述したコードが C に自動で変換されて実行されるため、拡張ライブラリの作成方法の知識が無くとも利用出来る。

今は四則演算しか対応していない。

使用方法の説明

  • 最初にライブラリをロードする narray_ext.rb
    • require "narray_ext"
  • C で計算したい部分を NumRu::NArrayExt.c_loop のブロック内に記述する。
    • 引数に NArray を並べる (NArray 以外は不可)
    • 与えた実引数と同じ数の仮引数をブロックに与える必要がある (名前は同じである必要は無い)
    • 何回読んでも良い
    • 呼ぶ毎にCのソースコード生成、コンパイル、実行が行われる。
    • 戻り値は nil
      • 結果の配列も引数として渡す必要がある
  • C で回すループは loop メソッドのブロックを使う
    • 第一引数、第二引数に、それぞれループの開始、終了のインデックス番号を与える

require "./narray_ext"
include NumRu


x = NArray.sint(2,3).indgen
y = NArray.sint(2,3).indgen(1)
z1 = NArray.sint(2,3)
z2 = NArray.sint(2,3)
z3 = NArray.sint(2,3)
z4 = NArray.sfloat(2,3)

NArrayExt.c_loop(x,y,z1,z2,z3,z4) do |x,y,z1,z2,z3,z4|
  loop(0,2) do |j|
    loop(0,1) do |i|
      z1[i,j] = x[i,j]*2.0 + y[i,j] + 1.0
      z2[i,j] = ( x[i,j] + y[i,j] ) * x[i,j]
    end
    loop(0,0) do |i|
      z3[i,j] = x[0,j] + y[i+1,j]
    end
  end
  loop(0,1) do |j|
    loop(0,1) do |i|
      z4[i,j] = x[i,j] + y[i,j+1]
    end
  end
end



z = x*2.0+y+1.0
p z1==z
print "\n"

z = (x+y) * x
p z2==z
print "\n"

z = z3.dup.fill(0)
z[0,true] = x[0,true] + y[1,true]
p z3==z
print "\n"

z = z4.dup.fill(0)
z[true,0..1] = x[true,0..1] + y[true,1..2]
p z4==z
print "\n"


begin
  NArrayExt.c_loop(x,y,z1) do |x,y,z1|
    loop(0,2) do |j|
      loop(0,1) do |i|
        z1[i,j] = x[0,j] + y[i+1,j] # exceed boundary
      end
    end
  end
rescue ArgumentError
  p true
else
  raise "exception must be raised"
end

更新日時:2016/02/16 21:39:23
キーワード:
参照: