-
Notifications
You must be signed in to change notification settings - Fork 0
/
trees.py
executable file
·231 lines (192 loc) · 7.29 KB
/
trees.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/usr/bin/env python
#
# trees.py is a set collection of functions that work on parse trees; that is,
# nltk.tree.Tree instances
#
import heads as hd
import wordnet as wn
import nltk.tree as nltr
import pdb
from nltk.corpus import wordnet as nlwn
def leaves_string(subtree):
return ' '.join(subtree.leaves())
def tree_pos(tree):
pos_list = []
for subtree in tree.subtrees():
if not isinstance(subtree[0], nltr.Tree):
pos_list.append(subtree)
return pos_list
# return a list of NP or NN/NNS/NNP/NNPS subtrees such that there are no
# embedded NP subtrees in any tree
def smallest_np_subtrees(subtree):
trees = []
for tree in subtree.subtrees():
if tree.node in ['NP', 'NP-COORD']:
can_add = True
for t in tree[0:]:
if find_first_constituent(t, 'NP'):
can_add = False
if can_add:
trees.append(tree)
return trees
def modifiers_of_head_noun(scope, constituent, num=0):
try:
return leaves_string(hd.head_np_of_np(scope[constituent][num]['TREE'])).rpartition(scope[constituent][num]['HEAD_LIST'][0]['HEAD'])[0].split()
except:
return []
def concat_tree_list_to_string(tree_list, sep = ' '):
tree_string = ''
for tree in tree_list:
tree_string += leaves_string(tree) + sep
return tree_string.strip()
def tree_startswith_labels(tree, labels):
# if labels = [ [label1, label2], [label3] ], then returns True if the
# first child of tree is labeled label1 or label2, and the second child is
# named label3. In general, labels is a list of lists of labels.
if len(tree) < len(labels):
return False
for idx in xrange(len(labels)):
if tree[idx].node not in labels[idx]:
return False
return True
def tree_endswith_labels(tree, labels):
# if labels = [ [label1, label2], [label3] ], then returns True if the last
# child of tree is labeled label3, and the second to last child is named
# label1 or label2. In general, labels is a list of lists of labels.
if len(tree) < len(labels):
return False
for idx in xrange(len(labels)):
if tree[-idx-1].node not in labels[-idx-1]:
return False
return True
def tree_endswith_labels_deep(tree, labels):
# like tree_endswith_labels, but looks at the deepest rightmost labels.
# For example, given the tree (NP (NP (DT The) (NN Man)) (PP (IN with) (NP
# (NN telescope)))). The children of the main NP are labeled NP and PP,
# which the shallow versions of the similarly named functions look at. But
# this function looks at, from left-to-right: NP NP DT NN PP IN NP NN
subtree_list = [subtree for subtree in tree.subtrees()]
if len(subtree_list) < len(labels):
return False
for idx in xrange(len(labels)):
if subtree_list[-idx-1].node not in labels[-idx-1]:
return False
return True
def pp_list_of_np(np_subtree):
# returns the children PP of an NP
pp_list = []
if np_subtree and np_subtree.node == "NP":
for child in np_subtree:
if child.node == "PP":
pp_list.append(child)
return pp_list
def find_first_constituent(tree, labels):
# returns the first constituent with a label from the list label, while
# doing a deep traversal
for t in tree.subtrees():
if t.node in labels:
return t
def prep_of_pp(pp_subtree):
# returns the prepostion of a PP
# TODO: does this handle multiple-word prepositions?
if pp_subtree.node == "PP":
if len(pp_subtree) > 0 and pp_subtree[0].node in ["IN", "TO"]:
return pp_subtree[0]
def lists_have_common(treelist1, treelist2):
# returns True if the two lists share a common element
for treej in treelist1:
for treep in treelist2:
if treej and treej == treep:
return treej
def find_pre_target_trees(target, tree):
pretarget_trees = []
for child in tree.subtrees():
if not has_subtree(child, target):
# make sure we have not already looked at a parent of child
have_looked = False
for looked in pretarget_trees:
if has_subtree(looked, child):
have_looked = True
if not have_looked:
pretarget_trees.append(child)
if child == target:
break
return pretarget_trees
def modifiers_of_head_noun_of_pp_constituent(scope, constituent, num=0):
return leaves_string(hd.head_np_of_pp(scope[constituent][num]['TREE'])).rpartition(scope[constituent][num]['HEAD_LIST'][0]['HEAD'])[0].split()
def constituent_has_head_stems(scope, constituent, num=0):
return len(scope[constituent]) > num and len(scope[constituent][num]['HEAD_LIST']) > 0 and len(scope[constituent][num]['HEAD_LIST'][0]['STEMS']) > 0
# given a (PP-OF-XXXX, tree), find scope[XXXX][y]['TREE'] == tree and return (y, XXXX)
def np_constituent_to_which_pp_attaches(scope, pp_key):
constituent = pp_key[0].split('-')[-1]
tree = pp_key[1]
for num, sc in enumerate(scope[constituent]):
if sc['TREE'] == tree:
return (num, constituent)
def find_post_target_trees(target, tree):
posttarget_trees = []
found_target = False
for child in tree.subtrees():
if child == target:
found_target = True
posttarget_trees.append(child)
continue
if not found_target:
continue
have_looked = False
for looked in posttarget_trees:
if has_subtree(looked, child):
have_looked = True
if not have_looked:
posttarget_trees.append(child)
if len(posttarget_trees) > 0:
return posttarget_trees[1:]
return posttarget_trees
#def find_post_target_trees(target, tree):
# posttarget_trees = []
# subtree_list = [t for t in tree.subtrees()]
# for child in reversed(subtree_list):
# if not has_subtree(target, child):
#
# # make sure we have not already looked at a parent of child
# have_looked = False
# for looked in posttarget_trees:
# if has_subtree(child, looked):
# have_looked = True
#
# if not have_looked:
# posttarget_trees.append(child)
#
# if child == target:
# break
#
# posttarget_trees.reverse()
# return posttarget_trees
def tree_split(tree, labels):
# constituents is returned and will have the form [ [tree1, tree2],
# [tree3], .. ] where the treei's are children of tree, and they are placed
# into new sublists whenever a constituent with label in labels appears
# between them.
constituents = []
consti = []
for child in tree:
if child.node in labels:
if len(consti) > 0:
constituents.append(consti)
consti = []
else:
consti.append(child)
if len(consti) > 0:
constituents.append(consti)
return constituents
def has_subtree(tree, subtree):
for t in tree.subtrees():
if t == subtree:
return True
return False
def tree_endswith_wordnet_noun(subtree):
for candidate in hd.head_np_candidate_heads(subtree):
stemmed = wn.morphy(candidate['HEAD'].lower())
if stemmed:
return True
return False