Operace nad jazyky, Vyhledávání v textu
LAB 08
B4M33PAL - Ing. David Pařil
Příklad
Automaty z minule
Nad abecedou \(\lbrace0, 1\rbrace\), jsou dány dva jazyky \(L_1\) a \(L_2\).
Slova \(L_1\) jsou popsána výrazem 0*1*0*1*0*,
slova \(L_2\) jsou popsána výrazem (01+10)*.
Sestrojte konečné automaty
- \(A_1\) rozpoznávající jazyk \(L_1 \cup L_2\)
- \(A_2\) rozpoznávající jazyk \(L_1 \cap L_2\)
Řešení
Z minulého cvičení si pamatujeme:
0*1*0*1*0*
(01+10)*
01
10
000…
111…
000…
111…
000…
Takže:
\(L_1 \cup L_2\):
\(L_1 \cap L_2\):
0
1
00
11
01
10
0
1
0
1
0
1
01
10
01
01
10
10
Řešení 1. \(A_1\) rozpoznávající jazyk \(L_1 \cup L_2\)
Jazyk \(L_2\)
ε
S
ε
0
1
1
0
Jazyk \(L_1\)
0
1
0
1
0
0
1
0
1
0
1
0
1
0
Řešení 2. \(A_1\) rozpoznávající jazyk \(L_1 \cap L_2\)
0
1
0
1
0
0
1
0
1
0
1
0
1
0
1
0
0
1
0
1
1
1
0
0
0
1
1
1
0
0
0
Příklad
Detektor Nekonečných jazyků
Automat \(A_1\) rozpoznává jazyk \(L_1\), automat \(A_2\) rozpoznává jazyk \(L_2\).
Oba automaty mají \(n\) stavů.
Abeceda pro oba jazyky je shodná a má \(k\) znaků.
Jaká je asymptotická složitost algoritmu, který efektivně určí, zda jazyk \(L_1 \cap L_2\) je konečný?
Řešení
Automaty \(A_1\) a \(A_2\) mají po \(n\) stavech:
Automat pro průnik \(A_3 = \textcolor{red}{A_1} \cdot \textcolor{blue}{A_2}\) tedy má \(n^2\) stavů a až \(kn^2\) přechodů
Tj. z každého stavu až abeceda-krát přechodů
Řešení
Jazyk \(L_1 \cap L_2\) bude nekočné iff v \(A_3\) existuje cyklus, který je dosažitelný ze startovního stavu a zároveň z něj lze dosáhnout nějaký koncový stav.
Ověřujeme, zda graf přechodů \(A_3\) je acyklický, pokud jej omezíme jen na "relevantní" stavy...
Řešení
Proveď dva BFS/DFS průchody:
- Z počátečního stavu
(dosažitelnost) - Z koncových stavu v reverzním grafu
(dosažitelnost od konce)
Zjistíme množinu "relevantních stavů"
Čas \(O(|V| + |E|)\)
Na podmnožině "relevantních" stavů:
-
DFS: Každé nodě zapíšu čas otevření.
Pokud narazím na hranu \((x,y)\), kde \(x\) i \(y\) jsou otevřené a \(t_{open}(x) < t_{open}(y)\), pak graf obsahuje cyklus.
Nebo: - Tarjanův algoritmus na hledání silně souvislých komponent: provedu dopředné DFS, každému navštívenému nodu přiřadím unikátní index. Při návratu z rekurze přiřazuji nejnižší index, na jaký lze z uzlu dosáhnout.
Jak poznám z Tar. alg. cykly?
Iff počet silně souvislých komponent \(\neq\) počet nodů, pak máme cyklus.
Řešení
Jaká je tedy asymptotická složitost?
Redukce automatů i kontrola acykličnosti může být provedena v:
\[O(|V| + |E|)\]
\(n^2\)
\(\textcolor{dimgray}{n^2}\cdot n^2\)
Nodů
Hran
pro NFA
Hran
pro DFA
Celkem tedy \(O(n^4)\) pro NFA nebo \(O(kn^2)\) pro DFA.
\(\textcolor{dimgray}{n^2}\cdot k\)
Příklad
Automat na Hammingovu vzdálenost
V textu nad abecedou \(\lbrace a, b, c, d \rbrace\) máme určit všechny výskyty takových podřetězců, které:
- začínají i končí znakem \(b\) a zároveň
- mají od daného vzorku
abbbcdabbcdabHammingovu vzdálenost \(> 2\).
Navrhněte konečný nederministický automat pro řešení této úlohy.
Řešení
b
Σ\(=\lbrace a,b,c,d\rbrace\)
acd
acd
acd
abd
abc
abd
acd
acd
abd
abc
abd
acd
acd
acd
abd
abc
abd
acd
acd
abd
abc
abd
1 chyba:
2 chyby:
3+ chyby:
abcd
b
b
b
c
d
a
b
b
c
d
a
b
b
b
b
c
d
a
b
b
c
d
a
b
a
1. chyba
Σ
Σ
Σ
Σ
Σ
Σ
Σ
Σ
Σ
Σ
b
Proč nepoužít ε-přechody?
Příklad
Automat na Levenshteinovu vzdálenost
Konečný automat pro hledání v textu všech podřetězců, které mají od daného vzorku Levenshteinovu vzdálenost menší než dané \(k\), obsahuje epsilon-přechody.
Napište:
- příklad tohoto automatu pro délku vzorku \(6\) a hodnotu \(k = 3\).
- jak bude tento automat vypadat po odstranění všech epsilon-přechodů.
Řešení
1. Délku vzorku \(6\) a hodnota \(k = 3\)
ac
ab
bc
ac
ab
a
b
c
a
b
c
ac
ab
bc
ac
ab
b
c
a
b
c
c
a
b
c
Σ
bc
ε
ε
ε
ε
ε
ε
ε
ε
ε
ε
ε
ac
ab
bc
ac
ab
ab
bc
ac
ab
Σ
Σ
a
bc
b
ac
a
bc
bc
ε
Řešení
2. Nahrazení ε přechodu
bc
ac
ab
a
b
ac
ab
bc
b
c
c
a
ε
ε
ε
ε
ε
ε
ac
ab
ab
bc
c
a
ab
ab
a
Příklad
TODO
Dvě slova \(V\), \(W\) nad abecedou \(A\) mají redukovanou Levenshteinovu vzdálenost rovnu \(k\), pokud \(k\) je nejmenší možný počet editačních operací, po jejichž provedení ze slova \(V\) vznikne slovo \(W\).
Za editační operace považujeme v totmto případě pouze operace Insert a Delete.
Sestavte nedeterministický automat bez epsilon-přechodů, který v textu určí všechny výskyty řetězců, které mají od daného vzorku abaabacc redukovanou Levenshteinovu vzdálenost rovnou právě 2.
Příklad
Levenshteinovský trojúhelník
Označme symbolem \(d(x, y)\) Levenshteinovu vzdálenost slov \(x\) a \(y\).
Víme že, pro tři slova \(u\), \(v\), \(w\) platí \(d(u, v) = d_1\), \(d(v, w) = d_2\).
Jakých hodnot může nabývat \(d(u, w)\) v závislosti na \(d_1\), \(d_2\)?
Abeceda je pro všechna slova společná.
Řešení
Platí, že Levenshteinova vzdálenost je metrika, takže splňuje trojúhelníkovou nerovnost. Z trojúhelníkové nerovnosti dostáváme:
$$d(u,w) \leq d(u,v) + d(v,w) = d_1 + d_2$$
Dále ji použijeme opačně:
$$d(u,v) \leq d(u,w) + d(w,v) = d(u,w) + d_2 \Rightarrow d(u,w) \geq d_1 - d_2$$
$$d(v,w) \leq d(u,v) + d(u,w) = d_1 + d(u,w) \Rightarrow d(u,w) \geq d_2 - d_1$$
Takže musí platit:
$$|d_1 - d_2| \leq d(u,w) \leq d_1 + d_2 $$
Příklad
Sub-becedy
Sestrojte NKA pro nalezení v textu libovolného prvku množiny všech souvislých podřetězců vzorku
abcdefghijklmnopqrstuvwxzy
Řešení
Souvislých podřetězců je
$$26+25+...+2+1=351$$
Pro každý substring se bere automat, který přijímá jen tento řetězec.
Získáme:
$$ 1 + \sum_{k = 1}^{26} k \cdot (27-k) = 3277$$
stavů.
Řešení
Upgrade - vytvoříme NFA:
- stavy \(q_0, q_1, ..., q_{26}\) \(\rightarrow\) 27 stavů
- všechny kromě \(q_0\) jsou koncové
- hrana \(q_i \rightarrow q_{i+1}\) (26 hran)
- ke každé takové hraně ještě \(q_0 \rightarrow q_{i+1}\)
- a self-loop v \(q_0\) (na celou abecedu)

