Suppose we want to capture this with a (P)CFG.... the only real way to do this is to expand our set of non-terminals. I.e., we might start with a grammar like:
S -> NP VP NP -> Pro NP -> Det Noun VP -> Verb NP Pro -> he Pro -> they Verb -> eat Verb -> eats Det -> a
Which will generate our good sentences, but also bad sentences like "He eat a sandwich" and "They eats a sandwich". We can fix this by adding labels to our non-terminals:
S -> NP+sing VP+sing S -> NP+plur VP+plur NP+sing -> Pro+sing NP+plur -> Pro+plur NP+sing -> Det Noun+sing NP+plur -> Det Noun+plur VP+sing -> Verb+sing NP VP+plur -> Verb+plur NP Pro+sing -> he Pro+plur -> they Verb+sing -> eats Verb+plur -> eat Det -> a
Now life is great: we will no longer produce our bogus sentences. (Note that we would also have to account for "a" being singular, etc...)
Of course there are other phenomena we might want to capture, for instance pronouns sitting in object position have to change case: "A sandwich eats him" not "A sandwich eats he". If we ignore the singular/plural distinction, we can solve this separately.
S -> NP+nom VP VP -> Verb NP+acc NP+nom -> Pro+nom NP+acc -> Pro+acc NP -> Det Noun Pro+nom -> he Pro+acc -> him Pro+nom -> they Pro+acc -> them
And so on...
We've now solve the nominative/accusative issue, so we can combine the sing/plur grammar with the nom/acc grammar. The problem is exponential blowup: handling one roughly doubled the size of the grammar, handling the other doubles it again. In general, for every agreement-like phenomenon we want to handle, we'll double the size of our grammar again. This is bad (a) because it makes our grammar huge and (b) because we'll need tons and tons and tons of data to get reliable estimates of these probabilities from a treebank!
(Other English phenomena you might want to capture are selectional preferences -- which are really more semantics issues than syntactic issues; or determiner/noun agreement.)
One solution to this problem is to augment our grammar with features. That is, basically do what linguists do and write "+sing" on the pre-terminal, but not split the grammar into bits. Instead, we need to come up with ways of propagating these features up the tree, and checking for disagreement. This process is known as "unification".
The idea of unification is that everything has a bunch of features with values. Values can be atomic (number=sing) or disjunctions (number={sing,plur}) or variables (number=A). Two values unify basically if they have a non-empty intersection (it's actually more complicated than this, but this is the basic idea). So sing and sing unify and produce sing. Similarly sing and {sing,plur} unify and produce sing. A and sing unify and produce sing with a note off on the side of the page that A=sing. sing and plur don't unify. Our grammar will now encode what unifications happen at each step (eg., when producing a S, you want to unify the number feature of the NP and VP; or when producing a VP, you want to unify the object NP with "case=accusative" and likewise for subject NPs).
Our grammar is now a set of context free productions and unification rules. One nice thing is that chart parsing basically still works, but our parse cells become more complicated because they have to remember the values of features. But at least our grammars don't blow up!
No comments:
Post a Comment