Beispiel #1
0
def _check_rule_typing(hierarchy, rule_id, graph_id, lhs_mapping, rhs_mapping):
    all_paths = dict(nx.all_pairs_shortest_path(hierarchy))

    paths_from_target = {}
    for s in hierarchy.nodes():
        if s == graph_id:
            for key in all_paths[graph_id].keys():
                paths_from_target[key] = all_paths[graph_id][key]

    for t in paths_from_target.keys():
        if t != graph_id:
            new_lhs_h = compose(
                lhs_mapping,
                hierarchy.compose_path_typing(paths_from_target[t]))
            new_rhs_h = compose(
                rhs_mapping,
                hierarchy.compose_path_typing(paths_from_target[t]))
            try:
                # find homomorphisms from s to t via other paths
                s_t_paths = nx.all_shortest_paths(hierarchy, rule_id, t)
                for path in s_t_paths:
                    lhs_h, rhs_h = hierarchy.compose_path_typing(path)
                    if lhs_h != new_lhs_h:
                        raise HierarchyError(
                            "Invalid lhs typing: homomorphism does not "
                            "commute with an existing "
                            "path from '%s' to '%s'!" % (s, t))
                    if rhs_h != new_rhs_h:
                        raise HierarchyError(
                            "Invalid rhs typing: homomorphism does not "
                            "commute with an existing " +
                            "path from '%s' to '%s'!" % (s, t))
            except (nx.NetworkXNoPath):
                pass
    return
Beispiel #2
0
def _check_rule_typing(hierarchy, rule_id, graph_id, lhs_mapping, rhs_mapping):
    all_paths = dict(nx.all_pairs_shortest_path(hierarchy))

    paths_from_target = {}
    for s in hierarchy.nodes():
        if s == graph_id:
            for key in all_paths[graph_id].keys():
                paths_from_target[key] = all_paths[graph_id][key]

    for t in paths_from_target.keys():
        if t != graph_id:
            new_lhs_h = compose(
                lhs_mapping,
                hierarchy.compose_path_typing(paths_from_target[t]))
            new_rhs_h = compose(
                rhs_mapping,
                hierarchy.compose_path_typing(paths_from_target[t]))
            try:
                # find homomorphisms from s to t via other paths
                s_t_paths = nx.all_shortest_paths(hierarchy, rule_id, t)
                for path in s_t_paths:
                    lhs_h, rhs_h = hierarchy.compose_path_typing(path)
                    if lhs_h != new_lhs_h:
                        raise HierarchyError(
                            "Invalid lhs typing: homomorphism does not "
                            "commute with an existing "
                            "path from '%s' to '%s'!" % (s, t)
                        )
                    if rhs_h != new_rhs_h:
                        raise HierarchyError(
                            "Invalid rhs typing: homomorphism does not "
                            "commute with an existing " +
                            "path from '%s' to '%s'!" % (s, t)
                        )
            except(nx.NetworkXNoPath):
                pass
    return
