def obl_modifier(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                 context: UD2OIAContext):
    """
    the adv before the verb should be processed by verb_phrase
    this converter should process the adv after the verb
    :param sentence:
    :return:
    """

    pattern = DependencyGraph()

    # TODO: it seems that in UD labeling, adv is used instead of adj for noun
    modified_node = DependencyGraphNode()
    modifier_node = DependencyGraphNode()

    pattern.add_nodes([modified_node, modifier_node])

    pattern.add_dependency(modified_node, modifier_node, r'\bobl')

    for match in dep_graph.match(pattern):

        dep_modified_node = match[modified_node]
        dep_modifier_node = match[modifier_node]

        if oia_graph.has_relation(dep_modified_node,
                                  dep_modifier_node,
                                  direct_link=False):
            continue

        oia_modified_node = oia_graph.add_words(dep_modified_node.position)
        oia_modifier_node = oia_graph.add_words(dep_modifier_node.position)

        oia_graph.add_mod(oia_modifier_node, oia_modified_node)
def acl_mod_verb(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                 context: UD2OIAContext):
    """
    this is called after adnominal_clause_mark, which means there is no mark
    :param dep_graph:
    :param oia_graph:
    :return:
    """

    pattern = DependencyGraph()

    noun_node = pattern.create_node(UPOS="NOUN|PRON|PROPN|ADJ|ADV|NUM")
    # ADJ is for the cases that "many/some" are abbrv of many X/some X, representing NOUN
    # ADV is for the case of "here" for "i am here thinking xxx"
    verb_node = pattern.create_node(UPOS="VERB|AUX")
    # aux is for can, have which ommits the true verb

    pattern.add_nodes([noun_node, verb_node])

    pattern.add_dependency(noun_node, verb_node, r'acl')

    for match in dep_graph.match(pattern):

        dep_noun_node = match[noun_node]
        dep_verb_node = match[verb_node]

        if context.is_processed(dep_noun_node, dep_verb_node):
            continue

        if oia_graph.has_relation(dep_noun_node,
                                  dep_verb_node,
                                  direct_link=False):
            continue

        oia_verb_node = oia_graph.add_words(dep_verb_node.position)
        oia_noun_node = oia_graph.add_words(dep_noun_node.position)

        dep = dep_graph.get_dependency(dep_noun_node, dep_verb_node)
        labels = [x for x in dep.rels if x.startswith("acl:")]

        pred = None

        if labels:
            assert len(labels) == 1
            label = labels[0]
            pred = label.split(":")[1]
            if pred == "relcl":
                pred = None

        # if pred:
        #     # there is no mark, but we add it because it may be because of not being shared in conjunction
        #
        #     oia_pred_node = oia_graph.add_aux(pred)
        #     oia_graph.add_argument(oia_pred_node, oia_noun_node, 1, mod=True)
        #     oia_graph.add_argument(oia_pred_node, oia_verb_node, 2)
        # else:

        oia_graph.add_mod(oia_verb_node, oia_noun_node)
Example #3
0
def adverbial_clause(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                     context: UD2OIAContext):
    """
    Adverbial Clause
##### run in order to catch it. advcl with mark (in order to) #####
##### he worked hard, replacing his feud. advcl without mark #####

    :param dep_graph:
    :param oia_graph:
    :return:
    """
    pattern = DependencyGraph()
    verb_node = pattern.create_node()
    modifier_node = pattern.create_node()

    pattern.add_dependency(verb_node, modifier_node, "advcl")

    for match in list(dep_graph.match(pattern)):

        dep_verb_node = match[verb_node]
        dep_modifier_node = match[modifier_node]

        if context.is_processed(dep_verb_node, dep_modifier_node):
            continue

        oia_verb_node = oia_graph.add_words(dep_verb_node.position)
        oia_modifier_node = oia_graph.add_words(dep_modifier_node.position)

        logger.debug("adverbial clause: verb={0}, modifier={1}".format(
            dep_verb_node.position, dep_modifier_node.position))

        if oia_graph.has_relation(oia_verb_node, oia_modifier_node):
            continue

        mark = list(
            dep_graph.children(dep_modifier_node,
                               filter=lambda n, rel: "mark" in rel))

        if mark:
            mark, rel = mark[0]
            pred_node = oia_graph.add_words(mark.position)
            if pred_node is None:
                continue

            if mark.LEMMA in CONJUNCTION_WORDS[language]:
                continue

            oia_graph.add_argument(pred_node, oia_verb_node, 1, mod=True)
            oia_graph.add_argument(pred_node, oia_modifier_node, 2)
        else:

            oia_graph.add_mod(oia_modifier_node, oia_verb_node)
