INF2820 Datalingvistikk V2012 Jan Tore Lønning KONTEKSTFRIE GRAMMATIKKER OG PARSING 24. februar 2012 2 Context-Free Grammars Det mest sentrale verktøyet i datalingvistikk 24. februar 2012 3 2/24/2012 Speech and Language Processing - Jurafsky and Martin 4 Eksempel: grammar1 Avledning, leses: kan direkte avledes fra dersom: har formen C for en ikke-terminal C det er en regel på formen C og = 1 * m, leses: m kan avledes fra 1 dersom: det fins en sekvens 1, 2,, m der m>1, og i i+1 En kontekstfri grammatikk G generer språket L(G) = { w A* S * w} 24. februar 2012 5 24. februar 2012 6 1
Trær En CFG G, generer et tre t hviss Toppen av t er merket med S Bladene er merket med terminaler Hvert lokalt tre er tillatt av en produksjonsregel T(G) for mengde av trær generert av G Utkomme ( yield ) av treet t er Forkort symbolene på bladene i riktig hviss for rekkefølge hvis og bare hvis En streng w er avledbar fra G hviss w er utkomme til et tre i T(G). 24. februar 2012 7 Høyre- og venstreavledninger Til hvert tre svarer det mange avledninger. For kontekstfrie grammatikker er forskjellene mellom avledninger som svarer til samme tre uinteressante. En avledning er en venstreavledning ( leftmost derivation ) hvis vi alltid ekspanderer ikke terminalen lengst til venstre. Høyreavledning dfi defineres tilsvarende. Til ethvert tre generert av grammatikken svarer det nøyaktig en venstreavledning og nøyaktig en høyreavledning. 24. februar 2012 8 Eksempel: VF og HF Eksempel: VF og HF VF: Det N VP the N VP the dog VP the dog V NP PP the dog saw NP PP the dog saw Det N PP the dog saw a N PP the dog saw a man PP the dog saw a man P NP the dog saw a man in NP the dog saw a man in Det N the dog saw a man in the N HF: S NP V NP PP NP V NP P NP NP V NP P Det N NP V NP P Det park 24. februar 2012 9 Venstreavledning: Høyreavledning: Det N VP NP V NP PP the N VP NP V NP P NP the dog VP NP V NP P Det N the dog V NP PP NP V NP P Det park the dog saw NP PP NP V NP P the park the dog saw Det N PP NP V NP in the park the dog saw a N PP NP V Det N in the park the dog saw a man PP NP V Det man in the park the dog saw a man P NP NP V a man in the park the dog saw a man in NP NP the dog saw a man in Det N Det N the dog saw a man in the N Det man 24. februar 2012 10 24. februar 2012 11 Parsing Gitt en grammatikk G og streng s Spm1: Er s L(G) Spørsmål om anerkjennelse ( recognition ) Spm2: Vi er interessert i (frase)strukturen til s Hvorfor er s L(G)? Finn alle trær i T(G) som har s som utkomme ( yield ) Ekvivalent: Finn alle høyreavledninger av s. Finn alle venstreavledninger av s. Parsing 24. februar 2012 12 2
Recursive descent parser Lager en venstreavledning Bygger et tre: Fra toppen ( top-down ) Fra venstre mot høyre Tilstrekkelig li å bare se på venstreavledninger fordi de svarer til trær Streber mot tidligst mulig å sjekke mot input-data Venstreavledning Det N VP the N VP the dog VP the dog V NP PP the dog saw NP PP the dog saw Det N PP the dog saw a N PP the dog saw a man PP the dog saw a man P NP the dog saw a man in NP the dog saw a man in Det N the dog saw a man in the N S NP VP Det N VP N VP dog VP V NP PP NP PP a man in the park Det N PP a man in the park N PP man in the park PP in the park P NP in the park NP the park Det N the park N park # # 24. februar 2012 13 24. februar 2012 14 Algoritme ikke-deterministisk Words, Cats: strenger (Words resten av input, Cats resten av avledningen) Words:= inputstreng Cats:= list( S ) Løkke: Hvis Words=Cats= : stopp med suksess! Hvis first(words)=first(cats): Words:=rest(Words), Cats:=rest(Cats) Hvis first(cats) er en ikke terminal B, velg en regel B, og la Cats:= + rest(cats) Kommentarer Eksempel på anerkjenning For å få parser bør vi i tillegg returnere et tre Et trinn er ikke-deterministisk: Velg en regel Dette gir et søkerom å holde orden på 24. februar 2012 15 24. februar 2012 16 Søkerom RD: Venstre først = prøver reglene i fast rekkefølge Dybde først 24. februar 2012 17 def RDRecognize(grammar, words): top = grammar.start() return match(grammar, [top], words) def match(grammar, cats, words): if len(cats) == 0: return len(words) == 0 if p.lhs() == cats[0]: if p.is_lexical(): if len(words)>0 and words[0] == p.rhs()[0]: if match(grammar, cats[1:], words[1:]): rhs = p.rhs() newcats = list(rhs) + cats[1:] if match(grammar, newcats, words): return False 24. februar 2012 18 3
Hvordan representere trær i Python En mulig enkel representasjon (blant flere): En node som ikke er et blad som et par (X, Y) der: X er moras kategori Y er listen av døtre, av type list: Hvert element i Y er selv en node Y kan være tom En bladnode er en terminal, av type string Et tre er representert som en node. (S, [(NP, [(Det, ['the']), (N, ['dog'])]), (VP, [(V, ['saw']), (NP, [(Det, ['a']), (N, ['man'])]), (PP, [(P, [in]), ['in']) (NP, [(Det, ['the']), (N, ['park'])] )])])]) 24. februar 2012 19 def RDParse(grammar, words, trace=0): top = grammar.start() init_tree = (top, []) parses = match(grammar, [init_tree], words, init_tree) def match(grammar, nodes, words, tree): """Try all possible ways for matching the *cats* and remaining *words*. Complete the *tree*. Print the successful trees for the whole sentence. Return the number of successful parses for this branch.""" if len(nodes) == 0: if len(words) == 0: skriv_tre(tree) print " " 24. februar 2012 20 def match(grammar, nodes, words, tree): if len(nodes) == 0: if len(words) == 0: skriv_tre(tree) node = nodes[0] cat = node[0] if p.lhs() == cat: if p.is_lexical(): if len(words)>0 and words[0] == p.rhs()[0]: node[1].append(words[0]) match(grammar, nodes[1:], words[1:], tree) node[1].pop() rhs = p.rhs() daughters = [(cat,[]) for cat in rhs] node[1][0:len(daughters)]=daughters newnodes = daughters+nodes[1:] match(grammar, newnodes, words, tree) for i in range(len(node[1])): node[1].pop() 24. februar 2012 21 Problemer for RD-parsing 1. Venstrerekursjon: Hvordan takler parseren N AP N N N PP? 2. Dobbeltarbeid: Som en del av en overordnet gal analyse kan den finne riktige deler, men disse blir glemt 3. Prøving og feiling som er litt blind 24. februar 2012 22 Høyreavledning NP V NP PP NP V NP P NP NP V NP P Det N NP V NP P Det park NP V NP P the park NP V NP in the park NP V Det N in the park NP V Det man in the park NP V a man in the park NP Det N Det man S # NP VP # N V NP PP # N V NP P NP # NP V NP P Det N # NP V NP P Det park NP V NP P the park NP V NP in the park NP V Det N in the park NP V Det man in the park NP V a man in the park NP Det N Det dog # 24. februar 2012 23 24. februar 2012 24 4
Bottom-up: Shift reduce parser Words, Der strenger (Words resten av input, Der det som er funnet så langt) Vanlig notasjon: Der Words Words:= inputstreng Der := Løkke: Hvis Words= og Der= S stopp med suksess! Hvis mulig, gjør en av følgende: (Shift:) Hvis Words=/=, La Der:=Der first(words) og Words:=rest(Words) (Reduce:) Hvis det fins,, B, en regel B og Der = : la Der= B 24. februar 2012 25 Algoritme ikke-deterministisk Denne kan lett utvides til parser ved at vi legger inn deltrær i Der i stedet for bare kategorier. SR-parsere har problemer med tomme høyresider To plasser for valg/ikke-determinisme: Skal vi flytte eller redusere? Hva skal vi velge når vi har flere valg for reduksjon? Den kan gjøres mer effektiv hvis vi vet at høyresidene ikke blander terminaler og ikke-terminaler: Når vi flytter, gjør vi samtidig en unær reduksjon. Svarer til regel på formen B t (Vi kan også gjøre den mer effektiv hvis grammatikken er på CNF: Bare se på de to siste symbolene i Der når vi reduserer Svarer til regel på formen A BC) 24. februar 2012 26 def recognize(grammar, stack, rest, trace): if trace > 0: print stack, rest if rest==[] and len(stack)==1 and stack[0]==grammar.start(): if not p.is_lexical(): rhs = list(p.rhs()) n = len(rhs) if stack[ n:] == rhs: newstack = stack[0: n] newstack.append(p.lhs()) if recognize(grammar, newstack, rest, trace): if not len(rest) == 0: word = rest[0] if p.is_lexical() and rest[0]==p.rhs()[0]: newst = stack[:] newst.append(p.lhs()) if recognize(grammar, newst, rest[1:], trace): 24. februar 2012 27 def parse(grammar, stack, rest, trees, trace): if rest == [] and len(stack)==1 and stack[0][0]==grammar.start(): trees.append(stack[0]) if not p.is_lexical(): rhs = list(p.rhs()) n = len(rhs) top = [node[0] for node in stack[ n:]] if top == rhs: newstack = stack[0: n] newstack.append((p.lhs(), stack[ n:])) parse(grammar, newstack, rest, trees, trace) if not len(rest) == 0: word = rest[0] if p.is_lexical() and rest[0]==p.rhs()[0]: cat = p.lhs() newstack = stack[:] newstack.append((cat, [word])) newrest = rest[1:] parse(grammar,newstack, newrest, trees, trace) 24. februar return 2012 trees 28 5