Discourse Representation Theory

 
>>> from nltk.sem import logic

1   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() 

1.1   Parse to semantics

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)]))])

2   Unit Tests

2.1   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)])

2.2   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)])

2.3   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))

2.4   resolve_anaphora()

 
>>> from nltk.sem.drt_resolve_anaphora import AnaphoraResolutionException
 
>>> print dp.parse(r'([x,y,z],[dog(x), cat(y), walks(z), PRO(z)])').resolve_anaphora()
([x,y,z],[dog(x), cat(y), walks(z), (z = [x,y])])
>>> print dp.parse(r'([],[(([x],[dog(x)]) -> ([y],[walks(y), PRO(y)]))])').resolve_anaphora()
([],[(([x],[dog(x)]) -> ([y],[walks(y), (y = x)]))])
>>> print dp.parse(r'(([x,y],[]) + ([],[PRO(x)]))').resolve_anaphora().simplify()
([x,y],[(x = y)])
>>> try: print dp.parse(r'([x],[walks(x), PRO(x)])').resolve_anaphora()
... except AnaphoraResolutionException, e: print e
Variable 'x' does not resolve to anything.
>>> print dp.parse('([z6,z7,e1],[boy(z6), PRO(z7), run(e1), subj(e1,z7)])').resolve_anaphora()
([z6,z7,e1],[boy(z6), (z7 = z6), run(e1), subj(e1,z7)])

2.5   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)
True

2.6   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')

2.7   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)])

2.8   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)])

2.9   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

2.10   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)])

2.11   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)]))

2.12   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)]))

2.13   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)]))

2.14   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

2.15   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

2.16   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