Beispiel #3
0
def _refine_rule_hierarchy(hierarchy, rule_hierarchy, lhs_instances):
    new_lhs_instances = {}

    new_rules = {}
    new_rule_homomorphisms = {}

    for graph, rule in rule_hierarchy["rules"].items():
        # refine rule
        new_lhs_instance = rule.refine(hierarchy.get_graph(graph),
                                       lhs_instances[graph])
        new_lhs_instances[graph] = new_lhs_instance

    # Update rule homomorphisms
    for (source,
         target), (lhs_h, p_h,
                   rhs_h) in rule_hierarchy["rule_homomorphisms"].items():
        typing = hierarchy.get_typing(source, target)
        source_rule = rule_hierarchy["rules"][source]
        target_rule = rule_hierarchy["rules"][target]
        for node in source_rule.lhs.nodes():
            if node not in lhs_h.keys():
                source_node = new_lhs_instances[source][node]
                target_node = typing[source_node]
                target_lhs_node = keys_by_value(new_lhs_instances[target],
                                                target_node)[0]
                lhs_h[node] = target_lhs_node

                if node in source_rule.p_lhs.values():
                    source_p_node = keys_by_value(source_rule.p_lhs, node)[0]
                    target_p_node = keys_by_value(target_rule.p_lhs, node)[0]
                    p_h[source_p_node] = target_p_node

                    source_rhs_node = source_rule.p_rhs[source_p_node]
                    target_rhs_node = target_rule.p_rhs[target_p_node]
                    rhs_h[source_rhs_node] = target_rhs_node

    if len(rule_hierarchy["rules"]) == 0:
        for graph in hierarchy.graphs():
            rule_hierarchy["rules"][graph] = Rule.identity_rule()
            new_lhs_instances[graph] = dict()
        for (s, t) in hierarchy.typings():
            rule_hierarchy["rule_homomorphisms"][(s, t)] = (dict(), dict(),
                                                            dict())
    else:
        for graph, rule in rule_hierarchy["rules"].items():
            # add identity rules where needed
            # to preserve the info on p/rhs_typing
            # add ancestors that are not included in rule hierarchy
            for ancestor, typing in hierarchy.get_ancestors(graph).items():
                if ancestor not in rule_hierarchy["rules"] and\
                   ancestor not in new_rules:
                    # Find a typing of ancestor by the graph
                    l_pred, l_pred_pred, l_pred_l_graph = pullback(
                        hierarchy.get_graph(ancestor), rule.lhs,
                        hierarchy.get_graph(graph), typing,
                        new_lhs_instances[graph])
                    new_rules[ancestor] = Rule(p=l_pred, lhs=l_pred)
                    new_lhs_instances[ancestor] = l_pred_pred
                    r_pred_r_graph = {
                        v: rule.p_rhs[k]
                        for k, v in l_pred_l_graph.items()
                    }
                    for successor in hierarchy.successors(ancestor):
                        if successor in rule_hierarchy["rules"]:
                            if successor == graph:
                                new_rule_homomorphisms[(ancestor, graph)] = (
                                    l_pred_l_graph, l_pred_l_graph,
                                    r_pred_r_graph)
                            else:
                                path = hierarchy.shortest_path(
                                    graph, successor)
                                lhs_h, p_h, rhs_h = rule_hierarchy[
                                    "rule_homomorphisms"][(path[0], path[1])]
                                for i in range(2, len(path)):
                                    new_lhs_h, new_p_h, new_rhs_h = rule_hierarchy[
                                        "rule_homomorphisms"][(path[i - 1],
                                                               path[i])]
                                    lhs_h = compose(lhs_h, new_lhs_h)
                                    p_h = compose(p_h, new_p_h)
                                    rhs_h = compose(rhs_h, new_rhs_h)

                                new_rule_homomorphisms[(
                                    ancestor,
                                    successor)] = (compose(
                                        l_pred_l_graph,
                                        lhs_h), compose(l_pred_l_graph, p_h),
                                                   compose(
                                                       r_pred_r_graph, rhs_h))
                        if successor in new_rules:
                            lhs_h = {
                                k: keys_by_value(
                                    new_lhs_instances[successor],
                                    hierarchy.get_typing(ancestor,
                                                         successor)[v])[0]
                                for k, v in
                                new_lhs_instances[ancestor].items()
                            }
                            new_rule_homomorphisms[(ancestor,
                                                    successor)] = (lhs_h,
                                                                   lhs_h,
                                                                   lhs_h)
                    for predecessor in hierarchy.predecessors(ancestor):
                        if predecessor in rule_hierarchy["rules"] or\
                           predecessor in new_rules:
                            lhs_h = {
                                k: keys_by_value(
                                    new_lhs_instances[ancestor],
                                    hierarchy.get_typing(
                                        predecessor, ancestor)[v])[0]
                                for k, v in
                                new_lhs_instances[predecessor].items()
                            }
                            new_rule_homomorphisms[(predecessor,
                                                    ancestor)] = (lhs_h, lhs_h,
                                                                  lhs_h)

            for descendant, typing in hierarchy.get_descendants(graph).items():
                if descendant not in rule_hierarchy["rules"] and\
                   descendant not in new_rules:
                    l_suc, l_graph_l_suc, l_suc_suc = image_factorization(
                        rule.lhs, hierarchy.get_graph(descendant),
                        compose(new_lhs_instances[graph], typing))
                    new_rules[descendant] = Rule(p=l_suc, lhs=l_suc)
                    new_lhs_instances[descendant] = l_suc_suc
                    p_graph_p_suc = {
                        k: l_graph_l_suc[v]
                        for k, v in rule.p_lhs.items()
                    }
                    for predecessor in hierarchy.predecessors(descendant):
                        if predecessor in rule_hierarchy["rules"]:
                            if predecessor == graph:
                                new_rule_homomorphisms[(
                                    predecessor, descendant)] = (l_graph_l_suc,
                                                                 p_graph_p_suc,
                                                                 p_graph_p_suc)
                            else:
                                path = hierarchy.shortest_path(
                                    predecessor, graph)
                                lhs_h, p_h, rhs_h = rule_hierarchy[
                                    "rule_homomorphisms"][(path[0], path[1])]
                                for i in range(2, len(path)):
                                    new_lhs_h, new_p_h, new_rhs_h = rule_hierarchy[
                                        "rule_homomorphisms"][(path[i - 1],
                                                               path[i])]
                                    lhs_h = compose(lhs_h, new_lhs_h)
                                    p_h = compose(p_h, new_p_h)
                                    rhs_h = compose(rhs_h, new_rhs_h)
                                new_rule_homomorphisms[(
                                    predecessor,
                                    descendant)] = (compose(
                                        lhs_h, l_graph_l_suc),
                                                    compose(
                                                        p_h, p_graph_p_suc),
                                                    compose(
                                                        rhs_h, p_graph_p_suc))
                        if predecessor in new_rules:
                            lhs_h = {
                                k: keys_by_value(
                                    new_lhs_instances[descendant],
                                    hierarchy.get_typing(
                                        predecessor, descendant)[v])[0]
                                for k, v in
                                new_lhs_instances[predecessor].items()
                            }
                            new_rule_homomorphisms[(predecessor,
                                                    descendant)] = (lhs_h,
                                                                    lhs_h,
                                                                    lhs_h)

                    for successor in hierarchy.successors(descendant):
                        if successor in rule_hierarchy["rules"] or\
                           successor in new_rules:
                            lhs_h = {
                                k: keys_by_value(
                                    new_lhs_instances[successor],
                                    hierarchy.get_typing(
                                        descendant, successor)[v])[0]
                                for k, v in
                                new_lhs_instances[descendant].items()
                            }
                            new_rule_homomorphisms[(descendant,
                                                    successor)] = (lhs_h,
                                                                   lhs_h,
                                                                   lhs_h)

    rule_hierarchy["rules"].update(new_rules)
    rule_hierarchy["rule_homomorphisms"].update(new_rule_homomorphisms)

    return new_lhs_instances