def nmod_with_case(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                   context: UD2OIAContext):
    """

    #################### nmod:x ########################

    ##### the office of the chair #####
    ##### Istanbul in Turkey #####
    :param sentence:
    :return:
    """

    pattern = DependencyGraph()

    parent_node = DependencyGraphNode()
    child_node = DependencyGraphNode()
    case_node = DependencyGraphNode()

    pattern.add_nodes([parent_node, child_node, case_node])

    pattern.add_dependency(parent_node, child_node, r'\w*nmod\w*')
    pattern.add_dependency(child_node, case_node, r'\w*case\w*')

    for match in dep_graph.match(pattern):

        dep_parent_node = match[parent_node]
        dep_child_node = match[child_node]
        dep_case_node = match[case_node]

        rel = dep_graph.get_dependency(dep_parent_node, dep_child_node)

        # vs, lemma = versus
        # according, lemma = accord,
        # but rel always select the shorter one

        if oia_graph.has_relation(dep_parent_node, dep_child_node):
            continue

        if rel != "nmod:" + dep_case_node.LEMMA and rel != 'nmod:' + dep_case_node.FORM:
            pred_node = oia_graph.add_words(dep_case_node.position)
        else:
            pred_node = oia_graph.add_words(dep_case_node.position)

        arg1_node = oia_graph.add_words(dep_parent_node.position)
        arg2_node = oia_graph.add_words(dep_child_node.position)

        oia_graph.add_argument(pred_node, arg1_node, 1, mod=True)
        oia_graph.add_argument(pred_node, arg2_node, 2)
def oblique_without_prep(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                         context: UD2OIAContext):
    """

    :param dep_graph:
    :param oia_graph:
    :return:
    """

    # cut X by a knife
    pattern = DependencyGraph()
    verb_node = DependencyGraphNode(UPOS="VERB|NOUN|ADJ|PROPN|PRON")
    oblique_node = DependencyGraphNode()
    pattern.add_node(verb_node)
    pattern.add_node(oblique_node)
    pattern.add_dependency(verb_node, oblique_node, r'obl:tmod|obl:npmod|obl')

    for match in dep_graph.match(pattern):

        dep_verb_node = match[verb_node]
        dep_oblique_node = match[oblique_node]

        if oia_graph.has_relation(dep_verb_node,
                                  dep_oblique_node,
                                  direct_link=False):
            continue

        oblique_edge = dep_graph.get_dependency(dep_verb_node,
                                                dep_oblique_node)
        oblique_types = oblique_edge.values()

        if "tmod" in oblique_types:

            oia_pred_node = oia_graph.add_aux("TIME_IN")

            arg1_node = oia_graph.add_words(dep_verb_node.position)
            arg2_node = oia_graph.add_words(dep_oblique_node.position)

            oia_graph.add_argument(oia_pred_node, arg1_node, 1, mod=True)
            oia_graph.add_argument(oia_pred_node, arg2_node, 2)

        else:  # "npmod" in oblique_types and others

            oia_verb_node = oia_graph.add_words(dep_verb_node.position)
            obl_node = oia_graph.add_words(dep_oblique_node.position)

            oia_graph.add_mod(obl_node, oia_verb_node)
