2014/06/10(火) [n年前の日記]
#1 [ruby] 配列に入ってる整数を全て実数にしたい
Ruby で、配列に入った値を整数から実数にしたいときがあるのですけど。今まで以下のように書いてたわけで。
色々ググってたら、こういう書き方もできそうだなと。
_flatten, flatten! (Array) - Rubyリファレンス
_map, map! (Array) - Rubyリファレンス
しかし、ベンチマークを取ってみたら、flatten と map を使った書き方は微妙に遅くて。
微妙に遅いというか、3倍遅いのかな。見た目アホっぽく、ベタッと書いたほうが、まだ速い場面もあるのだなと…。
もっと違う書き方はできないかしら。
x1, y1 = a[0][0].to_f, a[0][1].to_f x2, y2 = a[1][0].to_f, a[1][1].to_f x3, y3 = a[2][0].to_f, a[2][1].to_f x4, y4 = a[3][0].to_f, a[3][1].to_fもっといい書き方ないのかなと。
色々ググってたら、こういう書き方もできそうだなと。
x1, y1, x2, y2, x3, y3, x4, y4 = a.flatten.map {|item| item.to_f }
_flatten, flatten! (Array) - Rubyリファレンス
flattenメソッドは、配列の配列を平坦化した新しい配列を返します。配列中に含まれる配列からすべて要素を取り出して、親の配列の中に並べます。
_map, map! (Array) - Rubyリファレンス
mapメソッドは、要素の数だけ繰り返しブロックを実行し、ブロックの戻り値を集めた配列を作成して返します。collectメソッドの別名です。
しかし、ベンチマークを取ってみたら、flatten と map を使った書き方は微妙に遅くて。
# 配列内の値を実数にする際のベンチマークを測定 require 'benchmark' def hoge(a) x1 = a[0][0].to_f x2 = a[1][0].to_f x3 = a[2][0].to_f x4 = a[3][0].to_f y1 = a[0][1].to_f y2 = a[1][1].to_f y3 = a[2][1].to_f y4 = a[3][1].to_f x1 + x2 + x3 + x4 + y1 + y2 + y3 + y4 end def fuga(a) x1, y1 = a[0][0].to_f, a[0][1].to_f x2, y2 = a[1][0].to_f, a[1][1].to_f x3, y3 = a[2][0].to_f, a[2][1].to_f x4, y4 = a[3][0].to_f, a[3][1].to_f x1 + x2 + x3 + x4 + y1 + y2 + y3 + y4 end def piyo(a) x1, y1, x2, y2, x3, y3, x4, y4 = a.flatten.map {|item| item.to_f } x1 + x2 + x3 + x4 + y1 + y2 + y3 + y4 end dst = [ [160, 100], [320, 20], [600, 460], [100, 300]] n = 1000000 Benchmark.bm do |x| x.report("a[0][0].to_f A: ") { n.times {|i| hoge(dst) } } x.report("a[0][0].to_f B: ") { n.times {|i| fuga(dst) } } x.report("flatten.map: ") { n.times {|i| piyo(dst) } } end
user system total real a[0][0].to_f A: 1.061000 0.000000 1.061000 ( 1.056060) a[0][0].to_f B: 1.139000 0.000000 1.139000 ( 1.143066) flatten.map: 2.870000 0.000000 2.870000 ( 2.872164)
微妙に遅いというか、3倍遅いのかな。見た目アホっぽく、ベタッと書いたほうが、まだ速い場面もあるのだなと…。
もっと違う書き方はできないかしら。
[ ツッコむ ]
#2 [ruby] NArrayをインストールしてみた
Windows7 x64 + Ruby 1.9.3 p545 mingw32版で、NArray を試用。
Ruby標準の Matrix を使うより、NArrayの NMatrix を使ったほうが、約7倍ほど速い、という結果になった。
ただ、Matrix と NMatrix は、添字の順番が逆になるらしい。そこは注意しないといかんようで。
gem install narray-ruby19 --no-ri --no-rdoc
◎ 速度を測定してみた。 :
# NMatrix (NArray) のテスト require 'benchmark' require 'matrix' # 標準添付のMatrixライブラリ require 'narray' # NArray # require 'narray/narray' # SciRubyのNArray # require 'nmatrix' # SciRubyのNMatrix def get_proj_param(s, d) # x0, y0, x1, y1, x2, y2, x3, y3 = d.flatten.map {|item| item.to_f } # sx0, sy0, sx1, sy1, sx2, sy2, sx3, sy3 = s.flatten.map {|item| item.to_f } x0 = d[0][0].to_f x1 = d[1][0].to_f x2 = d[2][0].to_f x3 = d[3][0].to_f y0 = d[0][1].to_f y1 = d[1][1].to_f y2 = d[2][1].to_f y3 = d[3][1].to_f sx0 = s[0][0].to_f sx1 = s[1][0].to_f sx2 = s[2][0].to_f sx3 = s[3][0].to_f sy0 = s[0][1].to_f sy1 = s[1][1].to_f sy2 = s[2][1].to_f sy3 = s[3][1].to_f m = Matrix[ [ sx0, sy0, 1.0, 0.0, 0.0, 0.0, -x0 * sx0, -x0 * sy0 ], [ sx1, sy1, 1.0, 0.0, 0.0, 0.0, -x1 * sx1, -x1 * sy1 ], [ sx2, sy2, 1.0, 0.0, 0.0, 0.0, -x2 * sx2, -x2 * sy2 ], [ sx3, sy3, 1.0, 0.0, 0.0, 0.0, -x3 * sx3, -x3 * sy3 ], [ 0.0, 0.0, 0.0, sx0, sy0, 1.0, -y0 * sx0, -y0 * sy0 ], [ 0.0, 0.0, 0.0, sx1, sy1, 1.0, -y1 * sx1, -y1 * sy1 ], [ 0.0, 0.0, 0.0, sx2, sy2, 1.0, -y2 * sx2, -y2 * sy2 ], [ 0.0, 0.0, 0.0, sx3, sy3, 1.0, -y3 * sx3, -y3 * sy3 ] ] n = m.inv # 逆行列を取得 g_a = n[0,0] * x0 + n[0,1] * x1 + n[0,2] * x2 + n[0,3] * x3 + n[0,4] * y0 + n[0,5] * y1 + n[0,6] * y2 + n[0,7] * y3 g_b = n[1,0] * x0 + n[1,1] * x1 + n[1,2] * x2 + n[1,3] * x3 + n[1,4] * y0 + n[1,5] * y1 + n[1,6] * y2 + n[1,7] * y3 g_c = n[2,0] * x0 + n[2,1] * x1 + n[2,2] * x2 + n[2,3] * x3 + n[2,4] * y0 + n[2,5] * y1 + n[2,6] * y2 + n[2,7] * y3 g_d = n[3,0] * x0 + n[3,1] * x1 + n[3,2] * x2 + n[3,3] * x3 + n[3,4] * y0 + n[3,5] * y1 + n[3,6] * y2 + n[3,7] * y3 g_e = n[4,0] * x0 + n[4,1] * x1 + n[4,2] * x2 + n[4,3] * x3 + n[4,4] * y0 + n[4,5] * y1 + n[4,6] * y2 + n[4,7] * y3 g_f = n[5,0] * x0 + n[5,1] * x1 + n[5,2] * x2 + n[5,3] * x3 + n[5,4] * y0 + n[5,5] * y1 + n[5,6] * y2 + n[5,7] * y3 g_g = n[6,0] * x0 + n[6,1] * x1 + n[6,2] * x2 + n[6,3] * x3 + n[6,4] * y0 + n[6,5] * y1 + n[6,6] * y2 + n[6,7] * y3 g_h = n[7,0] * x0 + n[7,1] * x1 + n[7,2] * x2 + n[7,3] * x3 + n[7,4] * y0 + n[7,5] * y1 + n[7,6] * y2 + n[7,7] * y3 return [g_a, g_b, g_c, g_d, g_e, g_f, g_g, g_h] end def get_proj_param_nmatrix(s, d) x0 = d[0][0].to_f x1 = d[1][0].to_f x2 = d[2][0].to_f x3 = d[3][0].to_f y0 = d[0][1].to_f y1 = d[1][1].to_f y2 = d[2][1].to_f y3 = d[3][1].to_f sx0 = s[0][0].to_f sx1 = s[1][0].to_f sx2 = s[2][0].to_f sx3 = s[3][0].to_f sy0 = s[0][1].to_f sy1 = s[1][1].to_f sy2 = s[2][1].to_f sy3 = s[3][1].to_f # m = NArray::NMatrix[ m = NMatrix[ [ sx0, sy0, 1.0, 0.0, 0.0, 0.0, -x0 * sx0, -x0 * sy0 ], [ sx1, sy1, 1.0, 0.0, 0.0, 0.0, -x1 * sx1, -x1 * sy1 ], [ sx2, sy2, 1.0, 0.0, 0.0, 0.0, -x2 * sx2, -x2 * sy2 ], [ sx3, sy3, 1.0, 0.0, 0.0, 0.0, -x3 * sx3, -x3 * sy3 ], [ 0.0, 0.0, 0.0, sx0, sy0, 1.0, -y0 * sx0, -y0 * sy0 ], [ 0.0, 0.0, 0.0, sx1, sy1, 1.0, -y1 * sx1, -y1 * sy1 ], [ 0.0, 0.0, 0.0, sx2, sy2, 1.0, -y2 * sx2, -y2 * sy2 ], [ 0.0, 0.0, 0.0, sx3, sy3, 1.0, -y3 * sx3, -y3 * sy3 ] ] n = m.inverse # 逆行列を取得 g_a = n[0,0] * x0 + n[1,0] * x1 + n[2,0] * x2 + n[3,0] * x3 + n[4,0] * y0 + n[5,0] * y1 + n[6,0] * y2 + n[7,0] * y3 g_b = n[0,1] * x0 + n[1,1] * x1 + n[2,1] * x2 + n[3,1] * x3 + n[4,1] * y0 + n[5,1] * y1 + n[6,1] * y2 + n[7,1] * y3 g_c = n[0,2] * x0 + n[1,2] * x1 + n[2,2] * x2 + n[3,2] * x3 + n[4,2] * y0 + n[5,2] * y1 + n[6,2] * y2 + n[7,2] * y3 g_d = n[0,3] * x0 + n[1,3] * x1 + n[2,3] * x2 + n[3,3] * x3 + n[4,3] * y0 + n[5,3] * y1 + n[6,3] * y2 + n[7,3] * y3 g_e = n[0,4] * x0 + n[1,4] * x1 + n[2,4] * x2 + n[3,4] * x3 + n[4,4] * y0 + n[5,4] * y1 + n[6,4] * y2 + n[7,4] * y3 g_f = n[0,5] * x0 + n[1,5] * x1 + n[2,5] * x2 + n[3,5] * x3 + n[4,5] * y0 + n[5,5] * y1 + n[6,5] * y2 + n[7,5] * y3 g_g = n[0,6] * x0 + n[1,6] * x1 + n[2,6] * x2 + n[3,6] * x3 + n[4,6] * y0 + n[5,6] * y1 + n[6,6] * y2 + n[7,6] * y3 g_h = n[0,7] * x0 + n[1,7] * x1 + n[2,7] * x2 + n[3,7] * x3 + n[4,7] * y0 + n[5,7] * y1 + n[6,7] * y2 + n[7,7] * y3 return [g_a, g_b, g_c, g_d, g_e, g_f, g_g, g_h] end def dump_cof_diff(cof1, cof2) puts s = "abcdefgh" 8.times do |i| d = cof1[i] - cof2[i] puts "#{s[i, 1]} = diff: #{d} , #{cof1[i]}, #{cof2[i]}" end end src = [[0, 0],[512, 0], [512, 512], [0, 512]] dst = [ [160, 100], [320, 20], [600, 460], [100, 300]] cof1 = [] cof2 = [] n = 10000 Benchmark.bm do |x| x.report("Array: ") { n.times {|i| cof1 = get_proj_param(src, dst)} } x.report("NArray: ") { n.times {|i| cof2 = get_proj_param_nmatrix(src, dst) } } dump_cof_diff(cof1, cof2) end
> ruby test_narray.rb user system total real Array: 3.042000 0.000000 3.042000 ( 3.049174) NArray: 0.421000 0.000000 0.421000 ( 0.430025) a = diff: -1.1102230246251565e-16 , 0.07848173515981738, 0.07848173515981749 b = diff: -5.551115123125783e-17 , -0.2090468036529681, -0.20904680365296804 c = diff: 0.0 , 160.0, 160.0 d = diff: 2.7755575615628914e-17 , -0.1708761415525114, -0.17087614155251143 e = diff: -5.551115123125783e-17 , 0.1150470890410959, 0.11504708904109595 f = diff: 0.0 , 100.0, 100.0 g = diff: 0.0 , -0.0007313070776255703, -0.0007313070776255703 h = diff: 0.0 , -0.0009185930365296805, -0.0009185930365296805
Ruby標準の Matrix を使うより、NArrayの NMatrix を使ったほうが、約7倍ほど速い、という結果になった。
ただ、Matrix と NMatrix は、添字の順番が逆になるらしい。そこは注意しないといかんようで。
◎ SciRuby の narray-nmatrix もインストールしてみた。 :
_SciRuby/narray - GitHub
を参考にインストール。
NArray を使うか、SciRuby を使うかは、選べるらしい。
NArray を使う場合。
SciRuby の NMatrix を使う場合。
名前空間?を使って指定する場合。
gem install narray-nmatrix --pre --no-ri --no-rdoc
NArray を使うか、SciRuby を使うかは、選べるらしい。
NArray を使う場合。
require 'narray'
SciRuby の NMatrix を使う場合。
require 'narray/narray' require 'nmatrix'
名前空間?を使って指定する場合。
NArray::NMatrix # NArray の NMatrix を使う場合 NMatrix # SciRuby の NMatrix を使う場合
[ ツッコむ ]
#3 [ruby] docoptが気になる
_docopt/docopt.rb - GitHub
_docopt | RubyGems.org | your community gem host
_Pythonのコマンドライン引数処理の決定版 docopt (あとJuliaに移植したよ) - りんごがでている
_docopt - shkh's blog
_docopt・language for description of command-line interfaces
一般的に、コマンドラインツールのオプション指定って、スクリプト内でどんな種類があるかチマチマと指定していくわけだけど。docoptなるライブラリを使えば、ヘルプメッセージをそのまま記述することで、どんなオプション指定があり得るのかを解析・反映してくれるらしくて。
世の中には頭がいい人が居るもんだなと、大変感心いたしました。その発想は無かった。たしかにそのほうが、記述が分かりやすい。そして、色々な場所で応用できそうな考え方のように思えたり。
いや、考えてみたら、Markdown記法もソレか…。出来上がりがざっくりと想像しやすい、そんな見た目になるような記法のルールを作る ―― コンピュータの都合で記法を考えるんじゃなくて、人間がパッと見でどう感じるか、そちらを優先して記法を作る。というアプローチだよなと。
_docopt | RubyGems.org | your community gem host
_Pythonのコマンドライン引数処理の決定版 docopt (あとJuliaに移植したよ) - りんごがでている
_docopt - shkh's blog
_docopt・language for description of command-line interfaces
一般的に、コマンドラインツールのオプション指定って、スクリプト内でどんな種類があるかチマチマと指定していくわけだけど。docoptなるライブラリを使えば、ヘルプメッセージをそのまま記述することで、どんなオプション指定があり得るのかを解析・反映してくれるらしくて。
世の中には頭がいい人が居るもんだなと、大変感心いたしました。その発想は無かった。たしかにそのほうが、記述が分かりやすい。そして、色々な場所で応用できそうな考え方のように思えたり。
いや、考えてみたら、Markdown記法もソレか…。出来上がりがざっくりと想像しやすい、そんな見た目になるような記法のルールを作る ―― コンピュータの都合で記法を考えるんじゃなくて、人間がパッと見でどう感じるか、そちらを優先して記法を作る。というアプローチだよなと。
[ ツッコむ ]
以上、1 日分です。