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 clone_node(self, n, node_name=None): """Clone a node of the graph.""" p_new_nodes = [] rhs_new_nodes = [] p_keys = keys_by_value(self.p_lhs, n) for k in p_keys: p_new_node = primitives.clone_node(self.p, k) p_new_nodes.append(p_new_node) rhs_new_node = primitives.clone_node(self.rhs, self.p_rhs[k]) rhs_new_nodes.append(rhs_new_node) # self.p_lhs[k] = n self.p_lhs[p_new_node] = n self.p_rhs[p_new_node] = rhs_new_node return (p_new_nodes, rhs_new_nodes)
def clone_rhs_node(self, node, new_name=None): """Clone an rhs node.""" if node not in self.rhs.nodes(): raise RuleError( "Node '%s' is not a node of right hand side" % node ) p_keys = keys_by_value(self.p_rhs, node) if len(p_keys) == 0: primitives.clone_node(self.rhs, node, new_name) elif len(p_keys) == 1: primitives.clone_node(self.rhs, node, new_name) new_p_node = primitives.clone_node(self.p, p_keys[0]) self.p_rhs[new_p_node] = new_name self.p_lhs[new_p_node] = self.p_lhs[p_keys[0]] else: raise RuleError("Cannot clone node that is result of merge!")
def _propagate_rule_up(graph, origin_typing, rule, instance, p_origin, p_typing, inplace=False): if inplace is True: graph_prime = graph else: graph_prime = copy.deepcopy(graph) if p_typing is None: p_typing = {} lhs_removed_nodes = rule.removed_nodes() lhs_removed_node_attrs = rule.removed_node_attrs() p_removed_edges = rule.removed_edges() p_removed_edge_attrs = rule.removed_edge_attrs() lhs_cloned_nodes = rule.cloned_nodes() graph_prime_graph = id_of(graph.nodes()) graph_prime_origin = copy.deepcopy(origin_typing) for lhs_node in rule.lhs.nodes(): origin_node = instance[lhs_node] g_nodes = keys_by_value(origin_typing, origin_node) for node in g_nodes: if lhs_node in lhs_removed_nodes: primitives.remove_node(graph_prime, node) del graph_prime_graph[node] del graph_prime_origin[node] else: graph_prime_origin[node] = origin_node for lhs_node, p_nodes in lhs_cloned_nodes.items(): nodes_to_clone = keys_by_value(origin_typing, instance[lhs_node]) for node in nodes_to_clone: if node in p_typing.keys(): p_nodes = p_typing[node] for i, p_node in enumerate(p_nodes): if i == 0: graph_prime_origin[node] = p_origin[p_node] graph_prime_graph[node] = node else: new_name = primitives.clone_node(graph_prime, node) graph_prime_origin[new_name] = p_origin[p_node] graph_prime_graph[new_name] = node if len(p_nodes) == 0: primitives.remove_node(graph_prime, node) for lhs_node, attrs in lhs_removed_node_attrs.items(): nodes_to_remove_attrs = keys_by_value(origin_typing, instance[lhs_node]) for node in nodes_to_remove_attrs: primitives.remove_node_attrs(graph_prime, node, attrs) for p_u, p_v in p_removed_edges: us = keys_by_value(graph_prime_origin, p_origin[p_u]) vs = keys_by_value(graph_prime_origin, p_origin[p_v]) for u in us: for v in vs: if (u, v) in graph_prime.edges(): primitives.remove_edge(graph_prime, u, v) for (p_u, p_v), attrs in p_removed_edge_attrs.items(): us = keys_by_value(origin_typing, p_origin[p_u]) vs = keys_by_value(origin_typing, p_origin[p_v]) for u in us: for v in vs: primitives.removed_edge_attrs(graph_prime, u, v, attrs) return (graph_prime, graph_prime_graph, graph_prime_origin)
def _propagate_rule_to(graph, origin_typing, rule, instance, p_origin, inplace=False): if inplace is True: graph_prime = graph else: graph_prime = copy.deepcopy(graph) lhs_removed_nodes = rule.removed_nodes() lhs_removed_node_attrs = rule.removed_node_attrs() p_removed_edges = rule.removed_edges() p_removed_edge_attrs = rule.removed_edge_attrs() lhs_cloned_nodes = rule.cloned_nodes() graph_prime_graph = id_of(graph.nodes()) graph_prime_origin = dict() for lhs_node in rule.lhs.nodes(): origin_node = instance[lhs_node] g_nodes = keys_by_value( origin_typing, origin_node) for node in g_nodes: if lhs_node in lhs_removed_nodes: primitives.remove_node( graph_prime, node) del graph_prime_graph[node] else: graph_prime_origin[node] = origin_node for lhs_node, p_nodes in lhs_cloned_nodes.items(): nodes_to_clone = keys_by_value(origin_typing, instance[lhs_node]) for node in nodes_to_clone: for i, p_node in enumerate(p_nodes): if i == 0: graph_prime_origin[node] = p_origin[p_node] graph_prime_graph[node] = node else: new_name = primitives.clone_node( graph_prime, node) graph_prime_origin[new_name] = p_origin[p_node] graph_prime_graph[new_name] = node for lhs_node, attrs in lhs_removed_node_attrs.items(): nodes_to_remove_attrs = keys_by_value( origin_typing, instance[lhs_node]) for node in nodes_to_remove_attrs: primitives.remove_node_attrs( graph_prime, node, attrs) for p_u, p_v in p_removed_edges: us = keys_by_value(graph_prime_origin, p_origin[p_u]) vs = keys_by_value(graph_prime_origin, p_origin[p_v]) for u in us: for v in vs: if (u, v) in graph_prime.edges(): primitives.remove_edge( graph_prime, u, v) for (p_u, p_v), attrs in p_removed_edge_attrs.items(): us = keys_by_value(origin_typing, p_origin[p_u]) vs = keys_by_value(origin_typing, p_origin[p_v]) for u in us: for v in vs: primitives.removed_edge_attrs( graph_prime, u, v, attrs) return (graph_prime, graph_prime_graph, graph_prime_origin)
def pullback_complement(a, b, d, a_b, b_d, inplace=False): """Find the final pullback complement from a->b->d. Makes changes to d inplace. """ check_homomorphism(a, b, a_b, total=True) check_homomorphism(b, d, b_d, total=True) if not is_monic(b_d): raise InvalidHomomorphism( "Second homomorphism is not monic, " "cannot find final pullback complement!" ) if inplace is True: c = d else: c = copy.deepcopy(d) a_c = dict() c_d = id_of(c.nodes()) # Remove/clone nodes for b_node in b.nodes(): a_keys = keys_by_value(a_b, b_node) # Remove nodes if len(a_keys) == 0: remove_node(c, b_d[b_node]) del c_d[b_d[b_node]] # Keep nodes elif len(a_keys) == 1: a_c[a_keys[0]] = b_d[b_node] # Clone nodes else: i = 1 for k in a_keys: if i == 1: a_c[k] = b_d[b_node] c_d[b_d[b_node]] = b_d[b_node] else: new_name = clone_node(c, b_d[b_node]) a_c[k] = new_name c_d[new_name] = b_d[b_node] i += 1 # Remove edges for (b_n1, b_n2) in b.edges(): a_keys_1 = keys_by_value(a_b, b_n1) a_keys_2 = keys_by_value(a_b, b_n2) if len(a_keys_1) > 0 and len(a_keys_2) > 0: for k1 in a_keys_1: for k2 in a_keys_2: if d.is_directed(): if (k1, k2) not in a.edges() and\ (a_c[k1], a_c[k2]) in c.edges(): remove_edge(c, a_c[k1], a_c[k2]) else: if (k1, k2) not in a.edges() and\ (k2, k1) not in a.edges(): if (a_c[k1], a_c[k2]) in d.edges() or\ (a_c[k2], a_c[k1]) in d.edges(): remove_edge(c, a_c[k1], a_c[k2]) # Remove node attrs for a_node in a.nodes(): attrs_to_remove = dict_sub( b.node[a_b[a_node]], a.node[a_node] ) remove_node_attrs(c, a_c[a_node], attrs_to_remove) # removed_node_attrs[a_c[a_node]] = attrs_to_remove # Remove edge attrs for (n1, n2) in a.edges(): attrs_to_remove = dict_sub( get_edge(b, a_b[n1], a_b[n2]), get_edge(a, n1, n2) ) remove_edge_attrs(c, a_c[n1], a_c[n2], attrs_to_remove) # removed_edge_attrs[(a_c[n1], a_c[n2])] = attrs_to_remove return (c, a_c, c_d)
def inject_clone_node(self, n, new_node_id=None): """Inject cloning of a node by the rule. This procedure clones `n` in the preserved part and the right-hand side. Parameters ---------- n : hashable Node from `lhs` to clone new_node_id : hashable Id for the clone Returns ------- p_new_node_id : hashable Id of the new clone node in the preserved part rhs_new_node_id : hashable Id of the new clone node in the right-hand side Raises ------ RuleError If the node to clone is already being removed by the rule or if node with the specified clone id already exists in p. """ p_nodes = keys_by_value(self.p_lhs, n) if len(p_nodes) == 0: raise RuleError( "Cannot inject cloning: node '%s' is already " "being removed by the rule, revert its removal " "first" % n) else: if new_node_id is not None and new_node_id in self.p.nodes(): raise RuleError( "Node with id '%s' already exists in the " "preserved part!") some_p_node = p_nodes[0] p_new_node_id = primitives.clone_node( self.p, some_p_node, new_node_id) self.p_lhs[p_new_node_id] = n # add it to the rhs # generate a new id for rhs rhs_new_node_id = p_new_node_id if rhs_new_node_id in self.rhs.nodes(): rhs_new_node_id = primitives.unique_node_id( self.rhs, rhs_new_node_id) primitives.add_node( self.rhs, rhs_new_node_id, self.p.node[p_new_node_id]) self.p_rhs[p_new_node_id] = rhs_new_node_id # reconnect the new rhs node with necessary edges for pred in self.p.predecessors(p_new_node_id): if (self.p_rhs[pred], rhs_new_node_id) not in self.rhs.edges(): primitives.add_edge( self.rhs, self.p_rhs[pred], rhs_new_node_id, self.p.edge[pred][p_new_node_id]) for suc in self.p.successors(p_new_node_id): if (rhs_new_node_id, self.p_rhs[suc]) not in self.rhs.edges(): primitives.add_edge( self.rhs, rhs_new_node_id, self.p_rhs[suc], self.p.edge[p_new_node_id][suc]) return (p_new_node_id, rhs_new_node_id)
def pullback_complement(a, b, d, a_b, b_d, inplace=False): """Find the final pullback complement from a->b->d. Makes changes to d inplace. """ check_homomorphism(a, b, a_b, total=True) check_homomorphism(b, d, b_d, total=True) if not is_monic(b_d): raise InvalidHomomorphism("Second homomorphism is not monic, " "cannot find final pullback complement!") if inplace is True: c = d else: c = copy.deepcopy(d) a_c = dict() c_d = id_of(c.nodes()) # Remove/clone nodes for b_node in b.nodes(): a_keys = keys_by_value(a_b, b_node) # Remove nodes if len(a_keys) == 0: remove_node(c, b_d[b_node]) del c_d[b_d[b_node]] # Keep nodes elif len(a_keys) == 1: a_c[a_keys[0]] = b_d[b_node] # Clone nodes else: i = 1 for k in a_keys: if i == 1: a_c[k] = b_d[b_node] c_d[b_d[b_node]] = b_d[b_node] else: new_name = clone_node(c, b_d[b_node]) a_c[k] = new_name c_d[new_name] = b_d[b_node] i += 1 # Remove edges for (b_n1, b_n2) in b.edges(): a_keys_1 = keys_by_value(a_b, b_n1) a_keys_2 = keys_by_value(a_b, b_n2) if len(a_keys_1) > 0 and len(a_keys_2) > 0: for k1 in a_keys_1: for k2 in a_keys_2: if d.is_directed(): if (k1, k2) not in a.edges() and\ (a_c[k1], a_c[k2]) in c.edges(): remove_edge(c, a_c[k1], a_c[k2]) else: if (k1, k2) not in a.edges() and\ (k2, k1) not in a.edges(): if (a_c[k1], a_c[k2]) in d.edges() or\ (a_c[k2], a_c[k1]) in d.edges(): remove_edge(c, a_c[k1], a_c[k2]) # Remove node attrs for a_node in a.nodes(): attrs_to_remove = dict_sub(b.node[a_b[a_node]], a.node[a_node]) remove_node_attrs(c, a_c[a_node], attrs_to_remove) # removed_node_attrs[a_c[a_node]] = attrs_to_remove # Remove edge attrs for (n1, n2) in a.edges(): attrs_to_remove = dict_sub(get_edge(b, a_b[n1], a_b[n2]), get_edge(a, n1, n2)) remove_edge_attrs(c, a_c[n1], a_c[n2], attrs_to_remove) # removed_edge_attrs[(a_c[n1], a_c[n2])] = attrs_to_remove return (c, a_c, c_d)