Beispiel #1
0
 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
Beispiel #2
0
    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
Beispiel #3
0
    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
Beispiel #4
0
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)
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
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)