Beispiel #4
0
def get_rule_hierarchy(hierarchy, origin_id, rule, instance, liftings,
                       projections):
    """Get a hierarchy of rules."""
    rule_hierarchy = {"rules": {}, "rule_homomorphisms": {}}

    rule_hierarchy["rules"][origin_id] = rule
    instances = {origin_id: instance}

    for graph, data in liftings.items():
        rule_hierarchy["rules"][graph] = data["rule"]
        instances[graph] = data["instance"]
        for successor in hierarchy.successors(graph):
            old_typing = hierarchy.get_typing(graph, successor)
            if successor == origin_id:
                graph_lhs_successor_lhs = data["l_g_l"]
                graph_p_successor_p = data["p_g_p"]
                rule_hierarchy["rule_homomorphisms"][(graph, successor)] = (
                    graph_lhs_successor_lhs, graph_p_successor_p,
                    graph_p_successor_p)
            else:
                l_graph_successor = compose(liftings[graph]["instance"],
                                            old_typing)
                # already lifted to the successor
                if successor in liftings:
                    p_graph_successor = compose(liftings[graph]["rule"].p_lhs,
                                                l_graph_successor)
                    p_successor_successor = compose(
                        liftings[successor]["rule"].p_lhs,
                        liftings[successor]["instance"])
                    graph_lhs_successor_lhs = {}
                    for k, v in l_graph_successor.items():
                        l_node_g = liftings[graph]["l_g_l"][k]
                        for vv in keys_by_value(
                                liftings[successor]["instance"], v):
                            l_node_s = liftings[successor]["l_g_l"][vv]
                            if (l_node_s == l_node_g):
                                graph_lhs_successor_lhs[k] = vv
                                break

                    graph_p_successor_p = {}
                    for k, v in p_graph_successor.items():
                        p_node_g = liftings[graph]["p_g_p"][k]
                        for vv in keys_by_value(p_successor_successor, v):
                            p_node_s = liftings[successor]["p_g_p"][vv]
                            if (p_node_s == p_node_g):
                                graph_p_successor_p[p_node_g] = p_node_s
                                break

                    rule_hierarchy["rule_homomorphisms"][(
                        graph, successor)] = (graph_lhs_successor_lhs,
                                              graph_p_successor_p,
                                              graph_p_successor_p)
                elif successor in projections:
                    rule_hierarchy["rule_homomorphisms"][(
                        graph,
                        successor)] = (compose(
                            liftings[graph]["l_g_l"],
                            projections[successor]["l_l_t"]),
                                       compose(
                                           liftings[graph]["p_g_p"],
                                           projections[successor]["p_p_t"]),
                                       compose(
                                           compose(liftings[graph]["p_g_p"],
                                                   rule.p_rhs),
                                           projections[successor]["r_r_t"]))
                # didn't touch the successor or projected to it
                else:
                    pass

    for graph, data in projections.items():
        rule_hierarchy["rules"][graph] = data["rule"]
        instances[graph] = data["instance"]
        for predecessor in hierarchy.predecessors(graph):
            old_typing = hierarchy.get_typing(predecessor, graph)
            if predecessor == origin_id:
                predecessor_l_graph_l = data["l_l_t"]
                predecessor_p_graph_p = data["p_p_t"]
                predecessor_rhs_graph_rhs = data["r_r_t"]
                rule_hierarchy["rule_homomorphisms"][(predecessor, graph)] = (
                    predecessor_l_graph_l, predecessor_p_graph_p,
                    predecessor_rhs_graph_rhs)
            else:
                # already projected to the predecessor
                if predecessor in projections:
                    l_pred_graph = compose(
                        projections[predecessor]["instance"], old_typing)
                    predecessor_l_graph_l = {}
                    for k, v in projections[predecessor]["instance"].items():
                        predecessor_l_graph_l[k] = keys_by_value(
                            projections[graph]["instance"], l_pred_graph[k])[0]
                    predecessor_rhs_graph_rhs = {}
                    for r_node, r_pred_node in projections[predecessor][
                            "r_r_t"].items():
                        p_pred_nodes = keys_by_value(
                            projections[predecessor]["rule"].p_rhs,
                            r_pred_node)
                        for v in p_pred_nodes:
                            p_graph_node = predecessor_l_graph_l[v]
                            r_graph_node = projections[graph]["rule"].p_rhs[
                                p_graph_node]
                        if len(p_pred_nodes) == 0:
                            r_graph_node = projections[graph]["r_r_t"][r_node]
                        predecessor_rhs_graph_rhs[r_pred_node] = r_graph_node
                    rule_hierarchy["rule_homomorphisms"][(
                        predecessor, graph)] = (predecessor_l_graph_l,
                                                predecessor_l_graph_l,
                                                predecessor_rhs_graph_rhs)
                # didn't touch the predecessor or lifter to it
                else:
                    pass

    return rule_hierarchy, instances
