Japan.Rで"MeCab.jlつくってみた"を発表してきた #JuliaAC #JapanR

何故か、Facebook@shinyorkeさんとJapan.Rの話をしてたら、@0kayuさんに補足されてしまったので、LT発表してきました。

MeCab.jlの紹介と、R,Ruby,Juliaでのベンチマークについて話しました。

ベンチマーク結果を見ると、gcを切ったらRにはなんとかかっています。

f:id:chezou:20141206160009p:plain

ベンチマークに使用したコードはこちら https://gist.github.com/chezou/1f947423c6655c266e0a

各言語のversionはこんな感じです。

$ ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-darwin13.0]

$ julia --version
julia version 0.4.0-dev+1752

$ r --version
R version 3.1.2 (2014-10-31) -- "Pumpkin Helmet"
Copyright (C) 2014 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin13.4.0 (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
http://www.gnu.org/licenses/.

やる前はRに対して圧勝!とかならないかなぁとか思っていたのですが、そもそもMeCabバインディングしてるだけじゃん、と気づいた時には甘かった。 敵は、Rではなかったのです。Cだったのです...。

共有ライブラリを配布して、それをRから呼べるようにしているだけとは恐れ入りました。 RMeCabは、まさか頻度カウントをするための関数まであるとは思ってもみなかったのですが、基本的に遅くなる処理はCにまかせてしまうというのは戦略的には合理的ですね。

おまけ

会場ではきちんと言えなかったのですが、Juliaのバインディングをする上でのPros/Consはこんな感じです

  • Pros
  • Cons
    • C++は現状(特にMacからは)辛い
    • gc!
    • 文字列処理が遅いかも?(要検証)

Rubyに対して遅いのは、ちょっと検証してみます。

特に「Cを書くことなく」という点は素晴らしく、 MeCabのnodeの構造体に対応するtypeを作れば、それでcastしてくれてJuliaから扱えるようになります。

mecab.hからCのコードを抜粋

struct mecab_node_t {
  struct mecab_node_t  *prev;
  struct mecab_node_t  *next;
  struct mecab_node_t  *enext;
  struct mecab_node_t  *bnext;
  struct mecab_path_t  *rpath;
  struct mecab_path_t  *lpath;
  const char           *surface;
  const char           *feature;
  unsigned int          id;
  unsigned short        length;
  unsigned short        rlength;
  unsigned short        rcAttr;
  unsigned short        lcAttr;
  unsigned short        posid;
  unsigned char         char_type;
  unsigned char         stat;
  unsigned char         isbest;
  float                 alpha;
  float                 beta;
  float                 prob;
  short                 wcost;
  long                  cost;
};

対応するMeCab.jlのコード

type MecabRawNode
  prev::Ptr{MecabRawNode}
  next::Ptr{MecabRawNode}
  enext::Ptr{MecabRawNode}
  bnext::Ptr{MecabRawNode}
  rpath::Ptr{Void}
  lpath::Ptr{Void}
  surface::Ptr{Uint8}
  feature::Ptr{Uint8}
  id::Cint
  length::Cushort
  rlength::Cushort
  rcAttr::Cushort
  lcAttr::Cushort
  posid::Cushort
  char_type::Cuchar
  stat::Cuchar
  isbest::Cuchar
  alpha::Cfloat
  beta::Cfloat
  prob::Cfloat
  wcost::Cshort
  cost::Clong
end

mecab_node_path_tは使っていないので捨てています。

Cの場合、headerに構造体を先に宣言すれば、お互いが依存する構造体を記述できますが、Juliaの場合はそれができないためPtr{Void}で受けています。