def nmod_without_case(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                      context: UD2OIAContext):
    """

    #################### nmod:x ########################

    :param sentence:
    :return:
    """

    pattern = DependencyGraph()

    center_node = pattern.create_node()
    modifier_node = pattern.create_node()

    pattern.add_dependency(center_node, modifier_node, r'\w*nmod\w*')

    for match in dep_graph.match(pattern):

        dep_center_node = match[center_node]
        dep_modifier_node = match[modifier_node]

        rels = dep_graph.get_dependency(dep_center_node, dep_modifier_node)

        if "nmod:poss" in rels and dep_center_node in set(
                dep_graph.offsprings(dep_modifier_node)):
            # whose in there
            continue

        if oia_graph.has_relation(dep_center_node,
                                  dep_modifier_node,
                                  direct_link=False):
            continue

        oia_center_node = oia_graph.add_words(dep_center_node.position)
        oia_modifier_node = oia_graph.add_words(dep_modifier_node.position)

        oia_graph.add_mod(oia_modifier_node, oia_center_node)
Example #7
0
def adv_relative_clause(dep_graph, oia_graph: OIAGraph,
                        context: UD2OIAContext):
    """

    #### When/Where Relative clause #####
    #### a time when US troops won/ a place where US troops won. acl:relcl with time/place
    :param sentence:
    :return:
    """

    pattern = DependencyGraph()
    modified_node = pattern.create_node()
    modifier_node = pattern.create_node()
    adv_rel_node = pattern.create_node()

    pattern.add_dependency(modified_node, modifier_node, r'acl:relcl\w*')
    pattern.add_dependency(modifier_node, adv_rel_node, r'advmod')

    for match in dep_graph.match(pattern):

        dep_modified_node = match[modified_node]
        dep_modifier_node = match[modifier_node]
        dep_rel_node = match[adv_rel_node]

        if not any(x in dep_rel_node.LEMMA
                   for x in {"when", "where", "how", "why", "what"}):
            continue

        oia_pred_node = oia_graph.add_words(dep_rel_node.position)
        oia_modified_node = oia_graph.add_words(dep_modified_node.position)
        oia_modifier_node = oia_graph.add_words(dep_modifier_node.position)

        if oia_graph.has_relation(oia_modifier_node, oia_modified_node):
            continue

        oia_graph.add_argument(oia_pred_node, oia_modified_node, 1, mod=True)
        oia_graph.add_argument(oia_pred_node, oia_modifier_node, 2)
def adv_verb_modifier(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                      context: UD2OIAContext):
    """
    the adv before the verb should be processed by verb_phrase
    this converter should process the adv after the verb
    verb1 in order to verb2
    :param sentence:
    :return:
    """

    pattern = DependencyGraph()

    # TODO: it seems that in UD labeling, adv is used instead of adj for noun
    verb_node = DependencyGraphNode(
        UPOS="VERB|NOUN|PROPN|AUX|PRON")  # aux is for be word
    adv_node = DependencyGraphNode(UPOS="ADV|X|NOUN|ADJ|VERB")

    pattern.add_nodes([verb_node, adv_node])

    pattern.add_dependency(verb_node, adv_node, r'advmod')

    for match in dep_graph.match(pattern):

        dep_verb_node = match[verb_node]
        dep_adv_node = match[adv_node]

        if context.is_processed(dep_verb_node, dep_adv_node):
            continue

        if oia_graph.has_relation(dep_verb_node, dep_adv_node):
            continue

        obl_children = [
            x for x, l in dep_graph.children(
                dep_adv_node, filter=lambda n, l: l.startswith("obl"))
        ]

        obl_node = None
        obl_has_case = False
        if len(obl_children) == 1:

            obl_node = obl_children[0]

            case_nodes = list(n for n, l in dep_graph.children(
                obl_node, filter=lambda n, l: "case" in l))

            if case_nodes:
                # if obl with case, let the oblique to process it
                obl_has_case = True

        mark_children = [
            x for x, l in dep_graph.children(
                dep_adv_node, filter=lambda n, l: l.startswith("mark"))
        ]

        oia_verb_node = oia_graph.add_words(dep_verb_node.position)
        oia_adv_node = oia_graph.add_words(dep_adv_node.position)

        if obl_node and not obl_has_case:
            # arg_nodes = list(dep_graph.offsprings(obl_node))
            # arg_nodes.sort(key=lambda x: x.LOC)
            # arg_words = [x.ID for x in arg_nodes]
            # head = obl_node.ID

            oia_arg_node = oia_graph.add_words(obl_node.position)

            oia_graph.add_argument(oia_adv_node, oia_verb_node, 1, mod=True)
            oia_graph.add_argument(oia_adv_node, oia_arg_node, 2)
        else:
            if mark_children:
                mark_node = mark_children[0]
                oia_pred_node = oia_graph.add_words(mark_node.position)

                oia_graph.add_argument(oia_pred_node,
                                       oia_verb_node,
                                       1,
                                       mod=True)
                oia_graph.add_argument(oia_pred_node, oia_adv_node, 2)

            else:
                oia_graph.add_mod(oia_adv_node, oia_verb_node)