Beispiel #5
0
def _get_rule_projections(hierarchy,
                          origin_id,
                          rule,
                          instance,
                          rhs_typing=None,
                          ignore=None):
    if ignore is None:
        ignore = []
    if rhs_typing is None:
        rhs_typing = {}
    projections = {}
    if rule.is_relaxing():
        for graph, origin_typing in hierarchy.get_descendants(
                origin_id).items():
            if graph not in ignore:
                if hierarchy.is_graph(graph):
                    # Compute canonical P_T
                    l_t, l_l_t, l_t_t = image_factorization(
                        rule.lhs, hierarchy.get_graph(graph),
                        compose(instance, origin_typing))

                    # Compute canonical R_T
                    r_t, l_t_r_t, r_r_t = pushout(rule.p, l_t, rule.rhs, l_l_t,
                                                  rule.p_rhs)

                    # Modify P_T and R_T according to the controlling
                    # relation rhs_typing
                    if graph in rhs_typing.keys():
                        r_t_factorization = {
                            r_r_t[k]: v
                            for k, v in rhs_typing[graph].items()
                        }
                        added_t_nodes = set()
                        for n in r_t.nodes():
                            if n in r_t_factorization.keys():
                                # If corresponding R_T node is specified in
                                # the controlling relation add nodes of T
                                # that type it to P
                                t_nodes = r_t_factorization[n]
                                for t_node in t_nodes:
                                    if t_node not in l_t_t.values() and\
                                       t_node not in added_t_nodes:
                                        new_p_node = primitives.generate_new_node_id(
                                            l_t, t_node)
                                        primitives.add_node(l_t, new_p_node)
                                        added_t_nodes.add(t_node)
                                        l_t_r_t[new_p_node] = n
                                        l_t_t[new_p_node] = t_node
                                    else:
                                        l_t_r_t[keys_by_value(l_t_t,
                                                              t_node)[0]] = n

                    projections[graph] = {
                        "rule": Rule(lhs=l_t, p=l_t, rhs=r_t, p_rhs=l_t_r_t),
                        "instance": l_t_t,
                        "l_l_t": l_l_t,
                        "p_p_t": {k: l_l_t[v]
                                  for k, v in rule.p_lhs.items()},
                        "r_r_t": r_r_t
                    }

    return projections
Beispiel #6
0
def _propagate_down(hierarchy,
                    origin_id,
                    origin_construct,
                    rule,
                    instance,
                    rhs_typing_rels,
                    inplace=False):
    """Propagate changes down the hierarchy."""
    updated_graphs = dict()
    updated_homomorphisms = dict()
    updated_relations = []

    (origin_m, origin_m_origin, origin_prime, origin_m_origin_prime,
     rhs_origin_prime) = origin_construct

    if rule.is_relaxing():
        for graph in hierarchy.bfs_tree(origin_id):
            if graph != origin_id:
                relation_g_rhs = set()
                for key, values in rhs_typing_rels[graph].items():
                    for v in values:
                        relation_g_rhs.add((v, key))

                (g_prime, g_g_prime, rhs_g_prime) =\
                    pushout_from_relation(
                        hierarchy.get_graph(graph), rule.rhs,
                        relation_g_rhs, inplace)
                updated_graphs[graph] = (g_prime, g_g_prime, rhs_g_prime)

                graph_predecessors = hierarchy.predecessors(graph)
                if origin_id in graph_predecessors:
                    updated_homomorphisms[(origin_id, graph)] =\
                        get_unique_map_from_pushout(
                            origin_prime.nodes(),
                            origin_m_origin_prime,
                            rhs_origin_prime,
                            compose_chain(
                                [origin_m_origin,
                                 hierarchy.adj[origin_id][graph]["mapping"],
                                 g_g_prime]),
                            rhs_g_prime)

                if len(rule.added_nodes()) > 0 or\
                   len(rule.merged_nodes()) > 0:
                    for pred in hierarchy.predecessors(graph):
                        if pred in updated_graphs.keys():
                            if pred != origin_id:
                                updated_homomorphisms[(pred, graph)] =\
                                    get_unique_map_from_pushout(
                                        updated_graphs[pred][0].nodes(),
                                        updated_graphs[pred][1],
                                        updated_graphs[pred][2],
                                        compose(
                                            hierarchy.adj[
                                                pred][graph]["mapping"],
                                            g_g_prime),
                                        rhs_g_prime)
                    for suc in hierarchy.successors(graph):
                        if suc in updated_graphs.keys():
                            updated_homomorphisms[(graph, suc)] =\
                                get_unique_map_from_pushout(
                                    g_prime.nodes(),
                                    g_g_prime,
                                    rhs_g_prime,
                                    compose(
                                        hierarchy.adj[graph][suc]["mapping"],
                                        updated_graphs[suc][1]),
                                    updated_graphs[suc][2])
                if len(rule.merged_nodes()) > 0:
                    # propagate changes to adjacent relations
                    for related_g in hierarchy.adjacent_relations(graph):
                        updated_relations.append((graph, related_g))

    else:
        for suc in hierarchy.successors(origin_id):
            updated_homomorphisms[(origin_id, suc)] =\
                compose(
                    origin_m_origin,
                    hierarchy.adj[origin_id][suc]["mapping"])

    return {
        "graphs": updated_graphs,
        "homomorphisms": updated_homomorphisms,
        "relations": updated_relations
    }
