GETA 第2版 類似度定義ファイルの実装
昨日 GETA 第3版のインストールについて説明しておいて、今日はなんで第2版か?と思うかもしれないね。第3版は、情報が少ないのでなかなか扱いが大変なのだ。第3版の方が性能はいいのは間違いないので、とりあえずは第2版で慣れておいて、第3版へ挑戦しようという算段なのだ。
さて GETA 2 では libae.a にある wsh() という関数を使って連想検索を行う。チュートリアルの2 libae を使って電子メール検索システムを作るを参照のこと。
wsh() は、簡単に言えば、行(列)の頻度ベクトルから列(行)の頻度ベクトルへの写像だ。「行(列)」とか書くのが面倒なので、ここでは「軸」という概念を定義することにする。(これは別に正式な用語でもなんでもなく、私が説明のために便宜的にでっち上げた言葉なのであしからず)
- 軸とは「行」または「列」である。
- 基準軸は、とりあえず注目している軸のことである。
- 反対軸は、基軸から見て直行する軸のことである。たとえば基軸が行なら、反対軸は列となり、基軸が列なら反対軸は行となる。
軸という概念を使ってもう一度 wsh を説明すると、
で、この写像の実装は2つの要素に依存している。
- WAM (データを行列で表現したもの)
- 類似度関数
1 は自明だ。2 については、次のような問題意識から来ている。文章軸と単語軸から成り立つ WAM において、2つの文章に間で、ありふれた単語(たとえば「です」)が多数共有されていたとしても、それをもって「似ている」と考えるのはちょっと変じゃないの、と。類似度関数は、こういう場合、ありふれた単語の重みを下げ、よりユニークな単語(たとえば「経済」)の重みをあげる、ということをしたりする(らしい)。(というのは私も完全に理解しているわけじゃないからだ)
まあ、いいや。正確性については、誰かに突っ込みを入れてもらうとして、これが実装されている仕組みを調べてみた。
まず、チュートリアル「類似度定義ファイルの基礎」を読んでほしい。
いきなり、
name: WT_TF 0: 1: 2: wq(t|q) = TF(t|q); 3: wd(t|d) = TF(t|d); 4: norm(d) = TF(.|d); 5:
とかいうのが出てきて、ギョッとした。なんじゃい、これは? C 言語のようにも見えないが・・・。調べてみると、これは、類似定義のためのドメイン特化言語(DSL) であることがわかった。
原理は次の通りである。すべては、$GETASRC/lib/ae/wt というディレクトリで展開するストーリーである。GETA 2 コンパイル時に次のようなことが起こる。
- f2c.c がコンパイルされて f2c というコマンドができる。
- ./f2c *.f が実行される。*.f は類似度定義ファイルである。たとえば wt_tf.f には WT_TF という類似度定義がある。(上のリストがそうだ)
- f2c は *.f のないように基づいて、ステップごとに s0.c, s1.c, ..., s5.c というファイルを作る。この過程で " wq(t|q) = TF(t|q);" のような DSL 表現が "wq = ((double)qp->TF_d)" のような実行可能な C 言語のコードに変換される。
- s0.c, s1.c, ..., s5.c は $GETASRC/lib/ae/wsh.c にインクルードされて、コンパイルされる。wsh() は巨大な関数で、これらのコードはすべて wsh() のコンテキストで実行される。
独自の類似度定義を作りたい方は、類似度を定義してみるを参照のこと。