.. Copyright (C) 2001-2010 NLTK Project .. For license information, see LICENSE.TXT ================================ Discourse Representation Theory ================================ >>> from nltk.sem import logic >>> from nltk.inference import TableauProver Overview ======== A DRS can be created with the ``DRS()`` constructor. This takes two arguments: a list of discourse referents and list of conditions. . >>> from nltk.sem.drt import * >>> dp = DrtParser() >>> man_x = dp.parse('man(x)') >>> walk_x = dp.parse('walk(x)') >>> x = dp.parse('x') >>> print DRS([x], [man_x, walk_x]) ([x],[man(x), walk(x)]) The ``parse()`` method can also be applied directly to DRS expressions, which allows them to be specified more easily. >>> drs1 = dp.parse('([x],[man(x),walk(x)])') >>> print drs1 ([x],[man(x), walk(x)]) DRSs can be *merged* using the ``+`` operator. >>> drs2 = dp.parse('([y],[woman(y),stop(y)])') >>> drs3 = drs1 + drs2 >>> print drs3 (([x],[man(x), walk(x)]) + ([y],[woman(y), stop(y)])) >>> print drs3.simplify() ([x,y],[man(x), walk(x), woman(y), stop(y)]) We can embed DRSs as components of an ``implies`` condition. >>> s = '([], [(%s -> %s)])' % (drs1, drs2) >>> print dp.parse(s) ([],[(([x],[man(x), walk(x)]) -> ([y],[woman(y), stop(y)]))]) The ``fol()`` method converts DRSs into FOL formulae. >>> print dp.parse(r'([x],[man(x), walks(x)])').fol() exists x.(man(x) & walks(x)) >>> print dp.parse(r'([],[(([x],[man(x)]) -> ([],[walks(x)]))])').fol() all x.(man(x) -> walks(x)) In order to visualize a DRS, the ``draw()`` method can be use. >>> drs3.draw() # doctest: +SKIP Parse to semantics ------------------ .. >>> logic._counter._value = 0 DRSs can be used for building compositional semantics in a feature based grammar. To specify that we want to use DRSs, the appropriate logic parser needs be passed as a parameter to ``load_earley()`` >>> from nltk.parse import load_earley >>> parser = load_earley('grammars/book_grammars/drt.fcfg', trace=0, logic_parser=DrtParser()) >>> trees = parser.nbest_parse('a dog barks'.split()) >>> print trees[0].node['SEM'].simplify() ([x],[dog(x), bark(x)]) Alternatively, a ``FeatStructParser`` can be passed with the ``logic_parser`` set on it >>> from nltk.featstruct import FeatStructParser >>> from nltk.grammar import FeatStructNonterminal >>> parser = load_earley('grammars/book_grammars/drt.fcfg', trace=0, fstruct_parser=FeatStructParser(fdict_class=FeatStructNonterminal, logic_parser=DrtParser())) >>> trees = parser.nbest_parse('every girl chases a dog'.split()) >>> print trees[0].node['SEM'].simplify() ([],[(([x],[girl(x)]) -> ([z2],[dog(z2), chase(x,z2)]))]) Unit Tests ========== Parser ------ >>> print dp.parse(r'([x,y],[sees(x,y)])') ([x,y],[sees(x,y)]) >>> print dp.parse(r'([x],[man(x), walks(x)])') ([x],[man(x), walks(x)]) >>> print dp.parse(r'\x.([],[man(x), walks(x)])') \x.([],[man(x), walks(x)]) >>> print dp.parse(r'\x.\y.([],[sees(x,y)])') \x y.([],[sees(x,y)]) >>> print dp.parse(r'([x,y],[(x = y)])') ([x,y],[(x = y)]) >>> print dp.parse(r'([x,y],[(x != y)])') ([x,y],[-(x = y)]) >>> print dp.parse(r'\x.([],[walks(x)])(john)') (\x.([],[walks(x)]))(john) >>> print dp.parse(r'\R.\x.([],[big(x,R)])(\y.([],[mouse(y)]))') (\R x.([],[big(x,R)]))(\y.([],[mouse(y)])) >>> print dp.parse(r'(([x],[walks(x)]) + ([y],[runs(y)]))') (([x],[walks(x)]) + ([y],[runs(y)])) >>> print dp.parse(r'(([x,y],[walks(x), jumps(y)]) + (([z],[twos(z)]) + ([w],[runs(w)])))') (([x,y],[walks(x), jumps(y)]) + (([z],[twos(z)]) + ([w],[runs(w)]))) >>> print dp.parse(r'((([],[walks(x)]) + ([],[twos(x)])) + ([],[runs(x)]))') ((([],[walks(x)]) + ([],[twos(x)])) + ([],[runs(x)])) >>> print dp.parse(r'((([],[walks(x)]) + ([],[runs(x)])) + (([],[threes(x)]) + ([],[fours(x)])))') ((([],[walks(x)]) + ([],[runs(x)])) + (([],[threes(x)]) + ([],[fours(x)]))) >>> print dp.parse(r'(([],[walks(x)]) -> ([],[runs(x)]))') (([],[walks(x)]) -> ([],[runs(x)])) >>> print dp.parse(r'([x],[PRO(x), sees(John,x)])') ([x],[PRO(x), sees(John,x)]) >>> print dp.parse(r'([x],[man(x), -([],[walks(x)])])') ([x],[man(x), -([],[walks(x)])]) >>> print dp.parse(r'([],[(([x],[man(x)]) -> ([],[walks(x)]))])') ([],[(([x],[man(x)]) -> ([],[walks(x)]))]) >>> print dp.parse(r'DRS([x],[walk(x)])') ([x],[walk(x)]) >>> print dp.parse(r'DRS([x][walk(x)])') ([x],[walk(x)]) >>> print dp.parse(r'([x][walk(x)])') ([x],[walk(x)]) ``simplify()`` -------------- >>> print dp.parse(r'\x.([],[man(x), walks(x)])(john)').simplify() ([],[man(john), walks(john)]) >>> print dp.parse(r'\x.\y.([z],[dog(z),sees(x,y)])(john)(mary)').simplify() ([z],[dog(z), sees(john,mary)]) >>> print dp.parse(r'\R x.([],[big(x,R)])(\y.([],[mouse(y)]))').simplify() \x.([],[big(x,\y.([],[mouse(y)]))]) >>> print dp.parse(r'(([x],[walks(x)]) + ([y],[runs(y)]))').simplify() ([x,y],[walks(x), runs(y)]) >>> print dp.parse(r'(([x,y],[walks(x), jumps(y)]) + (([z],[twos(z)]) + ([w],[runs(w)])))').simplify() ([x,y,z,w],[walks(x), jumps(y), twos(z), runs(w)]) >>> print dp.parse(r'((([],[walks(x)]) + ([],[runs(x)]) + ([],[threes(x)]) + ([],[fours(x)])))').simplify() ([],[walks(x), runs(x), threes(x), fours(x)]) >>> dp.parse(r'([x],[man(x)])+([x],[walks(x)])').simplify() == \ ... dp.parse(r'([x,z1],[man(x), walks(z1)])') True >>> dp.parse(r'([y],[boy(y), (([x],[dog(x)]) -> ([],[chase(x,y)]))])+([x],[run(x)])').simplify() == \ ... dp.parse(r'([y,z1],[boy(y), (([x],[dog(x)]) -> ([],[chase(x,y)])), run(z1)])') True >>> dp.parse(r'\Q.(([x],[john(x),walks(x)]) + Q)(([x],[PRO(x),leaves(x)]))').simplify() == \ ... dp.parse(r'([x,z1],[john(x), walks(x), PRO(z1), leaves(z1)])') True >>> logic._counter._value = 0 >>> print dp.parse('([],[(([x],[dog(x)]) -> ([y,e],[boy(y), chase(e), subj(e,x), obj(e,y)]))])+([x,e],[PRO(x), run(e), subj(e,x)])').simplify() ([z1,e02],[(([x],[dog(x)]) -> ([y,e],[boy(y), chase(e), subj(e,x), obj(e,y)])), PRO(z1), run(e02), subj(e02,z1)]) ``fol()`` ----------- >>> print dp.parse(r'([x,y],[sees(x,y)])').fol() exists x y.sees(x,y) >>> print dp.parse(r'([x],[man(x), walks(x)])').fol() exists x.(man(x) & walks(x)) >>> print dp.parse(r'\x.([],[man(x), walks(x)])').fol() \x.(man(x) & walks(x)) >>> print dp.parse(r'\x y.([],[sees(x,y)])').fol() \x y.sees(x,y) >>> print dp.parse(r'\x.([],[walks(x)])(john)').fol() \x.walks(x)(john) >>> print dp.parse(r'\R x.([],[big(x,R)])(\y.([],[mouse(y)]))').fol() (\R x.big(x,R))(\y.mouse(y)) >>> print dp.parse(r'(([x],[walks(x)]) + ([y],[runs(y)]))').fol() (exists x.walks(x) & exists y.runs(y)) >>> print dp.parse(r'(([],[walks(x)]) -> ([],[runs(x)]))').fol() (walks(x) -> runs(x)) >>> print dp.parse(r'([x],[PRO(x), sees(John,x)])').fol() exists x.(PRO(x) & sees(John,x)) >>> print dp.parse(r'([x],[man(x), -([],[walks(x)])])').fol() exists x.(man(x) & -walks(x)) >>> print dp.parse(r'([],[(([x],[man(x)]) -> ([],[walks(x)]))])').fol() all x.(man(x) -> walks(x)) >>> print dp.parse(r'([x],[man(x) | walks(x)])').fol() exists x.(man(x) | walks(x)) >>> print dp.parse(r'([x],[man(x) <-> walks(x)])').fol() exists x.(man(x) <-> walks(x)) >>> print dp.parse(r'P(x) + ([x],[walks(x)])').fol() (P(x) & exists x.walks(x)) ``resolve_anaphora()`` ---------------------- >>> from nltk.sem.drt import AnaphoraResolutionException >>> print resolve_anaphora(dp.parse(r'([x,y,z],[dog(x), cat(y), walks(z), PRO(z)])')) ([x,y,z],[dog(x), cat(y), walks(z), (z = [x,y])]) >>> print resolve_anaphora(dp.parse(r'([],[(([x],[dog(x)]) -> ([y],[walks(y), PRO(y)]))])')) ([],[(([x],[dog(x)]) -> ([y],[walks(y), (y = x)]))]) >>> print resolve_anaphora(dp.parse(r'(([x,y],[]) + ([],[PRO(x)]))')).simplify() ([x,y],[(x = y)]) >>> try: print resolve_anaphora(dp.parse(r'([x],[walks(x), PRO(x)])')) ... except AnaphoraResolutionException, e: print e Variable 'x' does not resolve to anything. >>> print resolve_anaphora(dp.parse('([z6,z7,e1],[boy(z6), PRO(z7), run(e1), subj(e1,z7)])')) ([z6,z7,e1],[boy(z6), (z7 = z6), run(e1), subj(e1,z7)]) ``tp_equals()``: ---------------- >>> a = dp.parse(r'([x],[man(x), walks(x)])') >>> b = dp.parse(r'([x],[walks(x), man(x)])') >>> print a.tp_equals(b, TableauProver()) True ``replace()``: -------------- >>> a = dp.parse(r'a') >>> w = dp.parse(r'w') >>> x = dp.parse(r'x') >>> y = dp.parse(r'y') >>> z = dp.parse(r'z') replace bound ------------- >>> print dp.parse(r'([x],[give(x,y,z)])').replace(x.variable, a, False) ([x],[give(x,y,z)]) >>> print dp.parse(r'([x],[give(x,y,z)])').replace(x.variable, a, True) ([a],[give(a,y,z)]) replace unbound --------------- >>> print dp.parse(r'([x],[give(x,y,z)])').replace(y.variable, a, False) ([x],[give(x,a,z)]) >>> print dp.parse(r'([x],[give(x,y,z)])').replace(y.variable, a, True) ([x],[give(x,a,z)]) replace unbound with bound -------------------------- >>> dp.parse(r'([x],[give(x,y,z)])').replace(y.variable, x, False) == \ ... dp.parse('([z1],[give(z1,x,z)])') True >>> dp.parse(r'([x],[give(x,y,z)])').replace(y.variable, x, True) == \ ... dp.parse('([z1],[give(z1,x,z)])') True replace unbound with unbound ---------------------------- >>> print dp.parse(r'([x],[give(x,y,z)])').replace(y.variable, z, False) ([x],[give(x,z,z)]) >>> print dp.parse(r'([x],[give(x,y,z)])').replace(y.variable, z, True) ([x],[give(x,z,z)]) replace unbound --------------- >>> print dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,z)])').replace(z.variable, a, False) (([x],[P(x,y,a)]) + ([y],[Q(x,y,a)])) >>> print dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,z)])').replace(z.variable, a, True) (([x],[P(x,y,a)]) + ([y],[Q(x,y,a)])) replace bound ------------- >>> print dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,z)])').replace(x.variable, a, False) (([x],[P(x,y,z)]) + ([y],[Q(x,y,z)])) >>> print dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,z)])').replace(x.variable, a, True) (([a],[P(a,y,z)]) + ([y],[Q(a,y,z)])) replace unbound with unbound ---------------------------- >>> print dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,z)])').replace(z.variable, a, False) (([x],[P(x,y,a)]) + ([y],[Q(x,y,a)])) >>> print dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,z)])').replace(z.variable, a, True) (([x],[P(x,y,a)]) + ([y],[Q(x,y,a)])) replace unbound with bound on same side --------------------------------------- >>> dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,w)])').replace(z.variable, x, False) == \ ... dp.parse(r'(([z1],[P(z1,y,x)]) + ([y],[Q(z1,y,w)]))') True >>> dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,w)])').replace(z.variable, x, True) == \ ... dp.parse(r'(([z1],[P(z1,y,x)]) + ([y],[Q(z1,y,w)]))') True replace unbound with bound on other side ---------------------------------------- >>> dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,w)])').replace(w.variable, x, False) == \ ... dp.parse(r'(([z1],[P(z1,y,z)]) + ([y],[Q(z1,y,x)]))') True >>> dp.parse(r'([x],[P(x,y,z)])+([y],[Q(x,y,w)])').replace(w.variable, x, True) == \ ... dp.parse(r'(([z1],[P(z1,y,z)]) + ([y],[Q(z1,y,x)]))') True replace unbound with double bound --------------------------------- >>> dp.parse(r'([x],[P(x,y,z)])+([x],[Q(x,y,w)])').replace(z.variable, x, False) == \ ... dp.parse(r'(([z1],[P(z1,y,x)]) + ([z1],[Q(z1,y,w)]))') True >>> dp.parse(r'([x],[P(x,y,z)])+([x],[Q(x,y,w)])').replace(z.variable, x, True) == \ ... dp.parse(r'(([z1],[P(z1,y,x)]) + ([z1],[Q(z1,y,w)]))') True Parse errors ============ >>> try: dp.parse(r'') ... except ParseException, e: print e End of input found. Expression expected. ^ >>> try: dp.parse(r'(') ... except ParseException, e: print e End of input found. Expression expected. ( ^ >>> try: dp.parse(r'()') ... except ParseException, e: print e Unexpected token: ')'. Expression expected. () ^ >>> try: dp.parse(r'([') ... except ParseException, e: print e End of input found. Expected token ']'. ([ ^ >>> try: dp.parse(r'([,') ... except ParseException, e: print e ',' is an illegal variable name. Constants may not be quantified. ([, ^ >>> try: dp.parse(r'([x,') ... except ParseException, e: print e End of input found. Variable expected. ([x, ^ >>> try: dp.parse(r'([]') ... except ParseException, e: print e End of input found. Expected token '['. ([] ^ >>> try: dp.parse(r'([][') ... except ParseException, e: print e End of input found. Expected token ']'. ([][ ^ >>> try: dp.parse(r'([][,') ... except ParseException, e: print e Unexpected token: ','. Expression expected. ([][, ^ >>> try: dp.parse(r'([][]') ... except ParseException, e: print e End of input found. Expected token ')'. ([][] ^ >>> try: dp.parse(r'([x][man(x)]) |') ... except ParseException, e: print e End of input found. Expression expected. ([x][man(x)]) | ^