Beispiel #7
0
def _propagate_up(hierarchy,
                  graph_id,
                  rule,
                  instance,
                  p_origin_m,
                  origin_m_origin_prime,
                  p_typing,
                  inplace=False):
    updated_graphs = dict()
    updated_homomorphisms = dict()
    updated_relations = set()
    updated_rules = dict()
    updated_rule_h = dict()

    if rule.is_restrictive():
        for graph in hierarchy.bfs_tree(graph_id, reverse=True):
            if graph != graph_id:
                if hierarchy.is_graph(graph):
                    origin_typing = hierarchy.get_typing(graph, graph_id)
                    graph_p_typing = None
                    if graph in p_typing.keys():
                        graph_p_typing = p_typing[graph]
                    (graph_prime, graph_prime_graph, graph_prime_origin) =\
                        _propagate_rule_up(
                            hierarchy.get_graph(graph),
                            origin_typing, rule, instance,
                            p_origin_m, graph_p_typing, inplace)
                    updated_graphs[graph] =\
                        (graph_prime, graph_prime_graph,
                         None, graph_prime_origin)

                    graph_successors = list(hierarchy.successors(graph))
                    if graph_id in graph_successors:
                        updated_homomorphisms[(graph, graph_id)] =\
                            compose(
                                graph_prime_origin,
                                origin_m_origin_prime)
                    if len(rule.removed_nodes()) > 0 or\
                       len(rule.cloned_nodes()) > 0:
                        for suc in graph_successors:
                            if suc != graph_id:
                                if suc in updated_graphs.keys():
                                    graph_prime_suc_prime =\
                                        get_unique_map_to_pullback(
                                            updated_graphs[suc][0].nodes(),
                                            updated_graphs[suc][1],
                                            updated_graphs[suc][3],
                                            compose(
                                                graph_prime_graph,
                                                hierarchy.adj[graph][suc][
                                                    "mapping"]),
                                            graph_prime_origin)
                                else:
                                    graph_prime_suc_prime = compose(
                                        graph_prime_graph,
                                        hierarchy.adj[graph][suc]["mapping"])
                                updated_homomorphisms[(graph, suc)] =\
                                    graph_prime_suc_prime

                        for pred in hierarchy.predecessors(graph):
                            if pred in updated_graphs.keys():
                                pred_m_graph_m = get_unique_map_to_pullback(
                                    graph_prime.nodes(), graph_prime_graph,
                                    graph_prime_origin,
                                    updated_graphs[pred][1],
                                    updated_graphs[pred][3])
                                updated_homomorphisms[(pred,
                                                       graph)] = pred_m_graph_m

                        # propagate changes to adjacent relations
                        for related_g in hierarchy.adjacent_relations(graph):
                            updated_relations.add((graph, related_g))
                else:
                    rule_to_rewrite = hierarchy.node[graph]["rule"]

                    (lhs_origin_typing,
                     p_origin_typing,
                     rhs_origin_typing) =\
                        hierarchy.get_rule_typing(graph, graph_id)

                    (lhs_prime, lhs_prime_lhs, lhs_prime_origin) =\
                        _propagate_rule_up(
                            rule_to_rewrite.lhs,
                            lhs_origin_typing, rule, instance,
                            p_origin_m, {}, inplace=False)

                    (pr_prime, pr_prime_pr, pr_prime_origin) =\
                        _propagate_rule_up(
                            rule_to_rewrite.p,
                            p_origin_typing, rule, instance,
                            p_origin_m, {}, inplace=False)

                    (rhs_prime, rhs_prime_rhs, rhs_prime_origin) =\
                        _propagate_rule_up(
                            rule_to_rewrite.rhs,
                            rhs_origin_typing, rule, instance,
                            p_origin_m, {}, inplace=False)

                    # find p_m -> lhs_m
                    new_p_lhs = get_unique_map_to_pullback(
                        lhs_prime.nodes(), lhs_prime_lhs, lhs_prime_origin,
                        compose(pr_prime_pr, rule_to_rewrite.p_lhs),
                        pr_prime_origin)

                    # find p_m -> rhs_m
                    new_p_rhs = get_unique_map_to_pullback(
                        rhs_prime.nodes(), rhs_prime_rhs, rhs_prime_origin,
                        compose(pr_prime_pr, rule_to_rewrite.p_rhs),
                        pr_prime_origin)

                    new_rule =\
                        Rule(pr_prime, lhs_prime, rhs_prime,
                             new_p_lhs, new_p_rhs)

                    updated_rules[graph] = new_rule

                    for suc in hierarchy.successors(graph):
                        if suc == graph_id:
                            lhs_prime_suc_prime =\
                                compose(lhs_prime_origin,
                                        origin_m_origin_prime)
                            rhs_prime_suc_prime =\
                                compose(rhs_prime_origin,
                                        origin_m_origin_prime)

                        if suc in updated_graphs.keys():
                            lhs_prime_suc_prime = get_unique_map_to_pullback(
                                updated_graphs[suc][0].nodes(),
                                updated_graphs[suc][1], updated_graphs[suc][3],
                                compose(
                                    lhs_prime_lhs,
                                    hierarchy.adj[graph][suc]["lhs_mapping"]),
                                lhs_prime_origin)
                            rhs_prime_suc_prime = get_unique_map_to_pullback(
                                updated_graphs[suc][0].nodes(),
                                updated_graphs[suc][1], updated_graphs[suc][3],
                                compose(
                                    rhs_prime_rhs,
                                    hierarchy.adj[graph][suc]["rhs_mapping"]),
                                rhs_prime_origin)

                        else:
                            lhs_prime_suc_prime =\
                                compose(
                                    lhs_prime_lhs,
                                    hierarchy.adj[graph][suc]["lhs_mapping"])
                            rhs_prime_suc_prime =\
                                compose(
                                    rhs_prime_rhs,
                                    hierarchy.adj[graph][suc]["rhs_mapping"])

                        updated_rule_h[(graph, suc)] =\
                            (lhs_prime_suc_prime, rhs_prime_suc_prime)

    else:
        for pred in hierarchy.predecessors(graph_id):
            if hierarchy.is_graph(pred):
                updated_homomorphisms[(pred, graph_id)] =\
                    compose(
                        hierarchy.adj[pred][graph_id]["mapping"],
                        origin_m_origin_prime)
            else:
                updated_rule_h[(pred, graph_id)] = (
                    compose(hierarchy.adj[pred][graph_id]["lhs_mapping"],
                            origin_m_origin_prime),
                    compose(hierarchy.adj[pred][graph_id]["rhs_mapping"],
                            origin_m_origin_prime))

    return {
        "graphs": updated_graphs,
        "homomorphisms": updated_homomorphisms,
        "rules": updated_rules,
        "rule_homomorphisms": updated_rule_h,
        "relations": updated_relations
    }