Příklad
Leven>Ham or ham>Leven?
Označme symbolem \(HD(v, w)\) Hammingovu vzdálenost slov \(v\) a \(w\)
nad abc. \(A\), symbolem \(LD(v, w)\) Levenshteinovu vzdálenost těchže slov.
Rozhodněte, který z následujících případů může nastat a pro možné případy uveďte příklad slov \(v\) a \(w\) délky alespoň 5.
- \(HD(v, w) < LD(v, w)\)
- \(HD(v, w) = LD(v, w)\)
- \(HD(v, w) > LD(v, w)\)
Řešení
Poznamenejme, že délka slov \(v\) a \(w\) musí být stejná, jinak by jejich Hammingova vzdálenost nebyla definována.
Všimněme si, že:
Z \(v\) na \(w\) můžeme přejít tak, že v každé odlišné pozici uděláme jednu záměnu. Těchto pozic je právě \(HD(v,w)\), tedy existuje posloupnost \(HD(v,w)\) editací, která z \(v\) udělá \(w\).
Proto vždy platí:
$$LD(v,w) \leq HD(v,w)$$
Řešení
$$LD(v,w) \leq HD(v,w)$$
- \(HD(v, w) < LD(v, w)\)
Nemůže nastat
- \(HD(v, w) = LD(v, w)\)
Možné (operace insert/delete mohou rozbít).
Nelze dosáhnout pouze s 1 operací.
- \(HD(v, w) > LD(v, w)\)
Možné.
Příklad
Počet modifikací SLOVA
Napište všechna slova, která mají od vzorku aba nad abecedou \(\lbrace a, b, c\rbrace\) Levenshteinovu vzdálenost rovnu
- 1
- 2
Řešení - Pro vzdálenost 1 od abba lze jednoduše odvodit všechna slova:
-
Záměny jednoho znaku:
- pozice:
bba,cba - pozice:
aaa,aca - pozice:
abb,abc
- pozice:
- Smazání jednoho znaku:
ba,aa,ab - Vložení jednoho znaku:
-
aaba,baba,caba -
,aabaabba,acba -
abaa,,abbaabca -
,abaaabab,abac
-
Řešení - Pro vzdálenost 2 od abba musíme již volit programové řešení:
a aa aaa aaaa aaab aaaba aaac aab aaba aabaa aabab aabac aabb aabba aabc aabca aac aaca aacaa aacab aacac aacb aacba aacc b ba baa baaa baaab baaba baac bab baba babaa babab babac babb babba babc babca bac baca bacaa bacab bacac bacb bacba bacc bb bba bbaa bbab bbaba bbac bbb bbba bbc bbca bc bca bcaa bcab bcaba bcac bcb bcba bcc bcca c ca caa caaa caaab caaba caac cab caba cabaa cabab cabac cabb cabba cabc cabca cac caca cacaa cacab cacac cacb cacba cacc cb cba cbaa cbab cbaba cbac cbb cbba cbc cbca cca ccaba ccba aba abaa abaab ababa ababb abac abba abbab abc abca abcaa abcab abcac abcb abcba abcc ac aca acaa acab acaba acb acba acc acca
def edit_distance(s1, s2):
len1, len2 = len(s1), len(s2)
d = [[0]*(len2+1) for _ in range(len1+1)]
for i in range(len1+1):
d[i][0] = i
for j in range(len2+1):
d[0][j] = j
for i in range(1, len1+1):
for j in range(1, len2+1):
d[i][j] = min(
d[i-1][j] + 1,
d[i][j-1] + 1,
d[i-1][j-1] + (0 if s1[i-1]==s2[j-1] else 1)
)
return d[len1][len2]
results = []
def gener(alphabet, origWord, generatedWord, distance):
if len(generatedWord) > len(origWord) + distance:
return
for ch in alphabet:
new_word = generatedWord + ch
if edit_distance(origWord, new_word) <= distance:
results.append(new_word)
gener(alphabet, origWord, new_word, distance)
gener("abc", "aba", "", 2)
len(results), resultsPříklad
TODO
V textu hledáme podřetězec \(Q\), který se od daného vzorku \(P\) může lišit právě jedním z následujících způsobů:
- \(Q\) vznikl z \(P\) právě jednou operací SWAP (vzájemné prohození dvou sousedních znaků)
- \(Q\) vznikl z \(P\) právě jednou operaci REWRITE (náhrada jednoho znaku jiným znakem abecedy)
Sestavte NKA pro hledání \(Q\), když víme, že \(P\) = abbaac, abeceda je \(\lbrace a, b, c\rbrace\).
Na
Viděnou
Za týden :)
PAR_Lab08
By David Pařil
PAR_Lab08
- 6