Skip to content

Commit d2f804f

Browse files
AngledLuffaclaude
andcommitted
Make an adverb of place the predicate of a copula in the UD converter
"He is here" came out with is as the head and here as advmod, and is as VERB. EWT and GUM make the adverb the head of the clause with be as cop, as for an adjective or noun predicate: there are 287 adverbs with a cop in EWT, mostly here, there, out, away, back, in, around and up. EWT tags be as VERB only in existential "there is". When a copula has no other predicate, make an ADVP or PRT headed by an adverb of place or direction the head of the VP or SQ, and the copula its cop: He is here here head, is cop Is the trouble over? over head, Is cop The answer is a click of the away head, is cop, click obl:npmod mouse away He is still there there head, still advmod Other adverbs after a copula are modifiers, so "the goal is simply to win" is unchanged. "ago" is left out of the list of adverbs, since in the PTB "than it was a year ago" is usually an ellipsis of the predicate. A purpose clause after the adverb, as in "I'm here to help" or "most are there to make their fans cheer", is advcl, as in EWT and GUM. In the PTB's market reports the adverb often comes with a measure phrase or a degree adverb inside the ADVP, as in "the Dow was down 80.53 points", "was off three pence" or "earnings were down slightly", where the ADVP's head rule picked the measure or the degree adverb. Make the adverb the head of such an ADVP, with the measure phrase as obl:npmod and a degree adverb such as slightly or sharply as advmod. "far" before another adverb is itself a degree adverb, so "falling far short of" and "far more" are unchanged, as are other pairs of adverbs, as in "came back early". A copula followed by a VP is an auxiliary, so it stays aux in "is further investigating the causes". The tests with "here" and "over" after a copula now have the adverb as the head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFFrVzJ9BaKtDx4UPVveJx
1 parent 9c04f38 commit d2f804f

3 files changed

Lines changed: 136 additions & 21 deletions

File tree

‎src/edu/stanford/nlp/trees/UniversalEnglishGrammaticalRelations.java‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ private UniversalEnglishGrammaticalRelations() {}
175175
"SINV < (VP=target < (/^(?:VB|AUX|POS)/=aux < " + beAuxiliaryRegex + ") $-- (VP < VBD|VBN))",
176176
"SINV < (VP=target < (VP < (/^(?:VB|AUX|POS)/=aux < " + beAuxiliaryRegex + ")) $-- (VP < VBD|VBN))");
177177

