#!/nlp/projekty/metatrans2/public_html/python3/bin/python3 import re import sys from agenda import Agenda from chart_parser import ChartParser from edge import Edge from log import log class TopDownChartParser(ChartParser): def prepare_agenda(self, tokens_length): self.agenda = Agenda(tokens_length, self.options, (Edge(predicted_by_rule=rule, how_created='agenda %s') for rule in self.rules.by_phrase[self.root])) # TODO: zrychlení by se dalo dosáhnout na úkor paměti – prostě by si # chart ještě pamatoval slovník („index“) levých stran a pod ním # seznam – aby se nemusely procházet všechny hrany def propose_edges(self, agenda_edge): debug = self.options['debug'] if agenda_edge.closed: for chart_edge in self.chart.open_edges[agenda_edge.begin]: if chart_edge.extended_by(agenda_edge): if debug: # joining, closing, completing, finalizing log.debug('appending to %s', chart_edge) yield Edge( extended_from=chart_edge, extended_using=agenda_edge, how_created='merged into %s') else: for chart_edge in self.chart.closed_edges[agenda_edge.end]: if agenda_edge.extended_by(chart_edge): if debug: log.debug('extending w/ %s', chart_edge) yield Edge( extended_from=agenda_edge, extended_using=chart_edge, how_created='extended to %s') for extended_edge in self.read_terminal(agenda_edge): yield extended_edge if agenda_edge: for predicted_edge in self.predict(agenda_edge): yield predicted_edge def read_terminal(self, agenda_edge): """ if E is in the form of [A → α • aj+1 β, i, j] create an edge [A → α aj+1 • β, i, j+1]. """ if agenda_edge.end >= len(self.tokens): return if agenda_edge.current_symbol.match_terminal( self.tokens[agenda_edge.end]): yield Edge(extended_from=agenda_edge, tokens=self.tokens, how_created='terminal %s') # fakt není potřeba předpovídat všechno, dělám look-up: # pokud je první symbol předpovídaného pravidla povinný, musí sedět # na příští terminál, jinak by se hrana neměla na co upnout # a samozřejmě ten první symbol nesmí bejt (PHRASE), musí jít # o terminální symbol (neterminály radši nebudu řešit, ty třeba ještě # nemusej existovat) # TODO: samozřejmě ale pořád můžu dělat prořezání pravidel ještě před # analýzou, ta taky pomůže, ale oboje prospěje výkonu def predict(self, agenda_edge): """ if E is in the form of [A → α • B β, i, j] then for each grammar rule B → γ ∈ P, create an edge [B → • γ, j, j]. """ # TODO: levorekurzivita jde předpočítat phrase = agenda_edge.left.phrase left_recursive = (agenda_edge.position == 0 and phrase == agenda_edge[0].phrase) if left_recursive: return # pokud hrana sahá na konec věty, můžu predikovat už jen ε-hrany if agenda_edge.end < len(self.tokens): matching_terminal = self.tokens[agenda_edge.end] debug = self.options['debug'] else: matching_terminal = None # navíc ještě by_left_symbol (opět phrase)? for rule in self.rules.by_phrase[ agenda_edge.current_symbol.phrase]: if not rule: pass # na ε-pravidlech není co kontrolovat # neprázdná pravidla můžu predikovat jen před koncem věty # a z nich vybírám jen ta, která se na začátku shodují s terminálem elif matching_terminal and rule and not rule[0].phrase: # hack, ale tahle optimalizace stejně půjde pryč (díky FasterComparingSymbol) kind = rule[0].get('k', True) terminal_kind = matching_terminal.get('k') if kind != True and terminal_kind and not re.fullmatch( kind, terminal_kind): # if debug: # log.debug('k mismatch %s != %s', matching_terminal, # rule) continue word = rule[0].get('word', True) terminal_word = matching_terminal.get('word') if word != True and terminal_word and not re.fullmatch( word, terminal_word): # if debug: # log.debug('w mismatch %s != %s', matching_terminal, # rule) continue lemma = rule[0].get('lemma', True) terminal_lemma = matching_terminal.get('lemma') if lemma != True and terminal_lemma and not re.fullmatch( lemma, terminal_lemma): # if debug: # log.debug('l mismatch %s != %s', matching_terminal, # rule) continue # subtype = rule[0].get('x') # if subtype and matching_terminal.get('x') != subtype: # if debug: # log.debug('x mismatch %s != %s', matching_terminal, # rule) # continue if debug: log.debug('match? %s ?= %s', matching_terminal, rule) # TODO: chce to použít _match_, protože z (NP g=I n=S c=1) nechci # predikovat (NP c=4) → (k=1 c=4) predicted = Edge(predicted_from=agenda_edge, predicted_by_rule=rule, how_created='predict %s') # log.warning('predicted %s from %s', predicted, # agenda_edge.current_symbol) yield predicted if __name__ == '__main__': top_down = TopDownChartParser(argv=sys.argv) top_down.parse_from_vertical()