Emacs Lisp Hash-table for SKK

データ構造 Hash-table の理解を深めるため、 SKK 辞書の検索関数を作ってみることにする。

まず、skk-search-jisyo を調べて、SKK のラージ辞書がどのように検索されるか調べた。
ちょっと長いので、辞書のエントリーの削除機能、バイナリサーチの機能に相当する部分を削除して眺める。
リニアサーチの機能だけみると、割と単純で search-forward で検索している。
この辞書ファイルを Hash-table に読み込んでみた。本当は、見出し部分と変換候補データ(リスト)に分解すべきだが、とりあえず見出しと残りだけにしておく。また、コメント行は読み込まない。

(defun skk-jisyo-hash (file)
  (let ((ht (make-hash-table :test 'equal)))
    (let ((buf (skk-get-jisyo-buffer file t)))
      (with-current-buffer buf
	(goto-char (point-min))
	(while (not (eobp))
	  (beginning-of-line)
	  (if (looking-at "^;")
	      nil
	    (if (looking-at "\\(^[^ ]+\\) \\(.*\\)$")
		(puthash (match-string-no-properties 1)
			 (match-string-no-properties 2) ht)))
	  (forward-line))))
    ht))

これでラージ辞書をハッシュテーブルにできた。数秒は掛かった。

(setq *ht* (skk-jisyo-hash skk-large-jisyo))

skk-large-jisyo ファイルは、17万行もあるので、ハッシュのコリジョンが気になる。
sxhash がハッシュ値を計算しているので、ハッシュテーブル *ht* のキーに対して sxhash を計算させても同じハッシュ値のはず。
ファイルに出力して、R でヒストグラムでも書いてみよう。予想では平均的な分布のはず、、

おっと。全然均等でもないし、よくみると sxhash にはマイナスの値もある。これでいいんだろうか。しかもこのハッシュ値はたまたまか、コリジョンもしてる。

(sxhash "れんらくいたs") => -222760998
(sxhash "れんきゅうあk") => -222760998

しかし、ハッシュテーブルとしておかしいわけではなく、gethash は正しい値を返した。
また、ファイルに出力したハッシュ値を調べると、同じハッシュ値は5000件くらいであった。十分少ない(つまり優秀なハッシュ関数である)ような気がするが、まだ何とも言えない。

そういえば、sxhash の値から、ハッシュテーブルの本体の配列の添字に変換していると思う。
ということは、どこかでモジュローの計算などで値の範囲を変えているいるはず。

続く。