178+
/** An adverb which the head finder can make the predicate of a copula */
179+
private static final String COPULAR_ADVERB =
180+
"(/^(?:ADVP|PRT)/ < (/^(?:RB|RP|IN|NN|JJ)/ < " + UniversalSemanticHeadFinder.COPULAR_ADVERB_REGEX + "))";
181+
178182
/**
179183
* The "copula" grammatical relation. A copula is the relation between
180184
* the complement of a copular verb and the copular verb.
@@ -188,8 +192,8 @@ private UniversalEnglishGrammaticalRelations() {}
188192
public static final GrammaticalRelation COPULA =
189193
new GrammaticalRelation(Language.UniversalEnglish, "cop", "copula",
190194
AUX_MODIFIER, "VP|SQ|SINV|SBARQ", tregexCompiler,
191-
"VP < (/^(?:VB|AUX)/=target < " + copularWordRegex + " [ $++ (/^(?:ADJP|NP$|WHNP$|PP|UCP)/ !< (VBN|VBD !$++ /^N/)) | $++ (S <: (ADJP < JJ)) ] )",
192-
"SQ|SINV < (/^(?:VB|AUX)/=target < " + copularWordRegex + " [ $++ (ADJP !< VBN|VBD) | $++ (NP $++ NP) | $++ (S <: (ADJP < JJ)) ] )",
195+
"VP < (/^(?:VB|AUX)/=target < " + copularWordRegex + " [ $++ (/^(?:ADJP|NP$|WHNP$|PP|UCP)/ !< (VBN|VBD !$++ /^N/)) | $++ (S <: (ADJP < JJ)) | $++ " + COPULAR_ADVERB + " !$++ /^VP/ ] )",
196+
"SQ|SINV < (/^(?:VB|AUX)/=target < " + copularWordRegex + " [ $++ (ADJP !< VBN|VBD) | $++ (NP $++ NP) | $++ (S <: (ADJP < JJ)) | $++ (NP $++ " + COPULAR_ADVERB + ") !$++ /^VP/ ] )",
193197
// matches (what, is) in "what is that" after the SQ has been flattened out of the tree
194198
"SBARQ < (/^(?:VB|AUX)/=target < " + copularWordRegex + ") < (WHNP < WP)",
195199
// matches (old, is) in "How old is your cousin?" after the SQ has been flattened out of the tree
@@ -875,6 +879,9 @@ private UniversalEnglishGrammaticalRelations() {}
875879
// "VP < (/^S-ADV$/=target < (VP <, VBG|VBN) )",
876880
// they wrote asking the SEC to ...
877881
"VP < (S=target $-- NP < (VP < TO) !$-- (/^V/ < " + xcompVerbRegex + ") )",
882+
// a purpose clause after an adverb which is the predicate of a
883+
// copula, as in "I'm here to help"
884+
"VP < (/^(?:VB|AUX)/ < " + copularWordRegex + ") !< /^(?:VP|ADJP|NP|UCP|PP|WHADJP|WHNP)(?:-(?!TMP|ADV).*)?$/ < (" + COPULAR_ADVERB + " $++ (S=target < (VP <, TO) !< NP))",
878885
//"VP < (S=target < (VP < TO) !$-- (/^V/ < " + xcompNoObjVerbRegex + ") )",
879886

880887
"SBARQ < WHNP < (S=target < (VP <1 TO))",
@@ -1259,6 +1266,9 @@ private UniversalEnglishGrammaticalRelations() {}
12591266
new GrammaticalRelation(Language.UniversalEnglish, "obl:npmod", "noun phrase adverbial modifier",
12601267
MODIFIER, "VP|(?:WH)?(?:NP|ADJP|ADVP|PP|QP)(?:-TMP|-ADV)?", tregexCompiler,
12611268
"@ADVP|ADJP|WHADJP|WHADVP|PP|WHPP <# (JJ|JJR|IN|RB|RBR !< notwithstanding $- (@NP=target !< NNP|NNPS))",
1269+
// a measure phrase after a predicate adverb, as in "the Dow was
1270+
// down 80.53 points" or "was up 3/4"
1271+
"@ADVP <# (/^(?:RB|IN|RP)/ < " + UniversalSemanticHeadFinder.COPULAR_ADVERB_REGEX + " $+ (@NP|QP|CD=target !< NNP|NNPS))",
12621272
// one word nouns like "cost efficient", "ice-free"
12631273
"@ADJP < (NN=target $++ /^JJ/) !< CC|CONJP",
12641274
"@ADVP <# (/^(RB|ADVP)/ $++ @NP=target)", //up 20%, once a week, ...

‎src/edu/stanford/nlp/trees/UniversalSemanticHeadFinder.java‎

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,37 @@ protected int postOperationFix(int headIdx, Tree[] daughterTrees) {
302302

303303
static final TregexPattern noVerbOverTempTregex = TregexPattern.compile("/^VP/ < NP-TMP !< /^V/ !< NNP|NN|NNPS|NNS|NP|JJ|ADJP|S");
304304

305+
/**
306+
* Adverbs of place and direction which can be the predicate of a
307+
* copula, as in "he is here" or "the game is over". Other adverbs
308+
* after a copula, as in "the goal is simply to win", are modifiers.
309+
* "ago" is left out, since "it was a year ago" is most often an
310+
* ellipsis, as in "higher than it was a year ago".
311+
*/
312+
static final String COPULAR_ADVERB_REGEX = "/^(?i:here|there|everywhere|anywhere|somewhere|nowhere|elsewhere|" +
313+
"above|below|ahead|behind|around|away|back|close|near|nearby|down|up|uphill|downhill|upstairs|downstairs|" +
314+
"in|inside|indoors|out|outside|outdoors|off|on|over|through|together|home|abroad|overseas|aboard|along|apart|aside|" +
315+
"east|west|north|south|forward|far|farther|further|underway)$/";
316+
317+
/**
318+
* A predicate adverb followed by a measure phrase or a degree adverb,
319+
* as in "the Dow was down 80.53 points", "was off three pence" or
320+
* "earnings were down slightly", is the head of its ADVP, with the
321+
* measure phrase as obl:npmod and the degree adverb as advmod. "far"
322+
* before another adverb is itself a degree adverb, as in "far short"
323+
* or "far more", and other adverbs after the first one are left to the
324+
* usual head rule, as in "came back early" or "read it out loud".
325+
*/
326+
private static final String DEGREE_ADVERB_REGEX = "/^(?i:slightly|sharply|substantially|significantly|considerably|markedly|" +
327+
"modestly|marginally|fractionally|dramatically|steeply|strongly|moderately|somewhat|appreciably|noticeably|further)$/";
328+
329+
static final TregexPattern headOfADVPTregex =
330+
TregexPattern.compile("ADVP <, (/^(?:RB|IN|RP)/=head < " + COPULAR_ADVERB_REGEX + " [ $+ (/^(?:NP|QP)/ [ << CD | << /^(?i:little|bit|lot)$/ ]) | $+ CD | !< /^(?i:far|farther|further)$/ $+ (/^RBR?$/ < " + DEGREE_ADVERB_REGEX + ") ])");
331+
332+
/** An ADVP or PRT which is the predicate of a copula with no other predicate */
333+
static final TregexPattern copularAdverbTregex =
334+
TregexPattern.compile("/^(?:ADVP|PRT)/ < (/^(?:RB|RP|IN|NN|JJ)/ < " + COPULAR_ADVERB_REGEX + ")");
335+
305336
/**
306337
* We use this to avoid making a -TMP or -ADV the head of a copular phrase.
307338
* For example, in the sentence "It is hands down the best dessert ...",
@@ -342,6 +373,13 @@ protected Tree determineNonTrivialHead(Tree t, Tree parent) {
342373
// other key words as the head. For example, "and not" means
343374
// something completely different than "and". Furthermore,
344375
// downstream code was written assuming "not" would be the head...
376+
if (motherCat.equals("ADVP")) {
377+
TregexMatcher matcher = headOfADVPTregex.matcher(t);
378+
if (matcher.matchesAt(t)) {
379+
return matcher.getNode("head");
380+
}
381+
}
382+
345383
if (motherCat.equals("CONJP")) {
346384
for (TregexPattern pattern : headOfConjpTregex) {
347385
TregexMatcher matcher = pattern.matcher(t);
@@ -411,7 +449,6 @@ protected Tree determineNonTrivialHead(Tree t, Tree parent) {
411449
// looks for copular verbs
412450
if (hasVerbalAuxiliary(kids, copulars, false) && ! isExistential(t, parent) && ! isWHQ(t, parent)) {
413451
String[][] how;
414-
//TODO: also allow ADVP to be heads
415452
if (motherCat.equals("SQ")) {
416453
how = new String[][]{{"right", "VP", "ADJP", "NP", "UCP", "PP", "WHADJP", "WHNP"}};
417454
} else {
@@ -441,6 +478,17 @@ protected Tree determineNonTrivialHead(Tree t, Tree parent) {
441478
}
442479
}
443480

481+
// An adverb of place or direction is the predicate when there is
482+
// no other predicate, as in "he is here" or "is he here?"
483+
if (pti == null) {
484+
for (Tree kid : tmpFilteredChildren) {
485+
if (copularAdverbTregex.matcher(kid).matches()) {
486+
pti = kid;
487+
break;
488+
}
489+
}
490+
}
491+
444492
if (DEBUG) {
445493
log.info("Determined head (case 2) for " + t.value() + " is: " + pti);
446494
}

‎test/src/edu/stanford/nlp/trees/UniversalEnglishGrammaticalStructureTest.java‎

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -640,9 +640,66 @@ public static Collection<Object[]> testCases() {
640640
{TestType.BASIC,
641641
"(ROOT (S (NP (DT The) (NN man)) (VP (VBZ is) (ADVP (RB here))) (. .)))",
642642
"det(man-2, The-1)\n" +
643-
"nsubj(is-3, man-2)\n" +
643+
"nsubj(here-4, man-2)\n" +
644+
"cop(here-4, is-3)\n" +
645+
"root(ROOT-0, here-4)\n"},
646+
// a purpose clause after an adverb predicate is advcl
647+
{TestType.BASIC,
648+
"(ROOT (S (NP (PRP I)) (VP (VBP 'm) (ADVP (RB here)) (S (VP (TO to) (VP (VB help))))) (. .)))",
649+
"nsubj(here-3, I-1)\n" +
650+
"cop(here-3, 'm-2)\n" +
651+
"root(ROOT-0, here-3)\n" +
652+
"mark(help-5, to-4)\n" +
653+
"advcl(here-3, help-5)\n"},
654+
// other adverbs after a copula are modifiers
655+
{TestType.BASIC,
656+
"(ROOT (S (NP (DT The) (NN goal)) (VP (VBZ is) (ADVP (RB simply)) (S (VP (TO to) (VP (VB win))))) (. .)))",
657+
"det(goal-2, The-1)\n" +
658+
"nsubj(is-3, goal-2)\n" +
644659
"root(ROOT-0, is-3)\n" +
645-
"advmod(is-3, here-4)\n"},
660+
"advmod(is-3, simply-4)\n" +
661+
"mark(win-6, to-5)\n" +
662+
"xcomp(is-3, win-6)\n"},
663+
{TestType.BASIC,
664+
"(ROOT (S (NP (PRP He)) (VP (VBZ is) (ADVP (RB still)) (ADVP (RB there))) (. .)))",
665+
"nsubj(there-4, He-1)\n" +
666+
"cop(there-4, is-2)\n" +
667+
"advmod(there-4, still-3)\n" +
668+
"root(ROOT-0, there-4)\n"},
669+
// the adverb is the head of its ADVP, with the measure as obl:npmod
670+
{TestType.BASIC,
671+
"(ROOT (S (NP (DT The) (NNP Dow)) (VP (VBD was) (ADVP (IN down) (NP (CD 80.53) (NNS points)))) (. .)))",
672+
"det(Dow-2, The-1)\n" +
673+
"nsubj(down-4, Dow-2)\n" +
674+
"cop(down-4, was-3)\n" +
675+
"root(ROOT-0, down-4)\n" +
676+
"nummod(points-6, 80.53-5)\n" +
677+
"obl:npmod(down-4, points-6)\n"},
678+
{TestType.BASIC,
679+
"(ROOT (S (NP (NNS Earnings)) (VP (VBD were) (ADVP (RB down) (RB slightly))) (. .)))",
680+
"nsubj(down-3, Earnings-1)\n" +
681+
"cop(down-3, were-2)\n" +
682+
"root(ROOT-0, down-3)\n" +
683+
"advmod(down-3, slightly-4)\n"},
684+
// far before another adverb is a degree adverb, not the head
685+
{TestType.BASIC,
686+
"(ROOT (S (NP (PRP It)) (VP (VBD fell) (ADVP (RB far) (RB short) (PP (IN of) (NP (DT the) (NN goal))))) (. .)))",
687+
"nsubj(fell-2, It-1)\n" +
688+
"root(ROOT-0, fell-2)\n" +
689+
"advmod(short-4, far-3)\n" +
690+
"advmod(fell-2, short-4)\n" +
691+
"case(goal-7, of-5)\n" +
692+
"det(goal-7, the-6)\n" +
693+
"obl(short-4, goal-7)\n"},
694+
// a copula with a VP after it is an auxiliary, even after an adverb of place
695+
{TestType.BASIC,
696+
"(ROOT (S (NP (PRP It)) (VP (VBZ is) (ADVP (RBR further)) (VP (VBG investigating) (NP (DT the) (NNS causes)))) (. .)))",
697+
"nsubj(investigating-4, It-1)\n" +
698+
"aux(investigating-4, is-2)\n" +
699+
"advmod(investigating-4, further-3)\n" +
700+
"root(ROOT-0, investigating-4)\n" +
701+
"det(causes-6, the-5)\n" +
702+
"obj(investigating-4, causes-6)\n"},
646703
{TestType.BASIC,
647704
"(ROOT (SBARQ (WHPP (IN In) (WHNP (WDT which) (NN city))) (SQ (VBP do) (NP (PRP you)) (VP (VB live))) (. ?)))",
648705
"case(city-3, In-1)\n" +
@@ -670,19 +727,19 @@ public static Collection<Object[]> testCases() {
670727
"(ROOT (S (NP (PDT All) (DT the) (NNS boys)) (VP (VBP are) (ADVP (RB here))) (. .)))",
671728
"det:predet(boys-3, All-1)\n" +
672729
"det(boys-3, the-2)\n" +
673-
"nsubj(are-4, boys-3)\n" +
674-
"root(ROOT-0, are-4)\n" +
675-
"advmod(are-4, here-5)\n"},
730+
"nsubj(here-5, boys-3)\n" +
731+
"cop(here-5, are-4)\n" +
732+
"root(ROOT-0, here-5)\n"},
676733
{TestType.BASIC,
677734
"(ROOT (S (NP (CC Both) (NP (DT the) (NNS boys)) (CC and) (NP (DT the) (NNS girls))) (VP (VBP are) (ADVP (RB here))) (. .)))",
678735
"cc:preconj(boys-3, Both-1)\n" +
679736
"det(boys-3, the-2)\n" +
680-
"nsubj(are-7, boys-3)\n" +
737+
"nsubj(here-8, boys-3)\n" +
681738
"cc(girls-6, and-4)\n" +
682739
"det(girls-6, the-5)\n" +
683740
"conj(boys-3, girls-6)\n" +
684-
"root(ROOT-0, are-7)\n" +
685-
"advmod(are-7, here-8)\n"},
741+
"cop(here-8, are-7)\n" +
742+
"root(ROOT-0, here-8)\n"},
686743
{TestType.BASIC,
687744
"(ROOT (S (NP (PRP They)) (VP (VBD shut) (PRT (RP down)) (NP (DT the) (NN station))) (. .)))",
688745
"nsubj(shut-2, They-1)\n" +
@@ -880,10 +937,10 @@ public static Collection<Object[]> testCases() {
880937
"nmod(future-4, music-7)\n"},
881938
{TestType.BASIC,
882939
"( (SQ (VBZ Is) (NP-SBJ (DT the) (NN trouble)) (ADVP-PRD (RP over)) (. ?)))",
883-
"root(ROOT-0, Is-1)\n" +
940+
"cop(over-4, Is-1)\n" +
884941
"det(trouble-3, the-2)\n" +
885-
"nsubj(Is-1, trouble-3)\n" +
886-
"advmod(Is-1, over-4)\n"},
942+
"nsubj(over-4, trouble-3)\n" +
943+
"root(ROOT-0, over-4)\n"},
887944
{TestType.BASIC,
888945
"( (SBARQ (SBAR (IN Although) (S (NP (NNP Sue)) (VP (VBP is) (ADJP (JJ smart))))) (, ,) (WHNP (WP who)) (SQ (MD will) (VP (VB win))) (. ?)))",
889946
"mark(smart-4, Although-1)\n" +
@@ -2405,12 +2462,12 @@ public static Collection<Object[]> testCases() {
24052462
"(ROOT (S (NP (CC Both) (NP (DT the) (NNS boys)) (CC and) (NP (DT the) (NNS girls))) (VP (VBP are) (ADVP (RB here))) (. .)))",
24062463
"cc:preconj(boys-3, Both-1)\n" +
24072464
"det(boys-3, the-2)\n" +
2408-
"nsubj(are-7, boys-3)\n" +
2465+
"nsubj(here-8, boys-3)\n" +
24092466
"cc(girls-6, and-4)\n" +
24102467
"det(girls-6, the-5)\n" +
24112468
"conj:and(boys-3, girls-6)\n" +
2412-
"root(ROOT-0, are-7)\n" +
2413-
"advmod(are-7, here-8)\n"},
2469+
"cop(here-8, are-7)\n" +
2470+
"root(ROOT-0, here-8)\n"},
24142471
{TestType.COLLAPSED,
24152472
"( (S (NP (NNP Fred)) (VP (VBD flew) (PP (IN across) (CC or) (IN across) (NP (NNP Serbia)))) (. .)))",
24162473
"nsubj(flew-2, Fred-1)\n" +
@@ -2509,13 +2566,13 @@ public static Collection<Object[]> testCases() {
25092566
"(ROOT (S (NP (CC Both) (NP (DT the) (NNS boys)) (CC and) (NP (DT the) (NNS girls))) (VP (VBP are) (ADVP (RB here))) (. .)))",
25102567
"cc:preconj(boys-3, Both-1)\n" +
25112568
"det(boys-3, the-2)\n" +
2512-
"nsubj(are-7, boys-3)\n" +
2569+
"nsubj(here-8, boys-3)\n" +
25132570
"cc(girls-6, and-4)\n" +
25142571
"det(girls-6, the-5)\n" +
25152572
"conj:and(boys-3, girls-6)\n" +
2516-
"nsubj(are-7, girls-6)\n" +
2517-
"root(ROOT-0, are-7)\n" +
2518-
"advmod(are-7, here-8)\n"},
2573+
"nsubj(here-8, girls-6)\n" +
2574+
"cop(here-8, are-7)\n" +
2575+
"root(ROOT-0, here-8)\n"},
25192576
{TestType.CC_PROCESSED,
25202577
"(ROOT (S (NP-SBJ-38 (DT Neither) (NP (PRP they) ) (CC nor) (NP (NNP Mr.) (NNP McAlpine) )) (VP (MD could) (VP (VB be) (VP (VBN reached) (NP (-NONE- *-38) ) (PP-PRP (IN for) (NP (NN comment) ))))) (. .) ))",
25212578
"cc:preconj(they-2, Neither-1)\n" +

0 commit comments

Comments
 (0)