class PremodifierTest(unittest.TestCase):
    # @Before
    def setUp(self):
        self.lexicon = Lexicon.getDefaultLexicon()
        self.phraseFactory = NLGFactory(self.lexicon)
        self.realiser = Realiser(self.lexicon)

    # Test change from "a" to "an" in the presence of a premodifier with a vowel
    def testIndefiniteWithPremodifier(self):
        s = self.phraseFactory.createClause("there", "be")
        s.setFeature(Feature.TENSE, Tense.PRESENT)
        np = self.phraseFactory.createNounPhrase("a", "stenosis")
        s.setObject(np)
        # check without modifiers -- article should be "a"
        self.assertEqual("there is a stenosis",
                         self.realiser.realise(s).getRealisation())
        # add a single modifier -- should turn article to "an"
        np.addPreModifier(
            self.phraseFactory.createAdjectivePhrase("eccentric"))
        self.assertEqual("there is an eccentric stenosis",
                         self.realiser.realise(s).getRealisation())

    # Test for comma separation between premodifers
    def testMultipleAdjPremodifiers(self):
        np = self.phraseFactory.createNounPhrase("a", "stenosis")
        np.addPreModifier(
            self.phraseFactory.createAdjectivePhrase("eccentric"))
        np.addPreModifier(self.phraseFactory.createAdjectivePhrase("discrete"))
        self.assertEqual("an eccentric, discrete stenosis",
                         self.realiser.realise(np).getRealisation())

    # Test for comma separation between verb premodifiers
    def testMultipleAdvPremodifiers(self):
        adv1 = self.phraseFactory.createAdverbPhrase("slowly")
        adv2 = self.phraseFactory.createAdverbPhrase("discretely")
        # case 1: concatenated premods: should have comma
        vp = self.phraseFactory.createVerbPhrase("run")
        vp.addPreModifier(adv1)
        vp.addPreModifier(adv2)
        self.assertEqual("slowly, discretely runs",
                         self.realiser.realise(vp).getRealisation())
        # case 2: coordinated premods: no comma
        vp2 = self.phraseFactory.createVerbPhrase("eat")
        vp2.addPreModifier(
            self.phraseFactory.createCoordinatedPhrase(adv1, adv2))
        self.assertEqual("slowly and discretely eats",
                         self.realiser.realise(vp2).getRealisation())
