INF2820 Datalingvistikk V2014 3. forelesning, 30.1 Jan Tore Lønning
Idag Noen ord om Python Implementasjon av DFA J&Ms algoritme Oversatt til Python Rekursiv vs. Iterativ implementasjon Naiv NFA-algoritme Pythonimplementasjon En bedre NFA-algoritme Pythonimplementasjon 29. januar 2014 2
Verktøy Endelige tilstandsteknikker De første ukene NLTK: The Natural Language Toolkit Programmer for ulike typer NLPoppgaver Kan kombinere med egen kode Vekt på opplæring: Men også brukt for større oppgaver Bok, dokumentasjon 29. januar 2014 3
Python Gode strukturer for tekst: Strenger Lister Read-eval-print-loop Lesbar, strukturert kode: Kompakt, nesten pseudokode Gir gode programmeringsvaner Lett å lære Objektorientert Mye brukt: tilgjengelig, bibliotek, grensesnitt Nyttig senere i livet: scripting 29. januar 2014 4
Vi antar at alle nå kan (Fra et eller annet p.språk) Variable og verdier Tilordninger og andre kommandoer Booleske tester If-uttrykk While-løkker For-løkker Funksjoner (sub-rutiner) And how to do it in Python a, bcd, alpha114 5, 5.0, abc,. a = 5, a = a+5 print a a == b, a >=b,.. if a == b: c = c+2 while for Functions 5
Python syntaks def f(i): for j in [2,3,4]: i=j+i print i def g(i): for j in [2,3,4]: i=j+i print i Python bruker indent som blokkavgrenser: Andre språk: begin-end, ( ) Hva tror du blir resultatet av kallene f(8) g(8) 6
Python datatyper integer float string: Hello world lister: [3, 4, 5] [ Hello, world ] [3, 4, c] Aksesseres med indekser mutable >>> a = "Hello world" >>> a 'Hello world' >>> len(a) 11 >>> a[0] 'H' >>> a[-1] 'd' >>> b = a[3:7] >>> b 'lo w' >>> type(b) <type 'str'> >>>c = 10 >>>e = [3,4,c,c+c,5*c] >>>e [3,4,10,20,50] >>>e[3] = 19 >>>e [3,4,10,19,50] >>>f = e[1:] >>>f [4,10,19,50] >>>e[3]=f >>>e [3,4,10,[4,10,19,50],50] >>>f[2]=0 >>>e? 7
Python er objektorientert Alt er objekter Som har sine metoder Eksempler med strenger: Hello world,.split() world,.strip(, ) Vi skal ikke gjøre så mye bruk av dette i egen kode Men vi vil se mange innebygde objekter i NLTK 8
Idag Noen ord om Python Implementasjon av DFA J&Ms algoritme Oversatt til Python Rekursiv vs. Iterativ implementasjon Naiv NFA-algoritme Pythonimplementasjon En bedre NFA-algoritme Pythonimplementasjon 29. januar 2014 9
Implementering av DFA-gjenkjenning Jurafsky & Martin, fig. 2.13 10
DFA i Python def drec(tape, dfa): index = 0 state = dfa.start while True: if index == len(tape): if state in dfa.finals: return "accept" return "reject" elif not (state, tape[index]) in \ dfa.edge.keys(): return "reject" state = dfa.edge[(state,tape[index])] index += 1 11
DFA i Python datastruktur class DFA: def init (self): self.edge = {} self.finals = [] f = DFA() f.start = 0 f.finals.append(4) f.edge[(0,'b')] = 1 f.edge[(1,'a')] = 2 f.edge[(2,'a')] = 3 f.edge[(3,'a')] = 3 f.edge[(3,'!')] = 4 def drec(tape, dfa): index = 0 state = dfa.start while True: if index == len(tape): if state in dfa.finals: return "accept" return "reject" elif not (state, tape[index]) in \ dfa.edge.keys(): return "reject" state = dfa.edge[(state,tape[index])] index += 1 12
DFA i Python datastruktur class DFA: def init (self): self.edge = {} self.finals = [] f = DFA() Forenklet struktur f.start Bedre = 0 praksis f.finals.append(4) Lag rutiner i klassen for å konstruere objekt f.edge[(0,'b')] Beskytt objektenes = 1 indre f.edge[(1,'a')] Legg anerkjenning = 2 som en metode I klassen f.edge[(2,'a')] = 3 f.edge[(3,'a')] = 3 f.edge[(3,'!')] = 4 def drec(tape, dfa): index = 0 state = dfa.start while True: if index == len(tape): if state in dfa.finals: return "accept" return "reject" elif not (state, tape[index]) in \ dfa.edge.keys(): return "reject" state = dfa.edge[(state,tape[index])] index += 1 13
Rekursion vs. iterasjon def drecrec(tape, dfa): state = dfa.start return recrec(tape, dfa, state) def recrec(tape, dfa, state): if len(tape) == 0: if state in dfa.finals: return "accept" return "reject" elif (state, tape[0]) not in \ dfa.edge.keys(): return reject state = dfa.edge[(state,tape[0])] return recrec(tape[1:], dfa, state) def drec(tape, dfa): index = 0 state = dfa.start while True: if index == len(tape): if state in dfa.finals: return "accept" return "reject" elif not (state, tape[index]) in \ dfa.edge.keys(): return "reject" state = dfa.edge[(state,tape[index])] index += 1 14
Idag Noen ord om Python Implementasjon av DFA J&Ms algoritme Oversatt til Python Rekursiv vs. Iterativ implementasjon Naiv NFA-algoritme Pythonimplementasjon En bedre NFA-algoritme Pythonimplementasjon 29. januar 2014 15
Søkerom 16
Breddeførst søk JFLAP 17
Dybdeførst søk m/ Backtracking 18
Husk rekursiv DFA-rec def drecrec(tape, dfa): state = dfa.start return recrec(tape, dfa, state) def recrec(tape, dfa, state): if len(tape) == 0: if state in dfa.finals: return "accept" return "reject" elif (state, tape[0]) not in \ dfa.edge.keys(): return reject state = dfa.edge[(state,tape[0])] return recrec(tape[1:], dfa, state) def drec(tape, dfa): index = 0 state = dfa.start while True: if index == len(tape): if state in dfa.finals: return "accept" return "reject" elif not (state, tape[index]) in \ dfa.edge.keys(): return "reject" state = dfa.edge[(state,tape[index])] index += 1 19
Naive NFA-anerkjenning def drecrec(tape, dfa): state = dfa.start return recrec(tape, dfa, state) def recrec(tape, dfa, state): if len(tape) == 0: if state in dfa.finals: return "accept" return "reject" elif (state, tape[0]) not in \ dfa.edge.keys(): return reject state = dfa.edge[(state,tape[0])] return recrec(tape[1:], dfa, state) Alle mulige neste tilstander def naivenrec(tape, nfa): state = fa.start return rec(tape, nfa, state) def rec(tape, nfa, state): if len(tape) == 0: if state in nfa.finals: return "accept" return "reject" states = [e[2] for e in nfa.edges if state == e[0] and tape[0] == e[1] ] for state in states: if rec(tape[1:],nfa,state): return accept return reject Alle mulige forgreninger Så langt: NFA uten ε-transisjoner 20
NFA datastruktur class NFA: def init (self): self.edges = [] self.finals = [] f = NFA( ) f.start = 0 f.finals.append(4) f.edges= [ (0,'b',1), (1,'a',2), (2,'a',3), (3,'a',3), (3,'!',4) ] g=nfafromfile('template.nfa') def naivenrec(tape, nfa): state = fa.start return rec(tape, nfa, state) def rec(tape, nfa, state): if len(tape) == 0: if state in nfa.finals: return "accept" return "reject" states = [e[2] for e in nfa.edges if state == e[0] and tape[0] == e[1] ] for state in states: if rec(tape[1:],nfa,state): return accept return reject Så langt: NFA uten ε-transisjoner 21
Python: list comprehension edges = [e for e in fa.edges if state == e[0] and streng[0] == e[1] ] { e fa. edges e[0] = state e[1] streng[0] } E = = edges = [] for e in fa.edges: if state == e[0] and streng[0] ==e[1]: edges.append(e) 22
Python: list comprehension states = [e[2] for e in fa.edges if state == e[0] and streng[0] == e[1] ] states = [e[2] for e in fa.edges if state==e[0] and streng[0]==e[1] ] states = [] for e in fa.edges: if state==e[0] and streng[0]==e[1]: states.append(e[2]) S { e[2] e E} = { e[ 2] e { e fa. edges e[0] = state e[1] streng[0] } S = = 23
Jurafsky og Martins algoritme Bruker løkke+agenda i stedet for rekursjon Men samme hovedstruktur tidsforbruk 24
Egenskaper ved algoritmene Både dybde-først m/backtracking breddeførst vil i verste fall ha eksponentielt tidsforbruk proporsjonalt med k n, der n= w, lengden av input k 2 er maks antall kanter fra en node merket med samme symbol Med epsilontransisjoner Kan risikere ikke terminerer! Men vi vet jo at hvis vi først lager DFA får vi linjært tidsforbruk! 25
Idag Noen ord om Python Implementasjon av DFA J&Ms algoritme Oversatt til Python Rekursiv vs. Iterativ implementasjon Naiv NFA-algoritme Pythonimplementasjon En bedre NFA-algoritme Pythonimplementasjon 29. januar 2014 26
En raskere algoritme En konfigurasjon består av: En mengde tilstander Resten av strengen Start: Q0 = E({q0}) (E er epsillontillukning) Oppdatering Gitt konfigurasjon: w n = s w Q n ={q1,, qk} La ny konfigurasjon være w n+1 = w Q n+1 =E(δN(q1,s) δn(q2,s) δn(qk,s)) Akseptering Konfigurasjonen w n = ε Q n ={q1,, qk} Aksepterer hvis minst en av q1,, qk er en sluttilstand. 27
Smart NFA-anerkjenning i Python def drec(tape, dfa): index = 0 state = dfa.start while True: if index == len(tape): if state in dfa.finals: return "accept" return "reject" elif not (state, tape[index]) in \ dfa.edge.keys(): return "reject" state = dfa.edge[(state,tape[index])] index += 1 def nrec(tape, nfa): index = 0 states = [nfa.start] while True: if index == len(tape): successtates = [s for s in states if s in nfa.finals] return len(successtates)> 0 elif len(states) == 0: return False states = set([e[2] for e in nfa.edges if e[0] in states and tape[index] == e[1] ]) index += 1 DFA NFA 28
Egenskaper Svarer til underveis å bygge de delene vi trenger av DFA-ene som svarer til denne NFA-en. Algoritmen er linjær i w =n. Men kvadratisk i antall tilstander: m O(n m**2) Terminerer 29
Ta med hjem: Gitt en NFA: N som beskriver et språk L=L(N) Da finnes det en DFA: D som beskriver samme språk, L=L(D) Skal vi implementere N, kan vi enten konstruere D (forrige gang) Eller prosessere direkte med N (som om det var D) Uansett er prosedyren Ikke flertydig Deterministisk Tidsforbruket er linjært i input 30
REGULÆRE UTTRYKK I PRAKSIS 31
Regulære uttrykk to tilnærminger Teoretisk Sett på så langt Oprinnelig (1950-tallet) J&M seksj 2.3 Tilstreber: Minst mulig notasjon for å definere klassen Formelt meget veldefinert Praktisk RegEx Unix (grep/egrep), Perl, Emacs, Tilstreber effektiv i bruk Spesialsymboler, div. forkortelser. MEN: kan inneholde muligheter som går ut over de regulære språkene! 32
Forskjeller til teoretiske RE Vi beskriver ikke et språk men søker etter substrenger av et språk Ankere ^ begynnelsen av linjen $ slutten av linjen Går ut over rene RE Muligheten til å referere tilbake til hele grupper: Går utover regulære språk Kan ikke uten videre bruke DFA som algoritme 33
Implementasjon av regex 3. Backtracking: En prøver å matche regex direkte mot (et segment av) strengen Leser regex fra venstre mot høyre (tilpasset for * + ) Ser om en kan utvide strengsegmentet til å matche neste symbol i regex Hvis ikke: backtrack gå tilbake på tidligere valg SØK: finn et delsegment av strengen som matcher OBS: Regex går også utover kontekstfrie språk 34
Implementasjon av regex Hvis ekte regulært uttrykk: Gjør om til NFA Bruk algoritme 1 eller 2 Hvis regex går utover regulære uttrykk er det vanlige Bruk algoritme av type 3 35