def adv_ccomp(dep_graph: DependencyGraph, oia_graph: OIAGraph,
              context: UD2OIAContext):
    """

    :param dep_graph:
    :param oia_graph:
    :return:
    """

    pattern = DependencyGraph()

    # TODO: it seems that in UD labeling, adv is used instead of adj for noun
    # verb_node = pattern.create_node(UPOS="VERB|NOUN|PROPN")
    adv_node = pattern.create_node(UPOS="ADV|X|NOUN|PART")  # part is for "not"
    ccomp_node = pattern.create_node()

    # pattern.add_dependency(verb_node, adv_node, r'advmod')
    pattern.add_dependency(adv_node, ccomp_node, r"ccomp|xcomp")

    patterns = []
    for match in dep_graph.match(pattern):

        # dep_verb_node = match[verb_node]
        dep_adv_node = match[adv_node]
        dep_ccomp_node = match[ccomp_node]

        if oia_graph.has_relation(dep_adv_node, dep_ccomp_node):
            continue

        dep_case_nodes = [
            n for n, l in
            dep_graph.children(dep_ccomp_node,
                               filter=lambda n, l: "case" == l and dep_adv_node
                               .LOC < n.LOC < dep_ccomp_node.LOC)
        ]

        if dep_case_nodes:
            dep_case_nodes = continuous_component(dep_case_nodes,
                                                  dep_case_nodes[0])
            predicate_nodes = [dep_adv_node] + dep_case_nodes
            predicate_nodes.sort(key=lambda n: n.LOC)
        else:
            predicate_nodes = [dep_adv_node]

        dep_subj_nodes = [
            n for n, l in dep_graph.parents(dep_adv_node,
                                            filter=lambda n, l: "advmod" == l
                                            and n.UPOS in {"ADV", "X", "NOUN"})
        ]
        if len(dep_subj_nodes) > 1:
            raise Exception("Multiple subject")
        elif len(dep_subj_nodes) > 0:
            dep_subj_node = dep_subj_nodes[0]
        else:
            dep_subj_node = None

        patterns.append([dep_subj_node, predicate_nodes, dep_ccomp_node])

    for dep_subj_node, predicate_nodes, dep_ccomp_node in patterns:

        if len(predicate_nodes) > 1:

            new_pred_node = dep_graph.create_node(
                ID=" ".join([x.ID for x in predicate_nodes]),
                FORM=" ".join([x.FORM for x in predicate_nodes]),
                LEMMA=" ".join([x.LEMMA for x in predicate_nodes]),
                UPOS="ADV",
                LOC=predicate_nodes[0].LOC)

            new_pred_node.aux = True

            dep_graph.replace_nodes(predicate_nodes, new_pred_node)

            dep_graph.remove_dependency(dep_ccomp_node, new_pred_node)

        else:
            new_pred_node = predicate_nodes[0]

        oia_pred_node = oia_graph.add_words(new_pred_node.position)

        if dep_subj_node:
            oia_subj_node = oia_graph.add_words(dep_subj_node.position)
            oia_graph.add_argument(oia_pred_node, oia_subj_node, 1, mod=True)

        else:
            oia_ccomp_node = oia_graph.add_words(dep_ccomp_node.position)
            oia_graph.add_argument(oia_pred_node, oia_ccomp_node, 2)