Beispiel #2
0
class Realizer(object):
    def __init__(self):
        verb2noun, noun2verb, verb2actor, actor2verb = utils.noun_verb(
            prop.morph_verb)
        self.verb2noun = verb2noun
        self.verb2actor = verb2actor

        sub2word = utils.subgraph_word(prop.verbalization)
        self.sub2word = sub2word

        lexicon = Lexicon.getDefaultLexicon()
        self.nlgFactory = NLGFactory(lexicon)
        self.realiser = Realiser(lexicon)

    def create_clause(self, subject, vp, _object, frontmodifiers, complements):
        phrase = self.nlgFactory.createClause()
        phrase.setSubject(subject)
        phrase.setVerbPhrase(vp)

        if _object != None:
            phrase.setObject(_object)

        for frontmodifier in frontmodifiers:
            phrase = self.add_frontmodifier(phrase, frontmodifier)

        for complement in complements:
            phrase = self.add_complement(phrase, complement)
        return phrase

    def create_np(self, determiner, head, number, premodifiers, postmodifiers):
        np = self.nlgFactory.createNounPhrase()
        np.setNoun(head)

        if determiner != '':
            np.setDeterminer(determiner)

        if number == 'singular':
            np.setFeature(Feature.NUMBER, NumberAgreement.SINGULAR)
        elif number == 'plural':
            np.setFeature(Feature.NUMBER, NumberAgreement.PLURAL)

        for premodifier in premodifiers:
            np = self.add_premodifier(np, premodifier)

        for postmodifier in postmodifiers:
            np = self.add_postmodifier(np, postmodifier)

        return np

    def create_vp(self, sentence):
        verb = sentence['verb']
        voice = sentence['voice']
        tense = sentence['tense']
        perfect = sentence['perfect']
        form = sentence['form']
        modal = sentence['modal']

        vp = self.nlgFactory.createVerbPhrase()
        vp.setVerb(verb)

        if tense == "past":
            vp.setFeature(Feature.TENSE, Tense.PAST)
        elif tense == "present":
            vp.setFeature(Feature.TENSE, Tense.PRESENT)
        elif tense == "future":
            vp.setFeature(Feature.TENSE, Tense.FUTURE)

        if voice == "active":
            vp.setFeature(Feature.PASSIVE, Boolean(False))
        else:
            vp.setFeature(Feature.PASSIVE, Boolean(True))

        if perfect:
            vp.setFeature(Feature.PERFECT, Boolean(True))
        else:
            vp.setFeature(Feature.PERFECT, Boolean(False))

        if form == 'negative':
            vp.setFeature(Feature.NEGATED, Boolean(True))
        elif form == 'infinitive':
            vp.setFeature(Feature.FORM, Form.INFINITIVE)

        if modal == 'possible':
            vp.setFeature(Feature.MODAL, "can")
        elif modal == 'obligate':
            vp.setFeature(Feature.MODAL, "must")
        elif modal == 'permit':
            vp.setFeature(Feature.MODAL, "may")
        elif modal == 'recommend':
            vp.setFeature(Feature.MODAL, "should")
        return vp

    def create_pp(self, preposition, np):
        pp = self.nlgFactory.createPrepositionPhrase()
        pp.addComplement(np)
        pp.setPreposition(preposition)
        return pp

    def create_adjp(self, adjective):
        adjp = self.nlgFactory.createAdjectivePhrase(adjective)
        return adjp

    def create_advp(self, adverb):
        advp = self.nlgFactory.createAdverbPhrase(adverb)
        return advp

    def create_possessive(self):
        np = self.nlgFactory.createNounPhrase()
        np.setFeature(Feature.PRONOMINAL, Boolean(True))
        np.setFeature(Feature.POSSESSIVE, Boolean(True))
        return np

    def add_complement(self, phrase, complement):
        phrase.addComplement(complement)
        return phrase

    def add_premodifier(self, phrase, premodifier):
        phrase.addPreModifier(premodifier)
        return phrase

    def add_postmodifier(self, phrase, postmodifier):
        phrase.addPostModifier(postmodifier)
        return phrase

    def add_frontmodifier(self, phrase, frontmodifier):
        phrase.addFrontModifier(frontmodifier)
        return phrase

    def add_complementiser(self, phrase, complement):
        phrase.setFeature(Feature.COMPLEMENTISER, complement)
        return phrase

    def process_np(self, root):
        determiner, premodifiers, head, postmodifiers = '', [], '', []
        for node in self.tree.edges[root]:
            if self.tree.nodes[node].type == 'terminal':
                if self.tree.nodes[node].name == 'DT':
                    determiner = self.tree.nodes[node].lexicon
                elif self.tree.nodes[node].label > -1 and self.tree.nodes[
                        node].rule_id == self.tree.nodes[root].rule_id:
                    head = self.tree.nodes[node].lexicon
                elif self.tree.nodes[node].name == 'PRP$':
                    mod = self.create_possessive()
                    premodifiers.append(mod)
                else:
                    mod = self.tree.nodes[node].lexicon
                    if head == '':
                        premodifiers.append(mod)
                    else:
                        postmodifiers.append(mod)
            else:
                mod = self.process(node)
                if mod != None:
                    if head == '':
                        premodifiers.append(mod)
                    else:
                        postmodifiers.append(mod)

        if head == '':
            head = copy.copy(determiner)
            determiner = ''
        p = self.create_np(determiner=determiner,
                           head=head,
                           number='singular',
                           premodifiers=premodifiers,
                           postmodifiers=postmodifiers)
        return p

    def process_vp(self, root, sentence):
        for node in self.tree.edges[root]:
            if self.tree.nodes[node].type == 'terminal':
                # treat modals
                if self.tree.nodes[node].name == 'MD':
                    sentence['modal'] = self.tree.nodes[node].lexicon
                # treat infinitive
                elif self.tree.nodes[node].name == 'TO':
                    sentence['form'] = 'infinitive'
                # treat negative
                elif self.tree.nodes[node].lexicon == 'not':
                    sentence['form'] = 'negative'
                elif self.tree.nodes[node].name == 'VB':
                    sentence['verb'] = self.tree.nodes[node].lexicon


