def dmrs_query(dmrs_iter, search_dmrs_graphlang, results_as_dict=False, results_per_dmrs=False): """ Queries DMRS graphs for an underspecified (sub)graph pattern and returns the values of named wildcards (of the form "?[Identifier]") as they are specified in the queried graph. :param dmrs_iter An iterator of DMRS graphs to query. :param search_dmrs_graphlang The query DMRS (sub)graph, given as a GraphLang string. :param results_as_dict True if a query result should be a dictionary, mapping identifiers to values. :param results_per_dmrs True if a (possibly empty) list per DMRS should be returned. :return Iterator of dicts containing the matching node ids. """ queries = {} search_dmrs = parse_graphlang(search_dmrs_graphlang, queries=queries) queries = [(key, queries[key]) for key in sorted(queries)] for dmrs in dmrs_iter: assert isinstance(dmrs, Dmrs), 'Object in dmrs_iter is not a Dmrs.' # perform an exact matching of search_dmrs against dmrs matchings = dmrs_exact_matching(search_dmrs, dmrs) if results_per_dmrs: results = [] for matching in matchings: # extract matched values if results_as_dict: result = {key: query(matching, dmrs) for key, query in queries} else: result = tuple(query(matching, dmrs) for _, query in queries) if results_per_dmrs: results.append(result) else: yield result if results_per_dmrs: yield results
def dmrs_mapping(dmrs, search_dmrs, replace_dmrs, copy_dmrs=True, iterative=True, all_matches=True, require_connected=True): """ Performs an exact DMRS (sub)graph matching of a (sub)graph against a containing graph. :param dmrs DMRS graph to map. :param search_dmrs DMRS subgraph to replace. :param replace_dmrs DMRS subgraph to replace with. :param copy_dmrs True if DMRS graph argument should be copied before being mapped. :param iterative True if all possible mappings should be performed iteratively to the same DMRS graph, instead of a separate copy per mapping (iterative=False requires copy_dmrs=True). :param all_matches True if all possible matches should be returned, instead of only the first (or None). :param require_connected True if mappings resulting in a disconnected DMRS graph should be ignored. :return Mapped DMRS graph (resp. a list of graphs in case of iterative=False and all_matches=True) """ assert copy_dmrs or iterative, 'Invalid argument combination.' # extract anchor node mapping between search_dmrs and replace_dmrs sub_mapping = {} for search_node in search_dmrs.iter_nodes(): if not isinstance(search_node, AnchorNode): continue for replace_node in replace_dmrs.iter_nodes(): if not isinstance(replace_node, AnchorNode) or replace_node.anchor != search_node.anchor: continue sub_mapping[search_node.nodeid] = replace_node.nodeid break else: assert False, 'Un-matched anchor node.' # set up variables according to settings if iterative: result_dmrs = copy.deepcopy(dmrs) if copy_dmrs else dmrs else: matchings = dmrs_exact_matching(search_dmrs, dmrs) if not iterative and all_matches: result = [] # continue while there is a match for search_dmrs while True: if iterative: matchings = dmrs_exact_matching(search_dmrs, result_dmrs) else: result_dmrs = copy.deepcopy(dmrs) if copy_dmrs else dmrs # return mapping(s) if there are no more matches left try: search_matching = next(matchings) except StopIteration: if not all_matches: return None elif iterative: return result_dmrs else: return result # remove nodes in the matched search_dmrs if they are no anchor nodes, otherwise perform mapping() # mapping() performs the mapping process (with whatever it involves) specific to this node type (e.g. fill underspecified values) replace_matching = {} for nodeid in search_matching: if isinstance(search_dmrs[nodeid], AnchorNode): replace_dmrs[sub_mapping[nodeid]].mapping(result_dmrs, search_matching[nodeid]) replace_matching[sub_mapping[nodeid]] = search_matching[nodeid] elif search_matching[nodeid] is not None: result_dmrs.remove_node(search_matching[nodeid]) # add copies of the non-anchor nodes for the matched replace_dmrs for nodeid in replace_dmrs: if nodeid in replace_matching: continue node = copy.deepcopy(replace_dmrs[nodeid]) node.nodeid = result_dmrs.free_nodeid() result_dmrs.add_node(node) replace_matching[nodeid] = node.nodeid # set top/index if specified in replace_dmrs if replace_dmrs.top is not None: result_dmrs.top = result_dmrs[replace_matching[replace_dmrs.top.nodeid]] if replace_dmrs.index is not None: result_dmrs.index = result_dmrs[replace_matching[replace_dmrs.index.nodeid]] # remove all links in the matched search_dmrs links = [] matching_values = set(search_matching.values()) for link in result_dmrs.iter_links(): if link.start in matching_values and link.end in matching_values: links.append(link) result_dmrs.remove_links(links) # add all links for the matched replace_dmrs for link in replace_dmrs.iter_links(): link = Link(replace_matching[link.start], replace_matching[link.end], link.rargname, link.post) result_dmrs.add_link(link) # add/return result if not require_connected or result_dmrs.is_connected(): if all_matches and not iterative: result.append(result_dmrs) elif not all_matches: return result_dmrs
def dmrs_mapping(dmrs, search_dmrs, replace_dmrs, equalities=(), hierarchy=None, copy_dmrs=True, iterative=True, all_matches=True, require_connected=True, max_matches=100): """ Performs an exact DMRS (sub)graph matching of a (sub)graph against a containing graph. :param dmrs DMRS graph to map. :param search_dmrs DMRS subgraph to replace. :param replace_dmrs DMRS subgraph to replace with. :param equalities :param hierarchy An optional predicate hierarchy. :param copy_dmrs True if DMRS graph argument should be copied before being mapped. :param iterative True if all possible mappings should be performed iteratively to the same DMRS graph, instead of a separate copy per mapping (iterative=False requires copy_dmrs=True). :param all_matches True if all possible matches should be returned, instead of only the first (or None). :param require_connected True if mappings resulting in a disconnected DMRS graph should be ignored. :param max_matches: Maximum number of matches. :return Mapped DMRS graph (resp. a list of graphs in case of iterative=False and all_matches=True) """ assert copy_dmrs or iterative, 'Invalid argument combination.' # extract anchor node mapping between search_dmrs and replace_dmrs sub_mapping = {} optional_nodeids = [] for search_node in search_dmrs.iter_nodes(): if not isinstance(search_node, AnchorNode): continue if not search_node.required: optional_nodeids.append(search_node.nodeid) for replace_node in replace_dmrs.iter_nodes(): if not isinstance(replace_node, AnchorNode) or all(anchor not in replace_node.anchors for anchor in search_node.anchors): continue assert search_node.nodeid not in sub_mapping, 'Node matches multiple nodes.' + str(search_node) sub_mapping[search_node.nodeid] = replace_node.nodeid if search_node.nodeid not in sub_mapping: assert not search_node.requires_target, 'Un-matched anchor node.' # set up variables according to settings if iterative: result_dmrs = copy.deepcopy(dmrs) if copy_dmrs else dmrs matchings = dmrs_exact_matching(search_dmrs, dmrs, optional_nodeids=optional_nodeids, equalities=equalities, hierarchy=hierarchy, match_top_index=True) else: matchings = dmrs_exact_matching(search_dmrs, dmrs, optional_nodeids=optional_nodeids, equalities=equalities, hierarchy=hierarchy, match_top_index=True) if not iterative and all_matches: result = [] # continue while there is a match for search_dmrs count = 0 for _ in range(max_matches): if iterative: pass # matchings = dmrs_exact_matching(search_dmrs, result_dmrs, optional_nodeids=optional_nodeids, equalities=equalities, hierarchy=hierarchy, match_top_index=True) else: result_dmrs = copy.deepcopy(dmrs) if copy_dmrs else dmrs # return mapping(s) if there are no more matches left try: search_matching = next(matchings) count += 1 except StopIteration: if not all_matches: if copy_dmrs: return None else: return False elif iterative: if not require_connected or result_dmrs.is_connected(): if copy_dmrs: return result_dmrs else: return count > 0 else: if copy_dmrs: return None else: return False else: return result # remove nodes in the matched search_dmrs if they are no anchor nodes, otherwise perform mapping() # mapping() performs the mapping process (with whatever it involves) specific to this node type (e.g. fill underspecified values) for nodeid in search_dmrs: search_node = search_dmrs[nodeid] if isinstance(search_node, AnchorNode): search_node.before_map(result_dmrs, search_matching[nodeid]) replace_matching = {} for nodeid in search_matching: if nodeid in sub_mapping: replace_dmrs[sub_mapping[nodeid]].map(result_dmrs, search_matching[nodeid], hierarchy=hierarchy) replace_dmrs[sub_mapping[nodeid]].after_map(result_dmrs, search_matching[nodeid]) replace_matching[sub_mapping[nodeid]] = search_matching[nodeid] elif search_matching[nodeid] is not None: result_dmrs.remove_node(search_matching[nodeid]) # add copies of the non-anchor nodes for the matched replace_dmrs for nodeid in replace_dmrs: if nodeid in replace_matching: continue node = copy.deepcopy(replace_dmrs[nodeid]) node.nodeid = result_dmrs.free_nodeid() result_dmrs.add_node(node) replace_matching[nodeid] = node.nodeid # set top/index if specified in replace_dmrs if replace_dmrs.top is not None: result_dmrs.top = result_dmrs[replace_matching[replace_dmrs.top.nodeid]] if replace_dmrs.index is not None: result_dmrs.index = result_dmrs[replace_matching[replace_dmrs.index.nodeid]] # remove all links in the matched search_dmrs links = [] matching_values = set(search_matching.values()) for link in result_dmrs.iter_links(): if link.start in matching_values and link.end in matching_values: links.append(link) result_dmrs.remove_links(links) # add all links for the matched replace_dmrs for link in replace_dmrs.iter_links(): link = Link(replace_matching[link.start], replace_matching[link.end], link.rargname, link.post) result_dmrs.add_link(link) # add/return result if not require_connected or result_dmrs.is_connected(): if all_matches and not iterative: result.append(result_dmrs) elif not all_matches: if copy_dmrs: return result_dmrs else: return True raise Exception('More than {} matches!'.format(max_matches))
from pydmrs.matching.exact_matching import dmrs_exact_matching import examples.examples_dmrs as examples if __name__ == '__main__': # "the" - "the dog chases the cat" assert len(list(dmrs_exact_matching(examples.the(), examples.the_dog_chases_the_cat()))) == 2 # "the cat" - "the dog chases the cat" assert len(list(dmrs_exact_matching(examples.the_cat(), examples.the_dog_chases_the_cat()))) == 1 # "dog cat" - "the dog chases the cat" assert len(list(dmrs_exact_matching(examples.dog_cat(), examples.the_dog_chases_the_cat()))) == 1 # "the dog chases the cat" - "the dog chases the cat" assert len(list(dmrs_exact_matching(examples.the_dog_chases_the_cat(), examples.the_dog_chases_the_cat()))) == 1 # "the cat chases the dog" - "the dog chases the cat" assert not len(list(dmrs_exact_matching(examples.the_cat_chases_the_dog(), examples.the_dog_chases_the_cat()))) # "the dog chases the cat" - "the dog chases the cat and the mouse" assert not len(list(dmrs_exact_matching(examples.the_dog_chases_the_cat(), examples.the_dog_chases_the_cat_and_the_mouse()))) # "the dog chases the cat" - "the dog chases the cat and the cat chases the mouse" assert len(list(dmrs_exact_matching(examples.the_dog_chases_the_cat(), examples.the_dog_chases_the_cat_and_the_cat_chases_the_mouse()))) == 1 # "the cat" - "the dog chases the cat and the cat chases the mouse" assert len(list(dmrs_exact_matching(examples.the_cat(), examples.the_dog_chases_the_cat_and_the_cat_chases_the_mouse()))) == 2 # "dog cat" - "the dog chases the cat and the cat chases the mouse"
from pydmrs.matching.exact_matching import dmrs_exact_matching import examples.examples_dmrs as examples if __name__ == '__main__': # "the" - "the dog chases the cat" assert len( list( dmrs_exact_matching(examples.the(), examples.the_dog_chases_the_cat()))) == 2 # "the cat" - "the dog chases the cat" assert len( list( dmrs_exact_matching(examples.the_cat(), examples.the_dog_chases_the_cat()))) == 1 # "dog cat" - "the dog chases the cat" assert len( list( dmrs_exact_matching(examples.dog_cat(), examples.the_dog_chases_the_cat()))) == 1 # "the dog chases the cat" - "the dog chases the cat" assert len( list( dmrs_exact_matching(examples.the_dog_chases_the_cat(), examples.the_dog_chases_the_cat()))) == 1 # "the cat chases the dog" - "the dog chases the cat" assert not len(