Example #1
0
 def __init__(self, grammar, drt_parser):
     assert isinstance(grammar, str) and grammar.endswith('.fcfg'), \
                         "%s is not a grammar name" % grammar
     self.drt_parser = drt_parser()
     self.presupp_parser = PresuppDrtParser()
     self.logic_parser = LogicParser()
     self.parser = load_parser(grammar, logic_parser=self.drt_parser) 
Example #2
0
class Tester(object):
    
    INFERROR = {
    3 : AdmissibilityError,
    2 : InformativityError,
    1 : ConsistencyError           
    }
    
    WORD_SPLIT = re.compile(" |, |,")
    EXCLUDED_NEXT = re.compile("^ha[sd]|is|was|not|will$")
    EXCLUDED = re.compile("^does|h?is|red|[a-z]+ness$")
    SUBSTITUTIONS = [
     (re.compile("^died$"), ("did", "die")),
     (re.compile("^([A-Z][a-z]+)'s?$"), lambda m: (m.group(1), "s")),
     (re.compile("^(?P<stem>[a-z]+)s$"), lambda m: ("does", m.group("stem"))),
     (re.compile("^([a-z]+(?:[^cvklt]|lk|nt))ed|([a-z]+[cvlkt]e)d$"), lambda m: ("did", m.group(1) if m.group(1) else m.group(2))),
     (re.compile("^([A-Z]?[a-z]+)one$"), lambda m: (m.group(1), "one")),
     (re.compile("^([A-Z]?[a-z]+)thing$"), lambda m: (m.group(1), "thing")),
     (re.compile("^bit$"), ("did", "bite")),
     (re.compile("^bought$"), ("did", "buy")),
     (re.compile("^wrote$"), ("did", "write")),
    ]
    
    def __init__(self, grammar, drt_parser):
        assert isinstance(grammar, str) and grammar.endswith('.fcfg'), \
                            "%s is not a grammar name" % grammar
        self.drt_parser = drt_parser()
        self.presupp_parser = PresuppDrtParser()
        self.logic_parser = LogicParser()
        self.parser = load_parser(grammar, logic_parser=self.drt_parser) 

    def _split(self, sentence):
        words = []
        exlude_next = False
        for word in Tester.WORD_SPLIT.split(sentence):
            match = None
            if Tester.EXCLUDED_NEXT.match(word):
                exlude_next = True
                words.append(word)
                continue
            if exlude_next or Tester.EXCLUDED.match(word):
                exlude_next = False
                words.append(word)
                continue
            for pattern, replacement in Tester.SUBSTITUTIONS:
                match = pattern.match(word)
                if match:
                    if isinstance(replacement, LambdaType):
                        words.extend(replacement(match))
                    else:
                        words.extend(replacement)
                    break

            if not match:
                words.append(word)

        return words

    def parse(self, text, **args):
        sentences = text.split('.')
        utter = args.get("utter", True)
        verbose = args.get("verbose", False)
        drs = (utter and self.drt_parser.parse('DRS([n],[])')) or []
        
        for sentence in sentences:
            sentence = sentence.lstrip()
            if sentence:
                words = self._split(sentence)
                if verbose:
                    print words
                trees = self.parser.nbest_parse(words)
                try:
                    new_drs = trees[0].node['SEM'].simplify()
                except IndexError:
                    raise UngrammaticalException()
                if verbose:
                    print(new_drs)
                if drs:
                    drs = (drs + new_drs).simplify()
                else:
                    drs = new_drs
    
        if verbose:
            print drs
        return drs

    def test(self, cases, **args):
        verbose = args.get("verbose", False)
        for number, sentence, expected in cases:
            expected_drs = []
            if expected:
                for item in expected if isinstance(expected, list) else [expected]:
                    expected_drs.append(self.presupp_parser.parse(item, verbose))

            try:
                expression = self.parse(sentence, **args)
                readings, errors = expression.resolve(lambda x: (True, None), verbose)
                if len(expected_drs) == len(readings):
                    for index, pair in enumerate(zip(expected_drs, readings)):
                        if pair[0] == pair[1]:
                            print("%s. %s -- Reading (%s): %s\n" % (number, sentence, index + 1, pair[1]))
                        else:
                            print("%s. !!!failed reading (%s)!!!\n\n%s\n\nExpected:\t%s\n\nReturns:\t%s\n" %
                                  (number, index + 1, sentence, pair[0], pair[1]))
                else:
                        print("%s. !!!comparison failed!!!\n\n%s\n" % (number, sentence))
            except Exception as e:
                if type(e) is ResolutionException:
                    print("%s. *%s -- Exception:%s\n" % (number, sentence, e))
                else:
                    print("%s. !!!unexpected error!!!\n%s\n%s" % (number, sentence, e))

    def interpret(self, expr_1, expr_2, background=None, verbose=False, test=False):
        """Interprets a new expression with respect to some previous discourse 
        and background knowledge. The function first generates relevant background
        knowledge and then performs inference check on readings generated by 
        the resolve() method. It returns a list of admissible interpretations in
        the form of DRSs."""
        
        assert(not expr_1 or isinstance(expr_1, str)), "Expression %s is not a string" % expr_1
        assert(isinstance(expr_2, str)), "Expression %s is not a string" % expr_2
        assert(not background or  isinstance(background, dict)), "Background knowledge is not in dictionary format"
        try:
            if expr_1:
                discourse = self.parse(expr_1, utter=True)
                expression = self.parse_new(discourse, expr_2)          
            else:
                discourse = None
                expression = self.parse(expr_2, utter=True)

            interpretations, errors = self.interpret_new(discourse, expression, background=background, verbose=verbose)

            if test:
                return interpretations, errors
            else:
                return interpretations
            
        except IndexError:
            print "Input sentences only!"
            
        except ValueError as e:
            print "Error:", e
        
    def collect_background(self, discourse, background, verbose=False):
        background_knowledge = None                
        for formula in get_bk(discourse, background):
            try:
                parsed_formula = self.presupp_parser.parse(formula).fol()
            except ParseException:
                try:
                    parsed_formula = self.logic_parser.parse(formula)
                except Exception as e:
                    print "Error: %s" % e
                    
            if background_knowledge:
                background_knowledge = AndExpression(background_knowledge, parsed_formula)
            else:
                background_knowledge = parsed_formula
                            
        if verbose:
            print "Generated background knowledge:\n%s" % background_knowledge

        return background_knowledge

    def parse_new(self, discourse, expression_str):
        """parse the new expression and make sure that it has unique variables"""
        expression = self.parse(expression_str, utter=False)
        for ref in set(expression.get_refs(True)) & set(discourse.get_refs(True)):
            newref = DrtVariableExpression(unique_variable(ref))
            expression = expression.replace(ref, newref, True)
        return expression

    def interpret_new(self, discourse, expression, background=None, verbose=False):
        """Interprets a new expression with respect to some previous discourse 
        and background knowledge. The function first generates relevant background
        knowledge and then performs inference check on readings generated by 
        the resolve() method. It returns a list of admissible interpretations in
        the form of DRSs."""

        try:
            if discourse:
                new_discourse = (NewInfoDRS([], [expression]) + discourse).simplify()
            else:
                new_discourse = expression

            if background:      
                background_knowledge = self.collect_background(new_discourse, background, verbose)
            else:
                background_knowledge = None
                    
            return new_discourse.resolve(lambda x: inference_check(x, background_knowledge, verbose), verbose)
            
        except IndexError:
            print "Input sentences only!"
            
        except ValueError as e:
            print "Error: %s" % e

    def inference_test(self, cases, bk, verbose=False):
        for number, discourse, expression, judgement in cases:
            print "\n%s. %s %s" % (number, discourse, expression)
            interpretations, errors = self.interpret(discourse, expression, bk, verbose=False, test=True)
            
            for interpretation in interpretations:
                print "\nAdmissible interpretation: ", interpretation
            
            if judgement:
                
                if not isinstance(judgement, list):
                    judgement = [judgement]
                
                if len(judgement) == len(errors):
                    for index, error in enumerate(errors):
                        error_message = Tester.INFERROR.get(judgement[index], False)
                        if verbose:
                            print "\nexpected error:%s" % error_message
                            print "\nreturned error:%s" % error[1]
                        if type(error[1]) is error_message:
                            print "\nInadmissible reading %s returns as expected:\n\t%s" % (error[0], error_message.__name__)
                        else:
                            print "\n#!!!#: Inadmissible reading %s returned with unexpected error: %s" % (error[0], error[1])
                else:
                    print "\n#!!!#: !Unexpected error! #!!!#"
            
            else:
                print "\nNo inadmissible readings"