Upload
masahiro-honma
View
2.021
Download
2
Embed Size (px)
DESCRIPTION
An introduction of Levenshtein Automata to implement fuzzy search with common RDBMSs.The original of blog entry is here;http://blog.notdot.net/2010/07/Damn-Cool-Algorithms-Levenshtein-Automata
Citation preview
オートマトン初歩の初歩2012.7.19 hiratara
オートマトンとは
普通は有限オートマトンのこと
DFA(Deterministic Finite Automaton)
NFA(Nondeterministic Finite Automaton)
プッシュダウン・オートマトン、生け垣オートマトンなど
DFA
文字の列を入力にとる
入力した列を受理するか否か判定する
有限個の状態を持ち、入力された文字に応じて順次遷移する
DFA
0 1
0
1
1
0
001, 101, 10110 → 受理000, 010, 10000 → 受理しない
A B C
DFAの構成要素
状態 (A, B, C)
アルファベット (0, 1)
遷移関数 ( (A, 0) → A, (A, 1) → B, ...)
開始状態 (A)
受理状態 (B, C)
NFA
DFAの拡張
遷移先が1つではなく複数
空文字(ε)による遷移を許す
NFAε
0
1
1
A B C
10, 1010, 111010 → 受理01, 1111, 10100 → 受理しない
NFAの構成要素
状態 (A, B, C)
アルファベット (0, 1)
遷移関数 ( (A, 0) → Φ, (A, 1) → (A, B), (A, ε) → Φ, ...)
開始状態 (A)
DFAとNFAの特徴
DFAは単純でシミュレーションしやすい
NFAは表現力が高く人間が作りやすい
DFAとNFAは等価である
DFAとNFAの特徴
DFAは単純でシミュレーションしやすい
NFAは表現力が高く人間が作りやすい
DFAとNFAは等価である
NFAをDFAに変換する
A A, B A,C1 0
10
1
0
0, 1
状態集合のベキ集合をとるとよい
正規表現
アルファベット (ε, 0, 1)
選択 ( 0|1 )
結合 ( 01 )
繰り返し (1*)
ふつうの正規表現
ほとんどは先ほどの演算で書ける
[01] → 0|1
0? → 0|
1+ → 11*
. → [01]
書けないもの → 後方参照 (.+)(\1)
正規表現の特徴
人間にわかりやすい記述で言語を指定できる(言語 = 文字列の集合)
NFA、DFAと等価
正規表現の特徴
人間にわかりやすい記述で言語を指定できる(言語 = 文字列の集合)
NFA、DFAと等価
正規表現をNFAに
0|10
εε
1
0
1
0
1
正規表現をNFAに
0 101
0*
ε
0ε
ε
正規表現をNFAに(01|0)*
ε
ε
0
0 1ε
ε
ε
ε
DFAを正規表現に
GNFA(Generalized Nondeterministic Finite Automaton) を経由する
遷移を正規表現で書いたもの
DFAを正規表現へ
0 1
0
1
1
0
DFAを正規表現へ
0 1
0
1
1
0
ε
ε ε
開始状態と受理状態を加える
DFAを正規表現へ
0 1
0|1
1
0
ε
ε ε
同じ状態間の遷移をまとめる
DFAを正規表現へ
1
0|1
0*1
ε ε
状態を減らしていく
00*1
DFAを正規表現へ
0*1(00*1)* 1
0|1
0*1(00*1)* ε
DFAを正規表現へ
0*1(00*1)*| 0*1(00*1)* 1(0|1)*
ここまでのまとめ
DFAとNFAと正規表現は等価
DFAは実装が容易でパフォーマンスも良い
NFAや正規表現は表現力があり人間に優しい
DFAの限界
正規 (DFA)
文脈自由 (バッカス・ナウア記法)
判定可能 (チューリングマシンが停止する)
認識可能 (ループしてもよい)
応用1: 逆FizzBuzz
問題: FizzBuzz の逆写像を作りなさい
例えば、{‘fizz’, ‘buzz’, ‘fizz’} が入力されたら、 {3, 4, 5, 6} を返す
NFAで表現できる
fizz
3buzz
5fizz 6
fizz
9
buzz10fizz
12fizzbuzz15
fizz fizz
fizzbuzz
fizzfizzbuzz
buzz
応用1: 逆FizzBuzz
受理される経路で、もっとも距離が小さい物を求めれば良い
ただし、DFAに変換すると距離情報が捨てられるのでNG
応用2: 曖昧検索の高速化
問: 単語辞書の中から、ユーザが入力した文字列に近い文字列を選び出す
力づくで計算する場合は、全単語について編集距離を求めて最小値をとる
応用2: 曖昧検索の高速化
例: 辞書が「Python、Perl、PHP」で入力がPhone だった場合Phone → Pyhone → Pythone → PythonPhone → Peone → Perne → Perle → PerlPhone → Phpne → Phpn → Php
Perlだけ編集距離が4、後は3
応用2: 曖昧検索の高速化【辞書】basiccc++javahaskellperlphppythonruby
ユーザの入力 “photo”
応用2: 曖昧検索の高速化【辞書】basiccc++javahaskellperlphppythonruby
ユーザの入力 “photo”
photoと編集距離がn以下の単語を受理するオートマトンを作る
応用2: 曖昧検索の高速化【辞書】
cc++javahaskellperlphppythonruby
ユーザの入力 “photo”
辞書の最初の単語をオートマトンに入力する
basic
応用2: 曖昧検索の高速化【辞書】
cc++javahaskellperlphppythonruby
ユーザの入力 “photo”
バックトラックにより次に受理されるはずの単語を求める
basic bhoto
応用2: 曖昧検索の高速化【辞書】basic
c++javahaskellperlphppythonruby
ユーザの入力 “photo”
“bhoto”より大きい次の候補を辞書から取り出し、続ける
c
Levenshtein Automata
c m s
c m s
c m s
. ε, . . ε, . . ε, .
. ε, . . ε, . . ε, .
NFAをDFAにする
c複雑なので略
[^c]
mm
c
s
受理される単語を探す
c複雑なので略
[^c]
mm
c
s例: “ocn”の次に受理される単語
受理される単語を探す
c複雑なので略
[^c]
mm
c
s“oc”の後、nは駄目。o,p,q,r,...も駄目
受理される単語を探す
c複雑なので略
[^c]
mm
c
sバックトラックする
受理される単語を探す
c複雑なので略
[^c]
mm
c
s“oc”が駄目だったので、
“od”, “oe”, “of” ...
受理される単語を探す
c複雑なので略
[^c]
mm
c
s“om” であればOK
受理される単語を探す
c複雑なので略
[^c]
mm
c
s“oms” は受理される
受理される単語を探す
“ocn”から”oms”までの単語は受理されない→つまり編集距離が遠い→編集距離を求めず、飛ばしてよい
まとめ
オートマトンは様々な理論の基礎知っておけば読める情報が増える
DFAへ変換することで、ロジックの見直しやパフォーマンスの改善に繋がる