Example #10
0
def object_relative_clause(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                           context: UD2OIAContext):
    """
    ##### Object-extracted/referred relative clause #####
    ##### the person that Andy knows #####
    :param sentence:
    :return:
    """

    pattern = DependencyGraph()
    verb_node = DependencyGraphNode()
    entity_node = DependencyGraphNode()
    subj_node = DependencyGraphNode()

    pattern.add_nodes([verb_node, entity_node, subj_node])

    pattern.add_dependency(verb_node, subj_node, r'\w*subj\w*')
    pattern.add_dependency(entity_node, verb_node, r'\w*acl:relcl\w*')

    for match in dep_graph.match(pattern):

        dep_entity_node = match[entity_node]
        dep_subj_node = match[subj_node]
        dep_verb_node = match[verb_node]

        if dep_subj_node.LEMMA in {"what", "who", "which", "that"}:
            continue

        logger.debug("we found a objective relative clause")
        logger.debug("entity: {0}".format(dep_entity_node))
        logger.debug("subject: {0}".format(dep_subj_node))
        logger.debug("verb: {0}".format(dep_verb_node))

        if context.is_processed(dep_entity_node, dep_verb_node):
            logger.debug("processed")
            continue

        context.processed(dep_verb_node, dep_subj_node)
        context.processed(dep_entity_node, dep_verb_node)

        oia_entity_node = oia_graph.add_words(dep_entity_node.position)
        oia_verb_node = oia_graph.add_words(dep_verb_node.position)
        oia_subj_node = oia_graph.add_words(dep_subj_node.position)

        if oia_graph.has_relation(oia_entity_node, oia_verb_node):
            logger.debug("has relation between entity and verb")
            continue

        oia_graph.add_argument(oia_verb_node, oia_subj_node, 1)

        def __valid_ref(n, l):
            return l == "ref" and dep_entity_node.LOC < n.LOC < dep_verb_node.LOC

        ref_nodes = list(n for n, l in dep_graph.children(dep_entity_node,
                                                          filter=__valid_ref))
        ref_nodes.sort(key=lambda x: x.LOC)

        if ref_nodes:
            ref_node = ref_nodes[-1]

            oia_ref_node = oia_graph.add_words(ref_node.position)

            oia_graph.add_ref(oia_entity_node, oia_ref_node)

            logger.debug("we are coping with ref between:")
            logger.debug(dep_verb_node)
            logger.debug(ref_node)

            ref_relation = dep_graph.get_dependency(dep_verb_node, ref_node)

            case_nodes = list(n for n, l in dep_graph.children(
                ref_node, filter=lambda n, l: "case" in l))
            case_nodes.sort(key=lambda x: x.LOC)

            if ref_relation:
                if case_nodes:
                    # with which xxxx, the with will become the root pred
                    case_node = case_nodes[-1]
                    oia_case_node = oia_graph.add_words(case_node.position)

                    oia_graph.add_argument(oia_case_node,
                                           oia_verb_node,
                                           1,
                                           mod=True)
                    oia_graph.add_argument(oia_case_node, oia_ref_node, 2)
                    oia_graph.add_mod(oia_verb_node, oia_entity_node)
                else:

                    if "obj" in ref_relation:
                        oia_graph.add_argument(oia_verb_node, oia_ref_node, 2)
                    elif ref_relation == "advmod":
                        oia_graph.add_mod(oia_ref_node, oia_verb_node)
                    else:
                        raise Exception(
                            "unknown relation: {}".format(ref_relation))
                    # oia_graph.add_argument(oia_verb_node, oia_entity_node, 2, mod=True)

        oia_graph.add_argument(oia_verb_node, oia_subj_node, 1)
        oia_graph.add_argument(oia_verb_node, oia_entity_node, 2, mod=True)

        rels = dep_graph.get_dependency(dep_entity_node, dep_verb_node)

        #if rels.endswith("obj"):
        for node, l in dep_graph.children(dep_verb_node):
            if l == "ccomp":
                oia_ccomp_node = oia_graph.add_words(node.position)
                oia_graph.add_argument(oia_verb_node, oia_ccomp_node, 3)
