def add_node_attrs_rhs(self, n, attrs): """Add attrs to a node in the rhs.""" if n not in self.rhs.nodes(): raise RuleError( "Node %s does not exist in the right " "hand side of the rule" % n) primitives.add_node_attrs(self.rhs, n, attrs)
def relation_to_span(g1, g2, relation, edges=False, attrs=False, directed=True): """Convert a relation to a span.""" if directed: new_graph = nx.DiGraph() else: new_graph = nx.Graph() left_h = dict() right_h = dict() for a, b in relation: new_node = str(a) + "_" + str(b) new_graph.add_node(new_node) if attrs: common_attrs = attrs_intersection(g1.node[a], g2.node[b]) add_node_attrs(new_graph, new_node, common_attrs) left_h[new_node] = a right_h[new_node] = b for n1 in new_graph.nodes(): for n2 in new_graph.nodes(): if (left_h[n1], left_h[n2]) in g1.edges() and\ (right_h[n1], right_h[n2]) in g2.edges(): new_graph.add_edge(n1, n2) common_attrs = attrs_intersection( g1.edge[left_h[n1]][left_h[n2]], g2.edge[right_h[n1]][right_h[n2]], ) add_edge_attrs(new_graph, n1, n2, common_attrs) return (new_graph, left_h, right_h)
def _add_node_attrs_lhs(self, n, attrs): if n not in self.lhs.nodes(): raise RuleError( "Node '%s' does not exist in the lhs " "of the rule" % n) primitives.add_node_attrs(self.lhs, n, attrs) p_nodes = keys_by_value(self.p_rhs, n) for p_node in p_nodes: primitives.add_node_attrs(self.p, p_node, attrs)
def _propagate_values(hie, id, parent, mapping): anc = hie.get_ancestors(parent) graph = hie.node[id].graph parent_gr = hie.node[parent].graph for (anc_id, anc_typ) in anc.items(): anc_gr = hie.node[anc_id].graph for node in mapping: if mapping[node] in anc_typ: prim.add_node_attrs(anc_gr, anc_typ[mapping[node]], graph.node[node]) for node in mapping: prim.add_node_attrs(parent_gr, mapping[node], graph.node[node])
def add_node_attrs(self, n, attrs): """Add node attributes to a node in the graph.""" if n not in self.lhs.nodes(): raise RuleError( "Node '%s' does not exist in the left " "hand side of the rule" % n) p_keys = keys_by_value(self.p_lhs, n) if len(p_keys) == 0: raise RuleError( "Node '%s' is being removed by the rule, " "cannot add attributes" % n) for k in p_keys: primitives.add_node_attrs(self.rhs, self.p_rhs[k], attrs) return
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 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 add_attributes(hie, g_id, parent, node, json_attrs): """add the attributes from the json_attrs dict to a node""" attrs = prim.json_dict_to_attrs(json_attrs) if isinstance(hie.node[g_id], GraphNode): for typing in hie.successors(g_id): mapping = hie.edge[g_id][typing].mapping if node in mapping: parent_attrs = hie.node[typing].graph.node[mapping[node]] if not valid_attributes(attrs, parent_attrs): raise ValueError("Attributes not in node {} of {}".format( mapping[node], typing)) prim.add_node_attrs(hie.node[g_id].graph, node, attrs) elif isinstance(hie.node[g_id], RuleNode): hie.node[g_id].rule.add_node_attrs_rhs(node, attrs) else: raise ValueError("node is neither a rule nor a graph")
def add_attributes(hie, g_id, parent, node, json_attrs): """add the attributes from the json_attrs dict to a node""" attrs = prim.json_dict_to_attrs(json_attrs) if isinstance(hie.node[g_id], GraphNode): for typing in hie.successors(g_id): mapping = hie.edge[g_id][typing].mapping if node in mapping: parent_attrs = hie.node[typing].graph.node[mapping[node]] if not valid_attributes(attrs, parent_attrs): raise ValueError("Attributes not in node {} of {}" .format(mapping[node], typing)) prim.add_node_attrs(hie.node[g_id].graph, node, attrs) elif isinstance(hie.node[g_id], RuleNode): hie.node[g_id].rule.add_node_attrs_rhs(node, attrs) else: raise ValueError("node is neither a rule nor a graph")
def inject_add_node_attrs(self, n, attrs): """Inject addition of node attributes by the rule. First, tries to find a node with the id `n` in the left-hand side, injects its attrs add to all the `rhs` nodes related to it through l<-p->r, if found, otherwise, tries to find the corresponding node in the preserved part and adds attrs to the node to which `n` maps in p->r, if it is not found in `p`, tries to find it in the `rhs` (it helps us to implement injection of the node attrs add to only one of the clone nodes, or to new nodes, or to merged nodes). Parameters ---------- n1 : hashable Id of an edge's source node in `lhs`, `p` or `rhs`. n2 : hashable Id of an edge's target node in `lhs`, `p` or `rhs`. attrs : dict Dictionary with attrs to add Raises ------ RuleError If node `n` does not exist in the rhs of the rule """ if n not in self.lhs.nodes() + self.p.nodes() + self.rhs.nodes(): raise RuleError( "Node '%s' exists in neither lhs, nor p, nor rhs of the rule" % n) r_nodes = set() if n in self.lhs.nodes(): p_keys = keys_by_value(self.p_lhs, n) for p in p_keys: r_nodes.add(self.p_rhs[p]) elif n in self.p.nodes(): r_nodes.add(self.p_rhs[n]) elif n in self.rhs.nodes(): r_nodes.add(n) for r in r_nodes: primitives.add_node_attrs(self.rhs, r, attrs) return
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 relation_to_span(g1, g2, relation, edges=False, attrs=False, directed=True): """Convert a relation to a span.""" if directed: new_graph = nx.DiGraph() else: new_graph = nx.Graph() left_h = dict() right_h = dict() for a, b in relation: new_node = str(a) + "_" + str(b) new_graph.add_node(new_node) if attrs: common_attrs = attrs_intersection( g1.node[a], g2.node[b] ) add_node_attrs(new_graph, new_node, common_attrs) left_h[new_node] = a right_h[new_node] = b for n1 in new_graph.nodes(): for n2 in new_graph.nodes(): if (left_h[n1], left_h[n2]) in g1.edges() and\ (right_h[n1], right_h[n2]) in g2.edges(): new_graph.add_edge(n1, n2) common_attrs = attrs_intersection( g1.edge[left_h[n1]][left_h[n2]], g2.edge[right_h[n1]][right_h[n2]], ) add_edge_attrs( new_graph, n1, n2, common_attrs ) return (new_graph, left_h, right_h)
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)