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
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
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
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
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
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 }
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 }
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
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
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