#                     if self.tree.nodes[node].label > -1 and self.tree.nodes[node].rule_id == self.tree.nodes[root].rule_id:
#                         sentence['verb'] = self.tree.nodes[node].lexicon
            else:
                if self.tree.nodes[node].name == 'VP':
                    sentence = self.process_vp(node, sentence)
                else:
                    p = self.process(node)
                    if p != None:
                        rule_id = self.tree.nodes[node].rule_id
                        rule = self.synchg.rules[rule_id]
                        edge = rule.name.split('/')[0]
                        pos = self.tree.nodes[node].name

                        if 'NP' in pos:
                            if edge == ':ARG1' and sentence[
                                    'voice'] == 'active':
                                sentence['object'] = p
                            else:
                                sentence['complements'].append(p)
                        elif pos == 'PP':
                            if edge == ':ARG0' and sentence[
                                    'voice'] == 'passive':
                                p = p.getChildren()[1]
                                sentence['subject'] = p
                            else:
                                sentence['complements'].append(p)
                        else:
                            sentence['complements'].append(p)
        return sentence

    def process_pp(self, root):
        preposition, np = '', None
        for node in self.tree.edges[root]:
            if self.tree.nodes[node].type == 'terminal':
                preposition = self.tree.nodes[node].lexicon
            else:
                np = self.process(node)
        p = self.create_pp(preposition, np)
        return p

    def process_adjvp(self, root):
        premodifiers, head, postmodifiers = [], '', []
        for node in self.tree.edges[root]:
            if self.tree.nodes[node].type == 'terminal':
                if self.tree.nodes[node].label > -1 and self.tree.nodes[
                        node].rule_id == self.tree.nodes[root].rule_id:
                    head = self.tree.nodes[node].lexicon
                else:
                    mod = self.tree.nodes[node].lexicon
                    if head == '':
                        premodifiers.append(mod)
                    else:
                        postmodifiers.append(mod)
            else:
                mod = self.process(node)
                if head == '':
                    premodifiers.append(mod)
                else:
                    postmodifiers.append(mod)
        if self.tree.nodes[root].name == 'ADJP':
            p = self.create_adjp(head)
        else:
            p = self.create_advp(head)

        for premodifier in premodifiers:
            self.add_premodifier(p, premodifier)

        for postmodifier in postmodifiers:
            self.add_postmodifier(p, postmodifier)
        return p

    def process_s(self, root):
        # get voice
        rule_id = self.tree.nodes[root].rule_id
        rule = self.synchg.rules[rule_id]
        voice = rule.features.voice

        sentence = {
            'subject': None,
            'object': None,
            'verb': '',
            'tense': 'present',
            'modal': '',
            'voice': voice,
            'perfect': False,
            'form': 'affirmative',
            'frontmodifiers': [],
            'complements': []
        }

        for node in self.tree.edges[root]:
            if self.tree.nodes[node].name not in ['.', ':']:
                rule_id = self.tree.nodes[node].rule_id
                rule = self.synchg.rules[rule_id]

                edge = rule.name.split('/')[0]
                pos = self.tree.nodes[node].name

                if pos == 'VP':
                    sentence = self.process_vp(node, sentence)
                else:
                    p = self.process(node)

                    if 'NP' in pos:
                        if edge == ':ARG0':
                            sentence['subject'] = p
                        elif edge == ':ARG1':
                            if voice == 'active':
                                sentence['subject'] = p
                            else:
                                sentence['object'] = p
                        else:
                            if sentence['verb'] == '':
                                sentence['frontmodifiers'].append(p)
                            else:
                                sentence['complements'].append(p)
                    elif pos == 'PP':
                        if edge == ':ARG0' and self.voice == 'passive':
                            p = p.getChildren()[1]
                            sentence['subject'] = p
                        else:
                            if sentence['verb'] == '':
                                sentence['frontmodifiers'].append(p)
                            else:
                                sentence['complements'].append(p)

        vp = self.create_vp(sentence)
        subject = sentence['subject']
        object = sentence['object']
        frontmodifiers = sentence['frontmodifiers']
        complements = sentence['complements']

        p = self.create_clause(subject=subject,
                               vp=vp,
                               _object=object,
                               frontmodifiers=frontmodifiers,
                               complements=complements)
        return p

    def process_sbar(self, root):
        p, complement = None, 'that'
        for node in self.tree.edges[root]:
            if self.tree.nodes[node].name == 'S':
                p = self.process_s(node)
            elif self.tree.nodes[node].name[0] == 'W':
                child = self.tree.edges[node][0]
                complement = self.tree.nodes[child].lexicon
        if p != None:
            p = self.add_complementiser(p, complement)
        return p

    def check_coordination(self, root):
        pass

    def process(self, root):
        if self.tree.nodes[root].name == 'S':
            p = self.process_s(root)
        # SUBORDINATE CLAUSE
        elif self.tree.nodes[root].name == 'SBAR':
            p = self.process_sbar(root)
        # NOUN PHRASE
        elif 'NP' in self.tree.nodes[root].name:
            p = self.process_np(root)
        # PREPOSITIONAL PHRASES
        elif self.tree.nodes[root].name == 'PP':
            p = self.process_pp(root)
        # ADJECTIVE AND ADVERBIAL PHRASES
        elif self.tree.nodes[root].name in ['ADJP', 'ADVP']:
            p = self.process_adjvp(root)
        elif self.tree.nodes[root].name == 'FRAG':
            p = self.process(self.tree.edges[root][0])
        else:
            p = None
        return p

    def run(self, tree, synchg):
        self.tree = tree
        self.synchg = synchg

        root = tree.root
        # TO DO: treat multi sentences
        if self.tree.nodes[root].name == 'MULTI-SENTENCE':
            p = None
        else:
            root = self.tree.edges[self.tree.root][0]
            self.subject, self.vp, self.object = None, None, None
            self.complements, self.frontmodifiers = [], []

            p = self.process(root)

        if p != None:
            return self.realiser.realise(p)
        else:
            return '-'