#!/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()