Transitive Verbs

Our next challenge is to deal with sentences containing transitive verbs, such as (46).

(46) Angus chases a dog.

The output semantics that we want to build is exists x.(dog(x) & chase(angus, x)). Let's look at how we can use A-abstraction to get this result. A significant constraint on possible solutions is to require that the semantic representation of a dog be independent of whether the NP acts as subject or object of the sentence. In other words, we want to get the formula just shown as our output while sticking to (43) as the NP semantics. A second constraint is that VPs should have a uniform type of interpretation, regardless of whether they consist of just an intransitive verb or a transitive verb plus object. More specifically, we stipulate that VPs are always of type (e, t). Given these constraints, here's a semantic representation for chases a dog that does the trick.

Think of (47) as the property of being a y such that for some dog x, y chases x; or more colloquially, being a y who chases a dog. Our task now resolves to designing a semantic representation for chases which can combine with (43) so as to allow (47) to be derived.

Let's carry out the inverse of ^-reduction on (47), giving rise to (48).

(48) \P.exists x.(dog(x) & P(x))(\z.chase(y, z))

(48) may be slightly hard to read at first; you need to see that it involves applying the quantified NP representation from (43) to \z.chase(y,z). (48) is equivalent via reduction to exists x.(dog(x) & chase(y, x)).

Now let's replace the function expression in (48) by a variable X of the same type as an NP, that is, of type ((e, t), t).

The representation of a transitive verb will have to apply to an argument of the type of X to yield a function expression of the type of VPs, that is, of type (e, t). We can ensure this by abstracting over both the X variable in (49) and also the subject variable y. So the full solution is reached by giving chases the semantic representation shown in (50).

If (50) is applied to (43), the result after P-reduction is equivalent to (47), which is what we wanted all along:

>>> tvp = lp.parse(r'\X x.X(\y.chase(x,y))')

>>> np = lp.parse(r'(\P.exists x.(dog(x) & P(x)))')

>>> vp = nltk.ApplicationExpression(tvp, np)

(\X x.X(\y.chase(x,y)))(\P.exists x.(dog(x) & P(x)))

In order to build a semantic representation for a sentence, we also need to combine in the semantics of the subject NP. If the latter is a quantified expression, such as every girl, everything proceeds in the same way as we showed for a dog barks earlier on; the subject is translated as a function expression which is applied to the semantic representation of the VP. However, we now seem to have created another problem for ourselves with proper names. So far, these have been treated semantically as individual constants, and these cannot be applied as functions to expressions like (47). Consequently, we need to come up with a different semantic representation for them. What we do in this case is reinterpret proper names so that they too are function expressions, like quantified NPs. Here is the required A-expression for Angus:

(51) denotes the characteristic function corresponding to the set of all properties which are true of Angus. Converting from an individual constant angus to \P.P(angus) is another example of type-raising, briefly mentioned earlier, and allows us to replace a Boolean-valued application such as \x.walk(x)(angus) with an equivalent function application \P.P(angus)(\x.walk(x)). By P-reduction, both expressions reduce to walk(angus).

The grammar simple-sem.fcfg contains a small set of rules for parsing and translating simple examples of the kind that we have been looking at. Here's a slightly more complicated example:

>>> from nltk import load_parser

>>> parser = load_parser('grammars/book_grammars/simple-sem.fcfg', trace=0)

>>> sentence = 'Angus gives a bone to every dog'

>>> trees = parser.nbest_parse(tokens)

all z2.(dog(z2) -> exists z1.(bone(z1) & give(angus,z1,z2)))

NLTK provides some utilities to make it easier to derive and inspect semantic interpretations. The function batch_interpret() is intended for batch interpretation of a list of input sentences. It builds a dictionary d where for each sentence sent in the input, d[sent] is a list of pairs (synrep, semrep) consisting of trees and semantic representations for sent. The value is a list since sent may be syntactically ambiguous; in the following example, however, there is only one parse tree per sentence in the list.

(S[SEM=<walk(irene)>] (NP[-LOC, NUM='sg', SEM=<\P.P(irene)>]

(PropN[-LOC, NUM='sg', SEM=<\P.P(irene)>] Irene)) (VP[NUM='sg', SEM=<\x.walk(x)>] (IV[NUM='sg', SEM=<\x.walk(x)>, TNS='pres'] walks))) (S[SEM=<exists z1.(ankle(z1) & bite(cyril,z1))>] (NP[-LOC, NUM='sg', SEM=<\P.P(cyril)>]

(PropN[-LOC, NUM='sg', SEM=<\P.P(cyril)>] Cyril)) (VP[NUM='sg', SEM=<\x.exists z1.(ankle(z1) & bite(x,z1))>] (TV[NUM='sg', SEM=<\X x.X(\y.bite(x,y))>, TNS='pres'] bites) (NP[NUM='sg', SEM=<\Q.exists x.(ankle(x) & Q(x))>] (Det[NUM='sg', SEM=<\P Q.exists x.(P(x) & Q(x))>] an) (Nom[NUM='sg', SEM=<\x.ankle(x)>] (N[NUM='sg', SEM=<\x.ankle(x)>] ankle)))))

We have seen now how to convert English sentences into logical forms, and earlier we saw how logical forms could be checked as true or false in a model. Putting these two mappings together, we can check the truth value of English sentences in a given model. Let's take model m as defined earlier. The utility batch_evaluate() resembles batch_interpret(), except that we need to pass a model and a variable assignment as parameters. The output is a triple (synrep, semrep, value), where synrep, semrep are as before, and value is a truth value. For simplicity, the following example only processes a single sentence.

>>> val = nltk.parse_valuation(v) >>> g = nltk.Assignment(val.domain) >>> m = nltk.Model(val.domain, val) >>> sent = 'Cyril sees every boy'

>>> grammar_file = 'grammars/book_grammars/simple-sem.fcfg' >>> results = nltk.batch_evaluate([sent], grammar_file, m, g)[0] >>> for (syntree, semrel, value) in results: ... print semrep

... print value exists z3.(ankle(z3) & bite(cyril,z3)) True

+2 0

Post a comment