Beispiel #8
0
def get_rule_projections(tx, hierarchy, graph_id, rule, instance, rhs_typing=None):
    """Execute the query finding rule liftings."""
    if rhs_typing is None:
        rhs_typing = {}

    projections = {}

    if rule.is_relaxing():
        if len(rule.lhs.nodes()) > 0:
            lhs_instance = {
                n: instance[n] for n in rule.lhs.nodes()
            }
            lhs_vars = {
                n: n for n in rule.lhs.nodes()}
            match_instance_vars = {
                v: lhs_instance[k] for k, v in lhs_vars.items()
            }

            # Match nodes
            query = "// Match nodes the instance of the rewritten graph \n"
            query += "MATCH {}".format(
                ", ".join([
                    "({}:{} {{id: '{}'}})".format(k, graph_id, v)
                    for k, v in match_instance_vars.items()
                ])
            )
            query += "\n\n"

            carry_vars = list(lhs_vars.values())
            for k, v in lhs_vars.items():
                query += (
                    "OPTIONAL MATCH (n)<-[:typing*1..]-({})\n".format(v) +
                    "WITH {} \n".format(
                        ", ".join(
                            carry_vars +
                            ["collect(DISTINCT {{type:'node', origin: {}.id, id: n.id, graph:labels(n)[0], attrs: properties(n)}}) as {}_dict\n".format(
                                v, v)])
                    )
                )
                carry_vars.append("{}_dict".format(v))

            # Match edges
            for (u, v) in rule.p.edges():
                edge_var = "{}_{}".format(lhs_vars[u], lhs_vars[v])
                query += "OPTIONAL MATCH ({}_instance)-[{}:edge]->({}_instance)\n".format(
                    lhs_vars[u],
                    edge_var,
                    lhs_vars[v])
                query += "WHERE ({})<-[:typing*1..]-({}) AND ({})<-[:typing*1..]-({})\n".format(
                    "{}_instance".format(lhs_vars[u]), lhs_vars[u],
                    "{}_instance".format(lhs_vars[v]), lhs_vars[v])
                query += (
                    "WITH {} \n".format(
                        ", ".join(carry_vars + [
                            "collect({{type: 'edge', source: {}.id, target: {}.id, graph:labels({})[0], attrs: properties({})}}) as {}\n".format(
                                "{}_instance".format(lhs_vars[u]),
                                "{}_instance".format(lhs_vars[v]),
                                "{}_instance".format(lhs_vars[u]),
                                edge_var,
                                edge_var)
                        ])
                    )
                )
                carry_vars.append(edge_var)
            query += "RETURN {}".format(
                ", ".join(
                    ["{}_dict as {}".format(v, v) for v in lhs_vars.values()] +
                    ["{}_{}".format(lhs_vars[u], lhs_vars[v]) for u, v in rule.p.edges()]))

            result = tx.run(query)
            record = result.single()

            l_l_ts = {}
            l_nodes = {}
            l_edges = {}
            for k, v in record.items():
                if len(v) > 0:
                    if v[0]["type"] == "node":
                        for el in v:
                            l_node = keys_by_value(instance, el["origin"])[0]
                            if el["graph"] not in l_nodes:
                                l_nodes[el["graph"]] = {}
                                l_l_ts[el["graph"]] = {}
                            if el["id"] not in l_nodes[el["graph"]]:
                                l_nodes[el["graph"]][el["id"]] = {}
                            l_nodes[el["graph"]][el["id"]] = attrs_union(
                                l_nodes[el["graph"]][el["id"]],
                                attrs_intersection(
                                    generic.convert_props_to_attrs(el["attrs"]),
                                    get_node(rule.lhs, l_node)))
                            l_l_ts[el["graph"]][l_node] = el["id"]
                    else:
                        for el in v:
                            l_sources = keys_by_value(l_l_ts[el["graph"]], el["source"])
                            l_targets = keys_by_value(l_l_ts[el["graph"]], el["target"])

                            for l_source in l_sources:
                                for l_target in l_targets:
                                    if exists_edge(rule.l, l_source, l_target):
                                        if el["graph"] not in l_edges:
                                            l_edges[el["graph"]] = {}
                                        if (el["source"], el["target"]) not in l_edges[el["graph"]]:
                                            l_edges[el["graph"]][(el["source"], el["target"])] = {}
                                        l_edges[el["graph"]][(el["source"], el["target"])] =\
                                            attrs_union(
                                                l_edges[el["graph"]][(el["source"], el["target"])],
                                                attrs_intersection(
                                                    generic.convert_props_to_attrs(el["attrs"]),
                                                    get_edge(rule.lhs, l_source, l_target)))

        for graph, typing in hierarchy.get_descendants(graph_id).items():
            if graph in l_nodes:
                nodes = l_nodes[graph]
            else:
                nodes = {}
            if graph in l_edges:
                edges = l_edges[graph]
            else:
                edges = {}

            l = nx.DiGraph()
            add_nodes_from(l, [(k, v) for k, v in nodes.items()])
            if graph in l_edges:
                add_edges_from(
                    l,
                    [(s, t, v) for (s, t), v in edges.items()])

            rhs, p_rhs, r_r_t = pushout(
                rule.p, l, rule.rhs, compose(rule.p_lhs, l_l_ts[graph]), rule.p_rhs)

            l_t_t = {n: n for n in nodes}

            # Modify P_T and R_T according to the controlling
            # relation rhs_typing
            if graph in rhs_typing.keys():
                r_t_factorization = {
                    r_r_t[k]: v
                    for k, v in rhs_typing[graph].items()
                }
                added_t_nodes = set()
                for n in rhs.nodes():
                    if n in r_t_factorization.keys():
                        # If corresponding R_T node is specified in
                        # the controlling relation add nodes of T
                        # that type it to P
                        t_nodes = r_t_factorization[n]
                        for t_node in t_nodes:
                            if t_node not in l_t_t.values() and\
                               t_node not in added_t_nodes:
                                new_p_node = generate_new_id(
                                    l.nodes(), t_node)
                                l.add_node(new_p_node)
                                added_t_nodes.add(t_node)
                                p_rhs[new_p_node] = n
                                l_t_t[new_p_node] = t_node
                            else:
                                p_rhs[keys_by_value(l_t_t, t_node)[0]] = n

            projections[graph] = {
                "rule": Rule(p=l, rhs=rhs, p_rhs=p_rhs),
                "instance": l_t_t,
                "l_l_t": l_l_ts[graph],
                "p_p_t": {k: l_l_ts[graph][v] for k, v in rule.p_lhs.items()},
                "r_r_t": r_r_t
            }

    return projections
