def merge_nodes_rhs(self, n1, n2, new_name): """Merge3 nodes in rhs.""" if n1 not in self.rhs.nodes(): raise RuleError("Node '%s' is not a node of the rhs" % n1) if n2 not in self.rhs.nodes(): raise RuleError("Node '%s' is not a node of the rhs" % n2) primitives.merge_nodes(self.rhs, [n1, n2], node_id=new_name) for (source, target) in self.p_rhs.items(): if target == n1 or target == n2: self.p_rhs[source] = new_name
def merge_nodes(self, n1, n2, node_id=None): """Merge two nodes of the graph.""" # Update graphs new_name = None p_keys_1 = keys_by_value(self.p_lhs, n1) p_keys_2 = keys_by_value(self.p_lhs, n2) nodes_to_merge = set() for k1 in p_keys_1: if k1 not in self.p.nodes(): raise RuleError( "Node with the id '%s' does not exist in the " "preserved part of the rule" % k1 ) for k2 in p_keys_2: if k2 not in self.p.nodes(): raise RuleError( "Node with the id '%s' does not exist in " "the preserved part of the rule" % k2 ) nodes_to_merge.add(self.p_rhs[k1]) nodes_to_merge.add(self.p_rhs[k2]) new_name = primitives.merge_nodes( self.rhs, list(nodes_to_merge), node_id=node_id ) # Update mappings keys = p_keys_1 + p_keys_2 for k in keys: self.p_rhs[k] = new_name return new_name
def inject_merge_nodes(self, node_list, node_id=None): """Inject merge of a collection of nodes by the rule. Parameters ---------- node_list : iterable Collection of ids of nodes from the preserved part or the rhs to merge. node_id : hashable Id of the new node corresponding to the result of merge. Returns ------- new_name : hashable Id of the new node corresponding to the result of merge. Raises ------ RuleError If a node with some id specified in `node_lust` does not exist in the preserved part of the rule. """ # Update graphs new_name = None nodes_to_merge = set() for n in node_list: if n in self.p.nodes(): rhs_node = self.p_rhs[n] elif n in self.rhs.nodes(): rhs_node = n else: raise RuleError( "Node with the id '%s' does not exist in neither the " "preserved part of the rule nor its rhs" % n ) nodes_to_merge.add(rhs_node) new_name = primitives.merge_nodes( self.rhs, list(nodes_to_merge), node_id=node_id ) # Update mappings for n in node_list: if n in self.p.nodes(): self.p_rhs[n] = new_name for r_node in nodes_to_merge: merged_ps = keys_by_value(self.p_rhs, r_node) for p in merged_ps: self.p_rhs[p] = new_name return new_name
def pushout_from_relation(g1, g2, relation, inplace=False): """Find the pushout from a relation.""" left_dict = left_relation_dict(relation) right_dict = right_relation_dict(relation) if inplace is True: g12 = g1 else: g12 = copy.deepcopy(g1) g1_g12 = id_of(g12.nodes()) g2_g12 = dict() for node in g1.nodes(): if node in left_dict.keys(): for g2_node in left_dict[node]: g2_g12[g2_node] = node for node in g2.nodes(): if node not in right_dict.keys(): add_node(g12, node, g2.node[node]) g2_g12[node] = node elif len(right_dict[node]) == 1: node_attrs_diff = dict_sub( g2.node[node], g1.node[list(right_dict[node])[0]]) add_node_attrs( g12, list(right_dict[node])[0], node_attrs_diff) elif len(right_dict[node]) > 1: new_name = merge_nodes(g12, right_dict[node]) for g1_node in right_dict[node]: g1_g12[g1_node] = new_name g2_g12[node] = new_name node_attrs_diff = dict_sub( g2.node[node], g12.node[new_name]) add_node_attrs(g12, new_name, node_attrs_diff) for u, v in g2.edges(): if (g2_g12[u], g2_g12[v]) not in g12.edges(): add_edge(g12, g2_g12[u], g2_g12[v], get_edge(g2, u, v)) else: edge_attrs_diff = dict_sub( g2.edge[u][v], g12.edge[g2_g12[u]][g2_g12[v]]) add_edge_attrs(g12, g2_g12[u], g2_g12[v], edge_attrs_diff) return (g12, g1_g12, g2_g12)
def pushout_from_relation(g1, g2, relation, inplace=False): """Find the pushout from a relation.""" left_dict = left_relation_dict(relation) right_dict = right_relation_dict(relation) if inplace is True: g12 = g1 else: g12 = copy.deepcopy(g1) g1_g12 = id_of(g12.nodes()) g2_g12 = dict() for node in g1.nodes(): if node in left_dict.keys(): for g2_node in left_dict[node]: g2_g12[g2_node] = node for node in g2.nodes(): if node not in right_dict.keys(): add_node(g12, node, g2.node[node]) g2_g12[node] = node elif len(right_dict[node]) == 1: node_attrs_diff = dict_sub(g2.node[node], g1.node[list(right_dict[node])[0]]) add_node_attrs(g12, list(right_dict[node])[0], node_attrs_diff) elif len(right_dict[node]) > 1: new_name = merge_nodes(g12, right_dict[node]) for g1_node in right_dict[node]: g1_g12[g1_node] = new_name g2_g12[node] = new_name node_attrs_diff = dict_sub(g2.node[node], g12.node[new_name]) add_node_attrs(g12, new_name, node_attrs_diff) for u, v in g2.edges(): if (g2_g12[u], g2_g12[v]) not in g12.edges(): add_edge(g12, g2_g12[u], g2_g12[v], get_edge(g2, u, v)) else: edge_attrs_diff = dict_sub(g2.edge[u][v], g12.edge[g2_g12[u]][g2_g12[v]]) add_edge_attrs(g12, g2_g12[u], g2_g12[v], edge_attrs_diff) return (g12, g1_g12, g2_g12)
def pushout(a, b, c, a_b, a_c, inplace=False): """Find the pushour of the span b <- a -> c.""" check_homomorphism(a, b, a_b) check_homomorphism(a, c, a_c) if inplace is True: d = b else: d = copy.deepcopy(b) b_d = id_of(b.nodes()) c_d = dict() # Add/merge nodes for c_n in c.nodes(): a_keys = keys_by_value(a_c, c_n) # Add nodes if len(a_keys) == 0: add_node(d, c_n, c.node[c_n]) c_d[c_n] = c_n # Keep nodes elif len(a_keys) == 1: c_d[a_c[a_keys[0]]] = a_b[a_keys[0]] # Merge nodes else: nodes_to_merge = [] for k in a_keys: nodes_to_merge.append(a_b[k]) new_name = merge_nodes(d, nodes_to_merge) c_d[c_n] = new_name for node in nodes_to_merge: b_d[node] = new_name # Add edges for (n1, n2) in c.edges(): if b.is_directed(): if (c_d[n1], c_d[n2]) not in d.edges(): add_edge( d, c_d[n1], c_d[n2], get_edge(c, n1, n2)) else: if (c_d[n1], c_d[n2]) not in d.edges() and\ (c_d[n2], c_d[n1]) not in d.edges(): add_edge( d, c_d[n1], c_d[n2], get_edge(c, n1, n2) ) # Add node attrs for c_n in c.nodes(): a_keys = keys_by_value(a_c, c_n) # Add attributes to the nodes which stayed invariant if len(a_keys) == 1: attrs_to_add = dict_sub( c.node[c_n], a.node[a_keys[0]] ) add_node_attrs(d, c_d[c_n], attrs_to_add) # Add attributes to the nodes which were merged elif len(a_keys) > 1: merged_attrs = {} for k in a_keys: merged_attrs = merge_attributes( merged_attrs, a.node[k] ) attrs_to_add = dict_sub(c.node[c_n], merged_attrs) add_node_attrs(d, c_d[c_n], attrs_to_add) # Add edge attrs for (n1, n2) in c.edges(): d_n1 = c_d[n1] d_n2 = c_d[n2] if d.is_directed(): attrs_to_add = dict_sub( get_edge(c, n1, n2), get_edge(d, d_n1, d_n2) ) add_edge_attrs( d, c_d[n1], c_d[n2], attrs_to_add ) else: attrs_to_add = dict_sub( get_edge(c, n1, n2), get_edge(d, d_n1, d_n2) ) add_edge_attrs( d, c_d[n1], c_d[n2], attrs_to_add ) return (d, b_d, c_d)
def pushout(a, b, c, a_b, a_c, inplace=False): """Find the pushour of the span b <- a -> c.""" check_homomorphism(a, b, a_b) check_homomorphism(a, c, a_c) if inplace is True: d = b else: d = copy.deepcopy(b) b_d = id_of(b.nodes()) c_d = dict() # Add/merge nodes for c_n in c.nodes(): a_keys = keys_by_value(a_c, c_n) # Add nodes if len(a_keys) == 0: add_node(d, c_n, c.node[c_n]) c_d[c_n] = c_n # Keep nodes elif len(a_keys) == 1: c_d[a_c[a_keys[0]]] = a_b[a_keys[0]] # Merge nodes else: nodes_to_merge = [] for k in a_keys: nodes_to_merge.append(a_b[k]) new_name = merge_nodes(d, nodes_to_merge) c_d[c_n] = new_name for node in nodes_to_merge: b_d[node] = new_name # Add edges for (n1, n2) in c.edges(): if b.is_directed(): if (c_d[n1], c_d[n2]) not in d.edges(): add_edge(d, c_d[n1], c_d[n2], get_edge(c, n1, n2)) else: if (c_d[n1], c_d[n2]) not in d.edges() and\ (c_d[n2], c_d[n1]) not in d.edges(): add_edge(d, c_d[n1], c_d[n2], get_edge(c, n1, n2)) # Add node attrs for c_n in c.nodes(): a_keys = keys_by_value(a_c, c_n) # Add attributes to the nodes which stayed invariant if len(a_keys) == 1: attrs_to_add = dict_sub(c.node[c_n], a.node[a_keys[0]]) add_node_attrs(d, c_d[c_n], attrs_to_add) # Add attributes to the nodes which were merged elif len(a_keys) > 1: merged_attrs = {} for k in a_keys: merged_attrs = merge_attributes(merged_attrs, a.node[k]) attrs_to_add = dict_sub(c.node[c_n], merged_attrs) add_node_attrs(d, c_d[c_n], attrs_to_add) # Add edge attrs for (n1, n2) in c.edges(): d_n1 = c_d[n1] d_n2 = c_d[n2] if d.is_directed(): attrs_to_add = dict_sub(get_edge(c, n1, n2), get_edge(d, d_n1, d_n2)) add_edge_attrs(d, c_d[n1], c_d[n2], attrs_to_add) else: attrs_to_add = dict_sub(get_edge(c, n1, n2), get_edge(d, d_n1, d_n2)) add_edge_attrs(d, c_d[n1], c_d[n2], attrs_to_add) return (d, b_d, c_d)