Example #11
0
def simple_clause(dep_graph: DependencyGraph, oia_graph: OIAGraph,
                  context: UD2OIAContext):
    """
    :TODO badcase  Attached is a new link
    :param dep_graph:
    :param oia_graph:
    :return:
    """
    # for node in dep_graph.nodes():
    #     print('node:',node)
    for pred_node in dep_graph.nodes(
            filter=lambda x: x.UPOS in {"VERB", "ADJ", "NOUN", "AUX", "ADV"}):
        # ADJ is for "With the demand so high,"
        # NOUN is for "X the best for Y"
        # AUX is for have in "I have a cat"
        # print('pred_node', pred_node)
        expl = None
        nsubj = None
        subj = None
        objs = []

        for child, rel in dep_graph.children(pred_node):
            # print('child node:', child)
            # print('child rel:', rel)
            if ('nsubj' in rel or "csubj" in rel):  # and ":xsubj" not in rel:
                nsubj = child
            elif rel.startswith('obj'):
                objs.append((child, 1))
            elif rel.startswith('iobj'):
                objs.append((child, 0))
            elif 'ccomp' in rel or "xcomp" in rel:  # and child.UPOS == "VERB":
                objs.append((child, 2))
            elif "expl" in rel:
                expl = child

        if nsubj:
            # if pred_node.LOC < nsubj.LOC:
            #     # TODO: in what situation?
            #     objs.insert(0, nsubj)
            # else:
            subj = nsubj

        if expl:  # It VERB subj that    # VERB subj it that
            if expl.LOC < pred_node.LOC:
                subj = expl
                objs.insert(0, (subj, -1))
            else:  # expl.LOC > pred_node.LOC:
                objs.insert(0, (expl, -1))

        if not subj and not objs:
            continue

        pred_node = oia_graph.add_words(pred_node.position)

        if not pred_node:
            continue

        arg_index = 1

        if subj is not None:
            if not oia_graph.has_relation(pred_node, subj):
                subj_node = oia_graph.add_words(subj.position)
                oia_graph.add_argument(pred_node, subj_node, arg_index)

        arg_index += 1

        objs.sort(key=lambda x: x[1])

        for obj, weight in objs:
            # print('obj:',obj)
            oia_obj_node = oia_graph.add_words(obj.position)

            # def __sconj_node(n):
            #    # that conj is ommited
            #    return (n.UPOS == "SCONJ" and n.LEMMA not in {"that"})

            def __adv_question_node(n):
                return ((n.UPOS == "ADV"
                         and n.LEMMA in {"when", "where", "how", "whether"}))

            #
            # def __pron_question_node(n):
            #     return (n.UPOS == "PRON" and n.LEMMA in {"what", "who", "which"})

            # def __interested_node2(n):
            #     # that conj is ommited
            #     return (n.UPOS == "PART")

            # sconj_nodes = [n for n, l in dep_graph.children(obj,
            #                      filter=lambda n,l: l == "mark" and __sconj_node(n))]
            adv_question_nodes = [
                n for n, l in dep_graph.children(
                    obj,
                    filter=lambda n, l: l == "mark" and __adv_question_node(n))
            ]

            # subj_question_nodes = [n for n, l in dep_graph.children(obj,
            #                        filter=lambda n,l: "subj" in l and __pron_question_node(n))]
            #
            # obj_question_nodes = [n for n, l in dep_graph.children(obj,
            #                         filter=lambda n,
            #                                       l: ("obj" in l or "comp") in l and __pron_question_node(
            #                             n))]
            # nodes_of_interests2 = [n for n, l in dep_graph.children(obj,
            #                      filter=lambda n,l: l == "advmod" and __interested_node2(n))]
            # print('nodes_of_interests:', nodes_of_interests)
            # if nodes_of_interests2:
            #     assert len(nodes_of_interests2) == 1
            #     interest_node = nodes_of_interests2[0]
            #     oia_interest_node = oia_graph.add_word_with_head(interest_node.LOC)
            #     oia_graph.add_argument(pred_node, oia_interest_node, arg_index)
            #     # oia_graph.add_function(oia_interest_node, oia_obj_node)
            #     arg_index += 1
            #     oia_graph.add_argument(oia_interest_node, oia_obj_node, arg_index)
            #     arg_index += 1

            if adv_question_nodes:
                assert len(adv_question_nodes) == 1
                interest_node = adv_question_nodes[0]
                oia_interest_node = oia_graph.add_words(interest_node.position)
                oia_graph.add_argument(pred_node, oia_interest_node, arg_index)
                oia_graph.add_function(oia_interest_node, oia_obj_node)

            else:
                if not oia_graph.has_relation(pred_node, obj):
                    oia_graph.add_argument(pred_node, oia_obj_node, arg_index)

            arg_index += 1

    pattern = DependencyGraph()
    parent_pred = pattern.create_node()
    child_pred = pattern.create_node()
    question_word = pattern.create_node(LEMMA=r'what|who')

    pattern.add_dependency(parent_pred, child_pred,
                           r'subj|nsubj|iobj|obj|xcomp|ccomp')
    pattern.add_dependency(parent_pred, question_word,
                           r'subj|nsubj|iobj|obj|xcomp|ccomp')
    pattern.add_dependency(child_pred, question_word,
                           r'subj|nsubj|iobj|obj|xcomp|ccomp')

    for match in dep_graph.match(pattern):
        dep_parent_pred, dep_child_pred, dep_question_word = [
            match[x] for x in [parent_pred, child_pred, question_word]
        ]

        oia_parent_pred, oia_child_pred, oia_question_word = [
            oia_graph.add_words(x.position)
            for x in [dep_parent_pred, dep_child_pred, dep_question_word]
        ]

        oia_question_word.is_func = True

        rel = oia_graph.get_edge(oia_child_pred, oia_question_word)

        oia_graph.remove_relation(oia_child_pred, oia_question_word)
        oia_graph.remove_relation(oia_parent_pred, oia_child_pred)

        oia_graph.add_relation(oia_question_word, oia_child_pred,
                               "mod_by:" + rel.label)