Beispiel #9
0
def _check_consistency(hierarchy, source, target, mapping=None):
    all_paths = dict(nx.all_pairs_shortest_path(hierarchy))

    paths_to_source = {}
    paths_from_target = {}
    for s in hierarchy.nodes():
        if source in all_paths[s].keys():
            paths_to_source[s] = all_paths[s][source]
        if s == target:
            for key in all_paths[target].keys():
                paths_from_target[key] = all_paths[target][key]

    for s in paths_to_source.keys():
        if hierarchy._path_from_rule(paths_to_source[s]):
            for t in paths_from_target.keys():
                # find homomorphism from s to t via new path
                if s == source:
                    raise HierarchyError(
                        "Found a rule typing some node in the hierarchy!")
                new_lhs_h, new_rhs_h = hierarchy.compose_path_typing(
                    paths_to_source[s])
                new_lhs_h = compose(new_lhs_h, mapping)
                new_rhs_h = compose(new_rhs_h, mapping)

                if t != target:
                    new_lhs_h = compose(
                        new_lhs_h,
                        hierarchy.compose_path_typing(paths_from_target[t]))
                    new_rhs_h = compose(
                        new_rhs_h,
                        hierarchy.compose_path_typing(paths_from_target[t]),
                    )
                try:
                    # find homomorphisms from s to t via other paths
                    s_t_paths = nx.all_shortest_paths(hierarchy, s, t)
                    for path in s_t_paths:
                        lhs_h, rhs_h = hierarchy.compose_path_typing(path)
                        if lhs_h != new_lhs_h:
                            raise HierarchyError(
                                "Invalid lhs typing: homomorphism does "
                                "not commute with an existing " +
                                "path from '%s' to '%s'!" % (s, t))
                        if rhs_h != new_rhs_h:
                            raise HierarchyError(
                                "Invalid rhs typing: homomorphism does "
                                "not commute with an existing " +
                                "path from '%s' to '%s'!" % (s, t))
                except (nx.NetworkXNoPath):
                    pass
        else:
            for t in paths_from_target.keys():
                # find homomorphism from s to t via new path
                if s != source:
                    new_homomorphism = hierarchy.compose_path_typing(
                        paths_to_source[s])
                else:
                    new_homomorphism = dict([(key, key)
                                             for key, _ in mapping.items()])
                new_homomorphism = compose(new_homomorphism, mapping)
                if t != target:
                    new_homomorphism = compose(
                        new_homomorphism,
                        hierarchy.compose_path_typing(paths_from_target[t]))

                # find homomorphisms from s to t via other paths
                s_t_paths = nx.all_shortest_paths(hierarchy, s, t)
                try:
                    # check only the first path
                    for path in s_t_paths:
                        path_homomorphism = hierarchy.compose_path_typing(path)
                        if path_homomorphism != new_homomorphism:
                            raise HierarchyError(
                                "Homomorphism does not commute with an " +
                                "existing path from '%s' to '%s'!" % (s, t))
                except (nx.NetworkXNoPath):
                    pass
