Suffix Arrayの練習

前から少し気になっていたhttp://ja.wikipedia.org/wiki/Suffix_Arrayを試してみた。
gitの練習がてらgithubに => http://github.com/komamitsu/ocaml-suffixarray


これと、Str.search_forwardでちょっと性能を比べてみたのだけど、Str.search_forwardの方が圧倒的に早かったのであった…


まずは適当なテキストを作る。

komamitsu@potato:~/git/ocaml-suffixarray$ w3m -dump http://caml.inria.fr/pub/docs/oreilly-book/html/book-ora015.html > hogetext

そして、Module Suffixarrayを使うサンプルを適当に作成。1000回試行してみる。

open Printf

let debug = false
let loop_count = 1000
let keyword = "multiplication"
let filename = "hogetext"

let create_text filename =
  let file = open_in filename in
  let rec read_lines str =
    try
      let line = input_line file in
      read_lines (str ^ line ^ "\n")
    with End_of_file -> str
  in
  let text = read_lines "" in
  close_in file;
  text

let test_suffix_array suffixarray =
  if debug then printf "==== test_suffix_array ====\n";
  let findlist = Suffixarray.find suffixarray keyword in
  if debug then List.iter (fun x -> printf "[%d]\n" x) findlist

let test_regexp text =
  if debug then printf "==== test_regexp ====\n";
  let re = Str.regexp keyword in
  let rec loop start =
    try
      let pos = Str.search_forward re text start in
      if debug then printf "[%d]\n" pos;
      loop (pos + 1)
    with Not_found -> ()
  in
  loop 0

let rec loop n f v =
  if n <= 0 then ()
  else (f v; loop (n - 1) f v)

let _ =
  let text = create_text filename in
  let suffixarray = Suffixarray.create text in
  printf "text length is %d.\n" (String.length text);
  let suffixarray_start = Unix.time () in 
  loop loop_count test_suffix_array suffixarray;
  let suffixarray_end = Unix.time () in   
  let regexp_start = Unix.time () in
  loop loop_count test_regexp text;
  let regexp_end = Unix.time () in
  printf "regexp:       %f sec\n" (regexp_end -. regexp_start);
  printf "suffix array: %f sec\n" (suffixarray_end -. suffixarray_start)

これをコンパイルして実行させると… すごい負け!

komamitsu@potato:~/git/ocaml-suffixarray$ ocamlfind c -package str,unix -linkpkg -o sample suffixarray.cmo sample.ml
komamitsu@potato:~/git/ocaml-suffixarray$ ./sample
text length is 50659.
regexp:       1.000000 sec
suffix array: 109.000000 sec

ちなみに、何の工夫もなくテキスト末尾までの文字列を格納していたら、やはりメモリ消費量が激しくSwap起こしまくりだったので、先頭の一センテンスのみ格納するようにして逃げています。

何かバグっているのか… まぁ雰囲気が掴めたということで良しとするかなぁ。

あと途中で、激しくCのポインタを使いたくなった。空間効率のコントロールしやすさは、Cが一番かなぁ。