def clone_node(hie, g_id, parent, node, new_name, propagate=False): """Create a clone of a node. If propagate is True, also clone all the nodes typed by it""" if isinstance(hie.node[g_id], GraphNode): if new_name in hie.node[g_id].graph.nodes(): raise ValueError("node {} already in graph".format(new_name)) if propagate: lhs = nx.DiGraph() lhs.add_node(node) ppp = nx.DiGraph() ppp.add_node(node) ppp.add_node(new_name) rhs = nx.DiGraph() rhs.add_node(node) rhs.add_node(new_name) rule = Rule(ppp, lhs, rhs, {node: node, new_name: node}, None) _rewrite(hie, g_id, rule, {node: node}) else: prim.clone_node(hie.node[g_id].graph, node, new_name) for _, typing in hie.out_edges(g_id): mapping = hie.edge[g_id][typing].mapping if node in mapping.keys(): mapping[new_name] = mapping[node] elif isinstance(hie.node[g_id], RuleNode): hie.node[g_id].rule.clone_rhs_node(node, new_name) for _, typing in hie.out_edges(g_id): mapping = hie.edge[g_id][typing].rhs_mapping if node in mapping: mapping[new_name] = mapping[node] else: raise ValueError("node is neither a rule nor a graph")
def rm_node(hie, g_id, parent, node_id, force=False): """remove a node from a graph """ if isinstance(hie.node[g_id], GraphNode): if [ c for c in all_children(hie, g_id) if node_id in hie.edge[c][g_id].mapping.values() ]: if not force: raise ValueError("some nodes are typed by {}" "set the force argument to" "delete the as well".format(node_id)) lhs = nx.DiGraph() lhs.add_node(node_id) ppp = nx.DiGraph() rhs = nx.DiGraph() rule = Rule(ppp, lhs, rhs) _rewrite(hie, g_id, rule, {node_id: node_id}) elif isinstance(hie.node[g_id], RuleNode): hie.node[g_id].rule.remove_node_rhs(node_id) for _, typing in hie.out_edges(g_id): if node_id in hie.edge[g_id][typing].rhs_mapping.keys(): del hie.edge[g_id][typing].rhs_mapping[node_id] else: raise ValueError("node is neither a rule nor a graph")
def test_remove_edge(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.remove_edge(1, 2) assert_graph_eq(rule.lhs, self.pattern) assert(('d', 'a') in rule.p.edges()) assert(('s', 'x') in rule.rhs.edges()) return
def test_add_edge(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.add_edge(4, 2) assert_graph_eq(rule.lhs, self.pattern) assert_graph_eq(rule.p, self.p) assert(('s', 'y') in rule.rhs.edges()) return
def test_rewrite(self): pattern = nx.DiGraph() prim.add_nodes_from(pattern, [1, (2, {"a": {1, 2}}), 3]) prim.add_edges_from(pattern, [(1, 2), (2, 3)]) lhs_typing = { "g0": { 1: "circle", 2: "square", 3: "triangle" }, "g00": { 1: "white", 2: "white", 3: "black" } } p = nx.DiGraph() p.add_nodes_from([1, 2, 3]) p.add_edges_from([(2, 3)]) rhs = nx.DiGraph() prim.add_nodes_from( rhs, [1, (2, { "a": {3, 5} }), (3, { "new_attrs": {1} }), 4]) prim.add_edges_from(rhs, [(2, 1, { "new_attrs": {2} }), (2, 4, { "new_attrs": {3} }), (2, 3, { "new_attrs": {4} })]) p_lhs = {1: 1, 2: 2, 3: 3} p_rhs = {1: 1, 2: 2, 3: 3} rule = Rule(p, pattern, rhs, p_lhs, p_rhs) rhs_typing = { "g0": { 1: "circle", 2: "square", 3: "triangle", 4: "triangle" }, "g00": { 1: "white", 2: "white", 3: "black", 4: "black" } } instances = self.hierarchy.find_matching("g1", pattern, lhs_typing) # print(instances[0]) self.hierarchy.rewrite("g1", rule, instances[0], lhs_typing, rhs_typing)
def test_update_edge_attrs(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.update_edge_attrs(2, 3, {'b': 1}) assert(rule.p.edge['b']['c'] is None) test_dict = {'b': FiniteSet({1})} # normalize_attrs(test_dict) assert(rule.rhs.edge['y']['z'] == test_dict) return
def merge_node_list(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.merge_node_list([2, 3], 'wow_name') assert(rule.lhs == self.pattern) assert(rule.p == self.p) assert('wow_name' in rule.rhs.nodes()) assert(('wow_name', 'wow_name') in rule.rhs.edges()) assert(('wow_name', 'y') in rule.rhs.edges())
def test_add_edge_attrs(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.add_edge_attrs(4, 1, {'amazing': True}) assert_graph_eq(rule.p, self.p) t = {'amazing': {True}} normalize_attrs(t) assert(rule.rhs.edge['s']['x'] == t) return
def test_update_node_attrs(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.update_node_attrs(4, {'b': 2}) assert(rule.p.node['d'] is None) test_dict = {'b': {2}} normalize_attrs(test_dict) assert(rule.rhs.node['s'] == test_dict) return
def test_merge_nodes(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) new_name = rule.merge_nodes(1, 4) assert_graph_eq(rule.lhs, self.pattern) assert_graph_eq(rule.p, self.p) assert(new_name in rule.rhs.nodes()) assert((new_name, new_name) in rule.rhs.edges()) assert((new_name, 'y') in rule.rhs.edges()) return
def test_add_node(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.add_node('g', {'a': 1}) assert_graph_eq(rule.p, self.p) assert_graph_eq(rule.lhs, self.pattern) assert('g' in rule.rhs) t = {'a': set([1])} normalize_attrs(t) assert(rule.rhs.node['g'] == t) return
def test_remove_node_attrs(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.add_node_attrs(4, {'a': 2}) rule.remove_node_attrs(4, {'a': 1}) t1 = {'a': set()} t2 = {'a': set([2])} normalize_attrs(t1) normalize_attrs(t2) assert(rule.p.node['d'] == t1) assert(rule.rhs.node['s'] == t2) return
def test_clone_node(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.clone_node(2) assert_graph_eq(rule.lhs, self.pattern) assert('b1' in rule.p.nodes()) assert('y1' in rule.rhs.nodes()) assert(('a', 'b1') in rule.p.edges()) assert(('b1', 'c') in rule.p.edges()) assert(('x', 'y1') in rule.rhs.edges()) assert(('t', 'y1') in rule.rhs.edges()) return
def test_remove_node(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.remove_node(2) assert_graph_eq(rule.lhs, self.pattern) assert('b' not in rule.p.nodes()) assert(('a', 'b') not in rule.p.edges()) assert(('b', 'c') not in rule.p.edges()) assert('y' not in rule.rhs.nodes()) assert(('x', 'y') not in rule.rhs.edges()) assert(('t', 'y') not in rule.rhs.edges()) assert(('y', 'z') not in rule.rhs.edges()) return
def test_from_commands(self): pattern = nx.DiGraph() prim.add_nodes_from(pattern, [(1, { 'state': 'p' }), (2, { 'name': 'BND' }), 3, 4]) prim.add_edges_from(pattern, [(1, 2, { 's': 'p' }), (3, 2, { 's': 'u' }), (3, 4)]) p = nx.DiGraph() prim.add_nodes_from(p, [(1, { 'state': 'p' }), ("1_clone", { 'state': 'p' }), (2, { 'name': 'BND' }), 3, 4]) prim.add_edges_from(p, [(1, 2), ('1_clone', 2), (3, 4)]) rhs = nx.DiGraph() prim.add_nodes_from(rhs, [(1, { 'state': 'p' }), ("1_clone", { 'state': 'p' }), (2, { 'name': 'BND' }), 3, 4, 5]) prim.add_edges_from(rhs, [(1, 2, { 's': 'u' }), ('1_clone', 2), (2, 4), (3, 4), (5, 3)]) p_lhs = {1: 1, '1_clone': 1, 2: 2, 3: 3, 4: 4} p_rhs = {1: 1, '1_clone': '1_clone', 2: 2, 3: 3, 4: 4} rule1 = Rule(p, pattern, rhs, p_lhs, p_rhs) commands = "clone 1.\n" +\ "delete_edge 3 2.\n" +\ "add_node 5.\n" +\ "add_edge 2 4.\n" +\ "add_edge 5 3." rule2 = Rule.from_transform(pattern, commands) assert ((5, 3) in rule2.rhs.edges()) assert (5 in rule2.rhs.nodes() and 5 not in rule2.p.nodes()) assert ((2, 4) in rule2.rhs.edges())
def test_remove_edge_attrs(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.remove_edge_attrs(2, 3, {'a': set()}) t1 = {'a': {1}} normalize_attrs(t1) assert(rule.p.edge['b']['c'] == t1) assert(rule.rhs.edge['y']['z'] == t1) rule.remove_edge_attrs(2, 3, {'a': {1}}) t2 = {'a': set()} normalize_attrs(t2) print(t2) print(rule.p.edge['b']['c']) assert(rule.p.edge['b']['c'] == t2) assert(rule.rhs.edge['y']['z'] == t2) return
def test_porpagation_node_attrs_adds(self): p = nx.DiGraph() primitives.add_nodes_from( p, [1, 2] ) lhs = nx.DiGraph() primitives.add_nodes_from( lhs, [1, 2] ) rhs = nx.DiGraph() primitives.add_nodes_from( rhs, [ (1, {"a1": True}), (2, {"a2": 1}), (3, {"a3": "x"})] ) rule = Rule(p, lhs, rhs) instance = {1: "A", 2: "A_res_1"} rhs_typing = {"mm": {3: "state"}} try: self.hierarchy.rewrite( "n1", rule, instance, lhs_typing=None, rhs_typing=rhs_typing) raise ValueError("Error was not caught!") except RewritingError: pass new_hierarchy, _ = self.hierarchy.rewrite( "n1", rule, instance, lhs_typing=None, rhs_typing=rhs_typing, strict=False, inplace=False) # test propagation of the node attribute adds assert("a1" in new_hierarchy.graph["n1"].node["A"]) assert("a2" in new_hierarchy.graph["n1"].node["A_res_1"]) assert("a3" in new_hierarchy.graph["n1"].node[3]) assert("a1" in new_hierarchy.graph["ag"].node["A"]) assert("a2" in new_hierarchy.graph["ag"].node["A_res_1"]) assert("a3" in new_hierarchy.graph["ag"].node[3])
def remove_attributes(hie, g_id, parent, node, json_attrs): """remove the attributes from json_attrs from the node""" attrs = prim.json_dict_to_attrs(json_attrs) if isinstance(hie.node[g_id], GraphNode): lhs = nx.DiGraph() lhs.add_node(node) add_node_attrs(lhs, node, attrs) ppp = nx.DiGraph() ppp.add_node(node) rhs = nx.DiGraph() rhs.add_node(node) rule = Rule(ppp, lhs, rhs) _rewrite(hie, g_id, rule, {node: node}) elif isinstance(hie.node[g_id], RuleNode): hie.node[g_id].rule.remove_node_attrs_rhs(node, attrs) else: raise ValueError("node is neither a rule nor a graph")
def test_add_node_attrs(self): rule = Rule(self.p, self.pattern, self.rhs, self.p_lhs, self.p_rhs) rule.add_node_attrs(1, {'a': 1}) t1 = {'a': {1}} t2 = {'a': {1, 2}} t3 = {'a': {1, 2}, 'b': {1}} normalize_attrs(t1) normalize_attrs(t2) normalize_attrs(t3) assert(rule.rhs.node['x'] == t1) rule.add_node_attrs(4, {'a': 1}) assert(rule.rhs.node['s'] == t1) rule.add_node_attrs(4, {'a': 2}) assert(rule.rhs.node['s'] == t2) rule.add_node_attrs(4, {'b': 1}) assert(rule.rhs.node['s'] == t3) return
def new_rule(hie, parent, name, pattern_name=None): """create a new rule """ if valid_child_name(hie, parent, name): if pattern_name is None: pattern = nx.DiGraph() else: pattern_id = child_from_name(hie, parent, pattern_name) pattern = hie.node[pattern_id].graph rule_id = hie.unique_graph_id(name) rule = Rule(pattern, pattern, pattern) hie.add_rule(rule_id, rule, {"name": name}) if parent is not None: if pattern_name is None: hie.add_rule_typing(rule_id, parent, {}, {}) else: mapping = hie.edge[pattern_id][parent].mapping hie.add_rule_typing(rule_id, parent, mapping, mapping) else: raise ValueError("Invalid new name")
def merge_nodes(hie, g_id, parent, node1, node2, new_name): """merge node1 and node2 in graph or rule""" if isinstance(hie.node[g_id], GraphNode): if new_name in hie.node[g_id].graph.nodes(): raise ValueError("node {} already exists".format(new_name)) lhs = nx.DiGraph() lhs.add_node(node1) lhs.add_node(node2) ppp = nx.DiGraph() ppp.add_node(node1) ppp.add_node(node2) rhs = nx.DiGraph() rhs.add_node(new_name) rule = Rule(ppp, lhs, rhs, None, {node1: new_name, node2: new_name}) _rewrite(hie, g_id, rule, {node1: node1, node2: node2}) elif isinstance(hie.node[g_id], RuleNode): tmp_rule = copy.deepcopy(hie.node[g_id].rule) tmp_rule.merge_nodes_rhs(node1, node2, new_name) typings = { typing: copy.deepcopy(hie.edge[g_id][typing]) for _, typing in hie.out_edges(g_id) } for typing_rule in typings.values(): mapping = typing_rule.rhs_mapping if node1 in mapping.keys(): if node2 in mapping.keys(): if mapping[node1] == mapping[node2]: mapping[new_name] = mapping[node1] del mapping[node1] del mapping[node2] else: raise ValueError("merge nodes of different types") else: raise ValueError("merge nodes of different types") else: if node2 in mapping.keys(): raise ValueError("merge nodes of different types") for _, typing in hie.out_edges(g_id): hie.edge[g_id][typing] = typings[typing] hie.node[g_id].rule = tmp_rule else: raise ValueError("node is neither a rule nor a graph")
def rm_edge(hie, g_id, parent, node1, node2): """remove an edge from a graph, and all the edges typed by it""" if isinstance(hie.node[g_id], GraphNode): lhs = nx.DiGraph() lhs.add_node(node1) lhs.add_node(node2) lhs.add_edge(node1, node2) ppp = nx.DiGraph() ppp.add_node(node1) ppp.add_node(node2) rhs = nx.DiGraph() rhs.add_node(node1) rhs.add_node(node2) rule = Rule(ppp, lhs, rhs) _rewrite(hie, g_id, rule, {node1: node1, node2: node2}) elif isinstance(hie.node[g_id], RuleNode): hie.node[g_id].rule.remove_edge_rhs(node1, node2) else: raise ValueError("node is neither a rule nor a graph")
def test_rewrite(self): pattern = nx.DiGraph() add_nodes_from(pattern, [(1, { 'state': 'p' }), (2, { 'name': 'BND' }), 3, 4]) add_edges_from(pattern, [(1, 2, { 's': 'p' }), (3, 2, { 's': 'u' }), (3, 4)]) p = nx.DiGraph() add_nodes_from(p, [(1, {'state': 'p'}), (2, {'name': 'BND'}), 3, 4]) p.add_edges_from([(1, 2), (3, 4)]) rhs = nx.DiGraph() add_nodes_from(rhs, [(1, { 'state': 'p' }), (2, { 'name': 'BND' }), (3, { 'merged': 'yes' }), (4, { 'new': 'yes' })]) add_edges_from(rhs, [(1, 2, { 's': 'u' }), (2, 4), (3, 3), (3, 4, { 'from': 'merged' })]) p_lhs = {1: 1, 2: 2, 3: 3, 4: 4} p_rhs = {1: 1, 2: 2, 3: 3, 4: 3} rule = Rule(p, pattern, rhs, p_lhs, p_rhs) instances = find_matching_with_types(self.graph, rule.lhs, {}, {}, {}) rule.apply_to(self.graph, instances[0], rule)
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_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 _get_rule_liftings(hierarchy, origin_id, rule, instance, p_typing=None, ignore=None): if ignore is None: ignore = [] if p_typing is None: p_typing = {} liftings = {} if rule.is_restrictive(): for graph in hierarchy.bfs_tree(origin_id, reverse=True): if graph not in ignore: if graph != origin_id: # find the lifting to a graph if hierarchy.is_graph(graph): origin_typing = hierarchy.get_typing(graph, origin_id) # Compute L_G l_g, l_g_g, l_g_l = pullback( hierarchy.get_graph(graph), rule.lhs, hierarchy.get_graph(origin_id), origin_typing, instance) # Compute canonical P_G canonical_p_g, p_g_l_g, p_g_p = pullback( l_g, rule.p, rule.lhs, l_g_l, rule.p_lhs) # Remove controlled things from P_G if graph in p_typing.keys(): l_g_factorization = { keys_by_value(l_g_g, k)[0]: v for k, v in p_typing[graph].items() } p_g_nodes_to_remove = set() for n in canonical_p_g.nodes(): l_g_node = p_g_l_g[n] # If corresponding L_G node is specified in # the controlling relation, remove all # the instances of P nodes not mentioned # in this relations if l_g_node in l_g_factorization.keys(): p_nodes = l_g_factorization[l_g_node] if p_g_p[n] not in p_nodes: del p_g_p[n] del p_g_l_g[n] p_g_nodes_to_remove.add(n) for n in p_g_nodes_to_remove: primitives.remove_node(canonical_p_g, n) liftings[graph] = { "rule": Rule(p=canonical_p_g, lhs=l_g, p_lhs=p_g_l_g), "instance": l_g_g, "l_g_l": l_g_l, "p_g_p": p_g_p } return liftings
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 test_add_rule_multiple_typing(self): lhs = nx.DiGraph() prim.add_nodes_from(lhs, [1, 2, 3, 4]) prim.add_edges_from(lhs, [(1, 3), (2, 3), (4, 3)]) p = nx.DiGraph() prim.add_nodes_from(p, [1, 3, 31, 4]) prim.add_edges_from(p, [(1, 3), (1, 31), (4, 3), (4, 31)]) rhs = copy.deepcopy(p) p_lhs = {1: 1, 3: 3, 31: 3, 4: 4} p_rhs = {1: 1, 3: 3, 31: 31, 4: 4} lhs_typing_g2 = {1: 1, 2: 1, 3: 2, 4: 4} rhs_typing_g2 = {1: 1, 3: 2, 31: 2, 4: 4} lhs_typing_g3 = {1: 1, 2: 1, 3: 1, 4: 2} rhs_typing_g3 = {1: 1, 3: 1, 31: 1, 4: 2} rule = Rule(p, lhs, rhs, p_lhs, p_rhs) self.hierarchy.add_rule("r2", rule, {"name": "Second rule: with multiple typing"}) self.hierarchy.add_rule_typing("r2", "g2", lhs_typing_g2, rhs_typing_g2) self.hierarchy.add_rule_typing("r2", "g3", lhs_typing_g3, rhs_typing_g3) pattern = nx.DiGraph() prim.add_nodes_from(pattern, [1, 2]) prim.add_edges_from(pattern, [(2, 1)]) lhs_typing = { "g0": { 1: "circle", 2: "circle" }, "g00": { 1: "black", 2: "white" } } p = nx.DiGraph() prim.add_nodes_from(p, [1, 2, 21]) prim.add_edges_from(p, [(21, 1)]) rhs = copy.deepcopy(p) p_lhs = {1: 1, 2: 2, 21: 2} p_rhs = {1: 1, 2: 2, 21: 21} rule = Rule(p, pattern, rhs, p_lhs, p_rhs) rhs_typing = { "g0": ({ 1: "circle", 2: "circle", 21: "circle", }), "g00": ({ 1: "black", 2: "white", 21: "white" }) } instances = self.hierarchy.find_matching("g1", pattern, lhs_typing) self.hierarchy.rewrite("g1", rule, instances[0], lhs_typing, rhs_typing)
def test_add_rule(self): lhs = nx.DiGraph() prim.add_nodes_from(lhs, [1, 2, 3]) prim.add_edges_from(lhs, [(1, 2), (2, 1), (2, 3)]) p = nx.DiGraph() prim.add_nodes_from(p, [1, 2, 3, 31]) prim.add_edges_from(p, [(1, 2), (2, 3), (2, 31)]) rhs = nx.DiGraph() prim.add_nodes_from(rhs, [1, 2, 3, 31, 4]) prim.add_edges_from(rhs, [(1, 2), (4, 2), (2, 3), (2, 31)]) p_lhs = {1: 1, 2: 2, 3: 3, 31: 3} p_rhs = {1: 1, 2: 2, 3: 3, 31: 3} rule = Rule(p, lhs, rhs, p_lhs, p_rhs) lhs_typing = {1: "black_circle", 2: "white_circle", 3: "white_square"} rhs_typing = { 1: "black_circle", 2: "white_circle", 3: "white_square", 31: "white_square", 4: "black_circle" } self.hierarchy.add_rule("r1", rule, {"name": "First rule"}) self.hierarchy.add_rule_typing("r1", "g1", lhs_typing, rhs_typing) pattern = nx.DiGraph() prim.add_nodes_from(pattern, [1, (2, {"a": {1, 2}}), 3]) prim.add_edges_from(pattern, [(1, 2), (2, 3)]) lhs_typing = { "g0": { 1: "circle", 2: "square", 3: "triangle" }, "g00": { 1: 'white', 2: 'white', 3: 'black' } } p = nx.DiGraph() prim.add_nodes_from(p, [1, 11, 2, 3]) prim.add_edges_from(p, [(2, 3)]) rhs = nx.DiGraph() prim.add_nodes_from(rhs, [ 1, 11, (2, { "a": {3, 5} }), (3, { "new_attrs": {1} }), ]) prim.add_edges_from(rhs, [(2, 3, {"new_attrs": {4}})]) p_lhs = {1: 1, 11: 1, 2: 2, 3: 3} p_rhs = {1: 1, 11: 11, 2: 2, 3: 3} rule = Rule(p, pattern, rhs, p_lhs, p_rhs) rhs_typing = { "g0": { 1: "circle", 11: "circle", 2: "square", 3: "triangle" }, "g00": { 1: "white", 11: "white", 2: "white", 3: "black" } } instances = self.hierarchy.find_matching("g1", pattern, lhs_typing) self.hierarchy.rewrite("g1", rule, instances[0], lhs_typing, rhs_typing)
def test_propagation_node_adds(self): """Test propagation down of additions.""" p = nx.DiGraph() primitives.add_nodes_from( p, ["B"] ) l = nx.DiGraph() primitives.add_nodes_from( l, ["B"] ) r = nx.DiGraph() primitives.add_nodes_from( r, ["B", "B_res_1", "X", "Y"] ) primitives.add_edge(r, "B_res_1", "B") rule = Rule(p, l, r) instance = {"B": "B"} rhs_typing = { "mm": {"B_res_1": "residue"}, "mmm": {"X": "component"}, "colors": {"Y": "red"} } try: self.hierarchy.rewrite( "n1", rule, instance, lhs_typing=None, rhs_typing=rhs_typing) raise ValueError("Error was not caught!") except RewritingError: pass new_hierarchy, _ = self.hierarchy.rewrite( "n1", rule, instance, lhs_typing=None, rhs_typing=rhs_typing, strict=False, inplace=False) # test propagation of node adds assert("B_res_1" in new_hierarchy.graph["n1"].nodes()) assert("B_res_1" in new_hierarchy.graph["ag"].nodes()) assert(new_hierarchy.typing["n1"]["ag"]["B_res_1"] == "B_res_1") assert(new_hierarchy.typing["ag"]["mm"]["B_res_1"] == "residue") assert(("B_res_1", "B") in new_hierarchy.graph["n1"].edges()) assert(("B_res_1", "B") in new_hierarchy.graph["ag"].edges()) assert("X" in new_hierarchy.graph["n1"].nodes()) assert("X" in new_hierarchy.graph["ag"].nodes()) assert("X" in new_hierarchy.graph["mm"].nodes()) assert("X" in new_hierarchy.graph["colors"].nodes()) assert(new_hierarchy.typing["n1"]["ag"]["X"] == "X") assert(new_hierarchy.typing["ag"]["mm"]["X"] == "X") assert(new_hierarchy.typing["mm"]["mmm"]["X"] == "component") assert(new_hierarchy.typing["mm"]["colors"]["X"] == "X") assert("Y" in new_hierarchy.graph["n1"].nodes()) assert("Y" in new_hierarchy.graph["ag"].nodes()) assert("Y" in new_hierarchy.graph["mm"].nodes()) assert("Y" in new_hierarchy.graph["mm"].nodes()) assert(new_hierarchy.typing["n1"]["ag"]["Y"] == "Y") assert(new_hierarchy.typing["ag"]["mm"]["Y"] == "Y") assert(new_hierarchy.typing["mm"]["mmm"]["Y"] == "Y") assert(new_hierarchy.typing["mm"]["colors"]["Y"] == "red")