Beispiel #10
0
def _check_consistency(hierarchy, source, target, mapping=None):
    all_paths = dict(nx.all_pairs_shortest_path(hierarchy))

    paths_to_source = {}
    paths_from_target = {}
    for s in hierarchy.nodes():
        if source in all_paths[s].keys():
            paths_to_source[s] = all_paths[s][source]
        if s == target:
            for key in all_paths[target].keys():
                paths_from_target[key] = all_paths[target][key]

    for s in paths_to_source.keys():
        if hierarchy._path_from_rule(paths_to_source[s]):
            for t in paths_from_target.keys():
                # find homomorphism from s to t via new path
                if s == source:
                    raise HierarchyError(
                        "Found a rule typing some node in the hierarchy!"
                    )
                new_lhs_h, new_rhs_h = hierarchy.compose_path_typing(
                    paths_to_source[s])
                new_lhs_h = compose(new_lhs_h, mapping)
                new_rhs_h = compose(new_rhs_h, mapping)

                if t != target:
                    new_lhs_h = compose(
                        new_lhs_h,
                        hierarchy.compose_path_typing(paths_from_target[t])
                    )
                    new_rhs_h = compose(
                        new_rhs_h,
                        hierarchy.compose_path_typing(paths_from_target[t]),
                    )
                try:
                    # find homomorphisms from s to t via other paths
                    s_t_paths = nx.all_shortest_paths(hierarchy, s, t)
                    for path in s_t_paths:
                        lhs_h, rhs_h = hierarchy.compose_path_typing(path)
                        if lhs_h != new_lhs_h:
                            raise HierarchyError(
                                "Invalid lhs typing: homomorphism does "
                                "not commute with an existing " +
                                "path from '%s' to '%s'!" % (s, t)
                            )
                        if rhs_h != new_rhs_h:
                            raise HierarchyError(
                                "Invalid rhs typing: homomorphism does "
                                "not commute with an existing " +
                                "path from '%s' to '%s'!" % (s, t)
                            )
                except(nx.NetworkXNoPath):
                    pass
        else:
            for t in paths_from_target.keys():
                # find homomorphism from s to t via new path
                if s != source:
                    new_homomorphism = hierarchy.compose_path_typing(
                        paths_to_source[s])
                else:
                    new_homomorphism = dict([(key, key)
                                             for key, _ in mapping.items()])
                new_homomorphism = compose(
                    new_homomorphism, mapping)
                if t != target:
                    new_homomorphism = compose(
                        new_homomorphism,
                        hierarchy.compose_path_typing(paths_from_target[t])
                    )

                # find homomorphisms from s to t via other paths
                s_t_paths = nx.all_shortest_paths(hierarchy, s, t)
                try:
                    # check only the first path
                    for path in s_t_paths:
                        path_homomorphism = hierarchy.compose_path_typing(path)
                        if path_homomorphism != new_homomorphism:
                            raise HierarchyError(
                                "Homomorphism does not commute with an " +
                                "existing path from '%s' to '%s'!" % (s, t)
                            )
                except(nx.NetworkXNoPath):
                        pass