def oblique_with_prep(dep_graph, oia_graph: OIAGraph, context: UD2OIAContext):
    """

    :param dep_graph:
    :param oia_graph:
    :return:
    """

    # cut X by a knife
    pattern = DependencyGraph()
    verb_node = DependencyGraphNode(UPOS="VERB|ADJ|ADV|NOUN|X|PROPN|PRON")
    # adj is for "has more on "
    # adv is for "south of XXXX"
    prep_node = DependencyGraphNode(UPOS=r"PRON|ADP|VERB|SCONJ|ADJ")
    # verb is for including/according, adj is for "prior to"

    oblique_node = DependencyGraphNode()
    pattern.add_node(verb_node)
    pattern.add_node(prep_node)
    pattern.add_node(oblique_node)
    pattern.add_dependency(verb_node, oblique_node, r'\bobl')
    pattern.add_dependency(oblique_node, prep_node, r"case|mark")

    for match in dep_graph.match(pattern):

        dep_prep_node = match[prep_node]
        dep_verb_node = match[verb_node]
        dep_oblique_node = match[oblique_node]

        if oia_graph.has_relation(dep_verb_node, dep_oblique_node):
            continue

        oblique_edge = dep_graph.get_dependency(dep_verb_node,
                                                dep_oblique_node)
        oblique_cases = oblique_edge.values()

        # if dep_prop_node.LEMMA.lower() not in cases:
        #    continue

        prop_nodes = [
            x for x, l in dep_graph.children(
                dep_oblique_node,
                filter=lambda n, l: l == "case" or l == "mark")
        ]
        connected_case_nodes = continuous_component(prop_nodes, dep_prep_node)

        predicate = tuple([x.ID for x in connected_case_nodes])
        head_node = None
        for node in connected_case_nodes:
            if node.LEMMA.lower() in oblique_cases:
                head_node = node

        if not head_node:
            head_node = connected_case_nodes[-1]

        pred_node = oia_graph.add_words(head_node.position)
        arg1_node = oia_graph.add_words(dep_verb_node.position)
        arg2_node = oia_graph.add_words(dep_oblique_node.position)

        oia_graph.add_argument(pred_node, arg1_node, 1, mod=True)
        oia_graph.add_argument(pred_node, arg2_node, 2)