def add_semantics(self, frame, tree_name, anchor): """ Given a lemma and tree names, returns sem trees given by all matching verb classes and their frames. This is where all of the transformation logic currently lives for how to compute the semantics for combinations of wh/PRO/gerunds/relclauses. These essentially act as 'metagrammar rules' that can be applied successively. """ tree = self.grammar.get(tree_name) declarative_tree = self.grammar.get_declarative_tree(tree.tree_family) assert declarative_tree is not None sub_nouns = [n for n in declarative_tree.subst_nodes() if n.prefix() == "NP"] # Going to lexicalize for each frame tree = tree.copy() xtag_family = self.xtag_mapper.get_xtag_family(frame.primary, frame.secondary) if xtag_family is None or xtag_family != tree.tree_family: return None # Currently ignore trees with more than one anchor (like Tnx0VPnx1) if len(tree.anchor_positions()) > 1: return None # Can't align semantics if wrong number of nouns/subnodes if len(frame.np_var_order) != len(sub_nouns): return None # Lexicalize tree tree.lexicalize(anchor) # Align np vars and substitution nodes node_entity_dict = {} for np_var, subst_node in zip(frame.np_var_order, sub_nouns): node_entity_dict[subst_node.label()] = np_var tree = SemTree.convert(tree) # Map event semantics to root sem_dict = frame.sem_dict tree.semantics = sem_dict["Event"] tree.sem_var = tree.semantics.event() # Map argument semantics to subst nodes for node_label, np_var in node_entity_dict.items(): subst_node = tree.find(node_label) if subst_node is not None: #subst_node.semantics = sem_dict[np_var.name] tree.semantics = tree.semantics.concat(sem_dict[np_var.name]) subst_node.sem_var = np_var # Check for PRO trees # Unclear to me how to handle the semantics here # The "PRO" noun should be replaced by a noun in the tree that this # would be substituted into. Probably need to handle during subst. if "PRO" in tree.tree_name: nps = [n for n in tree.subtrees() if n.prefix() == "NP"] pro_np = [n for n in nps if n.has_pro()][0] control_np = [n for n in nps if n.has_control()][0] # Relative Clauses # In a relative clause, the root and and foot both represent the # variable that was extracted e.g. in "cat -> cat that chased the dog" # both "cat" and "cat that chased the dog" refer to the cat entity if tree.tree_name.startswith("betaN"): nps = [n for n in tree.subtrees() if n.prefix() == "NP" and n.label() not in ["NP_r", "NP_f", "NP_w"]] extracted = [n for n in nps if n.has_trace()][0] tree.find("NP_r").sem_var = node_entity_dict[extracted.label()] tree.find("NP_f").sem_var = node_entity_dict[extracted.label()] wh_var = VariableFactory.get_var() tree.find("NP_w").sem_var = wh_var return tree
def get_nonverb_semtree(self, tree_name, anchor): """ Returns the semantically annotated tree specified by tree_name anchored by anchor. Note: the semantic info should eventually live somewhere that is more flexible (json, xml, etc) """ tree = self.grammar.get(tree_name) tree.lexicalize(anchor) tree = SemTree.convert(tree) ''' if tree.initial(): v = VariableFactory.get_var(pre=anchor[0]) else: v = VariableFactory.get_var() ''' sem_map = { "alphaNXN": { "NP": (lambda a: "", "x1"), "N": (lambda a: "ISA(x1, %s)" % a.upper(), "x1"), }, "betaAn": { "N_r": (lambda a: "ISA(x1, %s)" % a.upper(), "x1"), "N_f": (lambda a: "", "x1"), }, "betaNn": { "N_r": (lambda a: "ISA(x1, %s)" % a.upper(), "x1"), "N_f": (lambda a: "", "x1"), }, ("betaDnx", "a"): { "NP_r": (lambda a: "EXISTS(x1)|", "x1"), "NP_f": (lambda a: "", "x1"), }, ("betaDnx", "an"): { "NP_r": (lambda a: "EXISTS(x1)|", "x1"), "NP_f": (lambda a: "", "x1"), }, ("betaDnx", "the"): { "NP_r": (lambda a: "EXISTS(x1)|", "x1"), "NP_f": (lambda a: "", "x1"), }, ("betaDnx", "one"): { "NP_r": (lambda a: "EXISTS(x1)|", "x1"), "NP_f": (lambda a: "", "x1"), }, "betaVvx": { "VP_r": (lambda a: "", "x1"), "VP": (lambda a: "", "x1"), }, "betanxPnx": { "NP_r": (lambda a: "%s(x1, y1)" % a, "x1"), "NP": (lambda a: "", "y1"), "NP_f": (lambda a: "", "x1"), }, "betavxPnx": { "VP_r": (lambda a: "%s(x1, y1)" % a, "x1"), "NP": (lambda a: "", "y1"), "VP": (lambda a: "", "x1"), }, "betasPUs": { "S_r": (lambda a: "", "AND(x1,y1)"), "S_f": (lambda a: "", "x1"), "S_1": (lambda a: "", "y1"), }, "betaARBvx": { "VP": (lambda a: "", "x1"), "VP_r": (lambda a: "%s(x1)" % a, "x1"), }, "betanxPUnx": { "NP_f": (lambda a: "", "x1"), "NP_r": (lambda a: "equal(x1,y1)", "x1"), "NP": (lambda a: "", "y1"), }, "betaPUs": { "S_r": (lambda a: "", "x1"), "S": (lambda a: "", "x1"), }, "betaVs": { "S_r": (lambda a: "", "x1"), "S": (lambda a: "", "x1"), }, "betanx1CONJnx2": { "NP": (lambda a: "", "AND(x1,y1)"), "NP_1": (lambda a: "", "x1"), "NP_2": (lambda a: "", "y1"), }, "betanxGnx": { "NP_r": (lambda a: "EXISTS(x1)|belongs_to(x1,y1)", "x1"), "NP_f": (lambda a: "", "x1"), "NP": (lambda a: "", "y1"), }, "betavxPs": { "VP_r": (lambda a: "", "x1"), "VP_f": (lambda a: "", "x1"), "PP": (lambda a: "%s(x1, y1)" % a, "y1"), "S": (lambda a: "", "y1"), }, "betas1CONJs2": { "S": (lambda a: "", "AND(x1,y1)"), "S_1": (lambda a: "", "x1"), "S_2": (lambda a: "", "y1"), }, "betaARBs": { "S": (lambda a: "", "x1"), "S_r": (lambda a: "%s(x1)" % a, "x1"), }, "betaCONJs": { "S_c": (lambda a: "", "x1"), "S_r": (lambda a: "", "x1"), }, } if (tree_name, anchor) in sem_map: key = (tree_name, anchor) elif tree_name in sem_map: key = tree_name else: print(tree_name, anchor) raise NotImplementedError node_dict = sem_map[key] for node_label, (sem_str, var_str) in node_dict.items(): sem_str = sem_str(anchor) node = tree.find(node_label) node.semantics = SemanticParser.parse(sem_str) var, rest = VariableParser.parse(var_str) node.sem_var = var return tree