Exemplo n.º 1
0
    def add_edge(self, s, t, attrs=None, **attr):
        """Add an edge to a graph.

        Parameters
        ----------
        graph : networkx.(Di)Graph
        s : hashable, source node id.
        t : hashable, target node id.
        attrs : dict
            Edge attributes.
        """
        if attrs is None:
            attrs = attr
        else:
            try:
                attrs.update(attr)
            except AttributeError:
                raise ReGraphError(
                    "The attr_dict argument must be a dictionary.")

        new_attrs = safe_deepcopy_dict(attrs)
        if s not in self.nodes():
            raise GraphError("Node '{}' does not exist!".format(s))
        if t not in self.nodes():
            raise GraphError("Node '{}' does not exist!".format(t))
        normalize_attrs(new_attrs)

        if (s, t) in self.edges():
            raise GraphError("Edge '{}'->'{}' already exists!".format(s, t))
        self._graph.add_edge(s, t, **new_attrs)
Exemplo n.º 2
0
    def clone_node(self, node_id, name=None):
        """Clone node.

        Create a new node, a copy of a node with `node_id`, and reconnect it
        with all the adjacent nodes of `node_id`.

        Parameters
        ----------
        node_id : hashable,
            Id of a node to clone.
        name : hashable, optional
            Id for the clone, if is not specified, new id will be generated.

        Returns
        -------
        new_node : hashable
            Id of the new node corresponding to the clone

        Raises
        ------
        GraphError
            If node wiht `node_id` does not exists or a node with
            `name` (clone's name) already exists.

        """
        if node_id not in self.nodes():
            raise GraphError("Node '{}' does not exist!".format(node_id))

        # generate new name for a clone
        if name is None:
            i = 1
            new_node = str(node_id) + str(i)
            while new_node in self.nodes():
                i += 1
                new_node = str(node_id) + str(i)
        else:
            if name in self.nodes():
                raise GraphError("Node '{}' already exists!".format(name))
            else:
                new_node = name

        self.add_node(new_node, self.get_node(node_id))

        # Connect all the edges
        self.add_edges_from(
            set([(n, new_node) for n, _ in self.in_edges(node_id)
                 if (n, new_node) not in self.edges()]))
        self.add_edges_from(
            set([(new_node, n) for _, n in self.out_edges(node_id)
                 if (new_node, n) not in self.edges()]))

        # Copy the attributes of the edges
        for s, t in self.in_edges(node_id):
            self.set_edge(s, new_node, safe_deepcopy_dict(self.get_edge(s, t)))
        for s, t in self.out_edges(node_id):
            self.set_edge(new_node, t, safe_deepcopy_dict(self.get_edge(s, t)))
        return new_node
Exemplo n.º 3
0
def add_edge(graph, s, t, attrs=None, **attr):
    """Add an edge to a graph.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    s : hashable, source node id.
    t : hashable, target node id.
    attrs : dict
        Edge attributes.

    Raises
    ------
    ReGraphError
        If `attrs` is not a dictionary
    GraphError
        If either one of the nodes does not exist in the graph or
        an edge between `s` and `t` already
        exists.
    """
    # Set up attribute dict (from Networkx to preserve the signature).
    if attrs is None:
        attrs = attr
    else:
        try:
            attrs.update(attr)
        except AttributeError:
            raise ReGraphError(
                "The attr_dict argument must be a dictionary."
            )

    new_attrs = deepcopy(attrs)
    if s not in graph.nodes():
        raise GraphError("Node '%s' does not exist!" % s)
    if t not in graph.nodes():
        raise GraphError("Node '%s' does not exist!" % t)
    normalize_attrs(new_attrs)

    if graph.is_directed():
        if (s, t) in graph.edges():
            raise GraphError(
                "Edge '%s'->'%s' already exists!" %
                (s, t)
            )
        graph.add_edge(s, t, new_attrs)
    else:
        if (s, t) in graph.edges() or (t, s) in graph.edges():
            raise GraphError(
                "Edge '%s'->'%s' already exists!" %
                (s, t)
            )
        graph.add_edge(s, t)
        graph.edge[s][t] = new_attrs
        graph.edge[t][s] = new_attrs
Exemplo n.º 4
0
    def remove_node_attrs(self, node_id, attrs):
        """Remove attrs of a node specified by attrs_dict.

        Parameters
        ----------
        node_id : hashable
            Node whose attributes to remove.
        attrs : dict
            Dictionary with attributes to remove.

        Raises
        ------
        GraphError
            If a node with the specified id does not exist.
        """
        if node_id not in self.nodes():
            raise GraphError("Node '%s' does not exist!" % str(node_id))
        elif attrs is None:
            warnings.warn(
                "You want to remove attrs from '{}' with an empty attrs_dict!".
                format(node_id), GraphAttrsWarning)

        node_attrs = safe_deepcopy_dict(self.get_node(node_id))
        remove_attrs(node_attrs, attrs, normalize=True)
        self.update_node_attrs(node_id, node_attrs)
Exemplo n.º 5
0
def update_edge_attrs(graph, s, t, attrs):
    """Update attributes of an edge.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    s : hashable, source node id.
    t : hashable, target node id.
    attrs : dict
        New attributes to assign to the edge

    Raises
    ------
    GraphError
        If an edge between `s` and `t` does not exist.
    """
    if not graph.has_edge(s, t):
        raise GraphError("Edge '%s->%s' does not exist!" % (str(s), str(t)))
    elif attrs is None:
        warnings.warn(
            "You want to update '%s->%s' attrs with an empty attrs_dict" %
            (str(s), str(t)), GraphAttrsWarning)
    else:
        new_attrs = deepcopy(attrs)
        normalize_attrs(new_attrs)
        graph.edge[s][t] = new_attrs
        if not graph.is_directed():
            graph.edge[t][s] = new_attrs
Exemplo n.º 6
0
    def set_node_attrs(self, node_id, attrs, normalize=True, update=True):
        """Set node attrs.

        Parameters
        ----------
        node_id : hashable
            Id of the node to update
        attrs : dict
            Dictionary with new attributes to set
        normalize : bool, optional
            Flag, when set to True attributes are normalized to be set-valued.
            True by default
        update : bool, optional
            Flag, when set to True attributes whose keys are not present
            in attrs are removed, True by default

        Raises
        ------
        GraphError
            If a node `node_id` does not exist.
        """
        if node_id not in self.nodes():
            raise GraphError("Node '{}' does not exist!".format(node_id))

        node_attrs = safe_deepcopy_dict(self.get_node(node_id))
        set_attrs(node_attrs, attrs, normalize, update)
        self.update_node_attrs(node_id, node_attrs, normalize)
Exemplo n.º 7
0
def update_node_attrs(graph, node_id, attrs):
    """Update attributes of a node.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    node_id : hashable, node to update.
    attrs : dict
        New attributes to assign to the node

    Raises
    ------
    GraphError
        If a node with the specified id does not exist.

    """
    new_attrs = deepcopy(attrs)
    if node_id not in graph.nodes():
        raise GraphError("Node '%s' does not exist!" % str(node_id))
    elif new_attrs is None:
        warnings.warn(
            "You want to update '%s' attrs with an empty attrs_dict!" %
            node_id, GraphAttrsWarning)
    else:
        normalize_attrs(new_attrs)
        graph.node[node_id] = new_attrs
Exemplo n.º 8
0
def remove_edge_attrs(graph, s, t, attrs):
    """Remove attrs of an edge specified by attrs.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    s : hashable, source node id.
    t : hashable, target node id.
    attrs : dict
        Dictionary with attributes to remove.

    Raises
    ------
    GraphError
        If an edge between `s` and `t` does not exist.
    """
    if not graph.has_edge(s, t):
        raise GraphError("Edge %s-%s does not exist" % (str(s), str(t)))
    else:
        normalize_attrs(attrs)
        old_attrs = get_edge(graph, s, t)
        for key, value in attrs.items():
            if key in old_attrs:
                new_set = old_attrs[key].difference(value)
                if new_set:
                    old_attrs[key] = new_set
                else:
                    del old_attrs[key]
        set_edge(graph, s, t, old_attrs)
Exemplo n.º 9
0
    def predecessors(self, node_id):
        """Return the set of predecessors."""
        if node_id not in self.nodes():
            raise GraphError(
                "Node '{}' does not exist in the graph".format(node_id))

        return self._graph.predecessors(node_id)
Exemplo n.º 10
0
    def update_edge_attrs(self, s, t, attrs, normalize=True):
        """Update attributes of a node.

        Parameters
        ----------
        s : hashable, source node of the edge to update.
        t : hashable, target node of the edge to update.
        attrs : dict
            New attributes to assign to the node

        """
        if not self._graph.has_edge(s, t):
            raise GraphError("Edge '{}->{}' does not exist!".format(s, t))
        if attrs is None:
            warnings.warn(
                "You want to update '{}->{}' attrs with an empty attrs_dict".
                format(s, t), GraphAttrsWarning)

        if normalize is True:
            normalize_attrs(attrs)
        attrs_to_remove = set()
        for k in self._graph.adj[s][t].keys():
            if k not in attrs.keys():
                attrs_to_remove.add(k)
        self._graph.add_edge(s, t, **attrs)
        for k in attrs_to_remove:
            del self._graph.adj[s][t][k]
Exemplo n.º 11
0
    def update_node_attrs(self, node_id, attrs, normalize=True):
        """Update attributes of a node.

        Parameters
        ----------
        node_id : hashable, node to update.
        attrs : dict
            New attributes to assign to the node

        """
        new_attrs = safe_deepcopy_dict(attrs)
        if node_id not in self.nodes():
            raise GraphError("Node '{}' does not exist!".format(node_id))
        elif new_attrs is None:
            warnings.warn(
                "You want to update '{}' attrs with an empty attrs_dict!".
                format(node_id), GraphAttrsWarning)
        else:
            if normalize is True:
                normalize_attrs(new_attrs)
            attrs_to_remove = set()
            for k in self._graph.nodes[node_id].keys():
                if k not in new_attrs.keys():
                    attrs_to_remove.add(k)
            self._graph.add_node(node_id, **new_attrs)
            for k in attrs_to_remove:
                del self._graph.nodes[node_id][k]
Exemplo n.º 12
0
def set_edge(graph, s, t, attrs):
    """Set edge attrs.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    s : hashable, source node id.
    t : hashable, target node id.
    attrs : dictionary
        Dictionary with attributes to set.

    Raises
    ------
    GraphError
        If an edge between `s` and `t` does not exist.
    """
    new_attrs = deepcopy(attrs)
    if not graph.has_edge(s, t):
        raise GraphError(
            "Edge %s->%s does not exist" % (str(s), str(t)))

    normalize_attrs(new_attrs)
    graph.edge[s][t] = new_attrs
    if not graph.is_directed():
        graph.edge[t][s] = new_attrs
Exemplo n.º 13
0
    def set_edge_attrs(self, s, t, attrs, normalize=True, update=True):
        """Set edge attrs.

        Parameters
        ----------
        attrs : dict
            Dictionary with new attributes to set
        normalize : bool, optional
            Flag, when set to True attributes are normalized to be set-valued.
            True by default
        update : bool, optional
            Flag, when set to True attributes whose keys are not present
            in attrs are removed, True by default

        Raises
        ------
        GraphError
            If an edge between `s` and `t` does not exist.
        """
        if not self.exists_edge(s, t):
            raise GraphError("Edge {}->{} does not exist".format(s, t))

        edge_attrs = safe_deepcopy_dict(self.get_edge(s, t))
        set_attrs(edge_attrs, attrs, normalize, update)
        self.update_edge_attrs(s, t, edge_attrs, normalize=normalize)
Exemplo n.º 14
0
def add_node(graph, node_id, attrs=None):
    """Add a node to a graph.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    node_id : hashable
        Prefix that is prepended to the new unique name.
    attrs : dict, optional
        Node attributes.

    Raises
    -------
    regraph.exceptions.GraphError
        Raises an error if node already exists in the graph.
    """
    new_attrs = deepcopy(attrs)
    if new_attrs is None:
        new_attrs = dict()
    if node_id not in graph.nodes():
        graph.add_node(node_id)
        normalize_attrs(new_attrs)
        graph.node[node_id] = new_attrs
    else:
        raise GraphError("Node '%s' already exists!" % node_id)
Exemplo n.º 15
0
def add_node_attrs(graph, node, attrs):
    """Add new attributes to a node.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    node : hashable
        Id of a node to add attributes to.
    attrs : dict
        Attributes to add.

    Raises
    ------
    GraphError
        If a node with the specified id does not exist.
    """
    if node not in graph.nodes():
        raise GraphError("Node '%s' does not exist!" % str(node))
    normalize_attrs(attrs)
    node_attrs = graph.node[node]
    if node_attrs is None:
        graph.node[node] = copy.deepcopy(attrs)
    else:
        for key in attrs:
            if key in node_attrs:
                # node_attrs[key] = hyb_union(node_attrs[key], attrs_dict[key])
                node_attrs[key] = node_attrs[key].union(attrs[key])
            else:
                node_attrs[key] = attrs[key]
Exemplo n.º 16
0
def remove_node_attrs(graph, node_id, attrs):
    """Remove attrs of a node specified by attrs_dict.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    node_id : hashable
        Node whose attributes to remove.
    attrs : dict
        Dictionary with attributes to remove.

    Raises
    ------
    GraphError
        If a node with the specified id does not exist.
    """
    if node_id not in graph.nodes():
        raise GraphError("Node '%s' does not exist!" % str(node_id))
    elif attrs is None:
        warnings.warn(
            "You want to remove attrs from '%s' with an empty attrs_dict!" %
            node_id, GraphAttrsWarning)
    elif graph.node[node_id] is None:
        warnings.warn("Node '%s' does not have any attribute!" % node_id,
                      GraphAttrsWarning)
    else:
        normalize_attrs(attrs)
        old_attrs = graph.node[node_id]
        for key, value in attrs.items():
            if key in old_attrs:
                new_set = old_attrs[key].difference(value)
                if not new_set:
                    del old_attrs[key]
                else:
                    old_attrs[key] = new_set
Exemplo n.º 17
0
def add_edge_attrs(graph, s, t, attrs):
    """Add attributes of an edge in a graph.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    s : hashable, source node id.
    t : hashable, target node id.
    attrs : dict
        Dictionary with attributes to remove.

    Raises
    ------
    GraphError
        If an edge between `s` and `t` does not exist.
    """
    new_attrs = deepcopy(attrs)
    if not graph.has_edge(s, t):
        raise (GraphError("Edge '%s->%s' does not exist" % (str(s), str(t))))
    elif new_attrs is None:
        pass
    else:
        normalize_attrs(new_attrs)
        edge_attrs = get_edge(graph, s, t)
        for key, value in new_attrs.items():
            if key in edge_attrs:
                edge_attrs[key] = edge_attrs[key].union(value)
            else:
                edge_attrs[key] = value
        set_edge(graph, s, t, edge_attrs)
Exemplo n.º 18
0
def get_relabeled_graph(graph, mapping):
    """Return a graph with node labeling specified in the mapping.

    Similar to networkx.relabel.relabel_nodes:
    https://networkx.github.io/documentation/development/_modules/networkx/relabel.html

    Parameters
    ----------
    graph : networkx.(Di)Graph
    mapping: dict
        A dictionary with keys being old node ids and their values
        being new id's of the respective nodes.

    Returns
    -------
    g : networkx.(Di)Graph
        New graph object isomorphic to the `graph` with the relabled nodes.

    Raises
    ------
    ReGraphError
        If new id's do not define a set of distinct node id's.


    See also
    --------
    regraph.primitives.relabel_nodes
    """
    g = type(graph)()

    old_nodes = set(mapping.keys())

    for old_node in old_nodes:
        try:
            new_node = mapping[old_node]
        except KeyError:
            continue
        try:
            g.add_node(new_node, graph.node[old_node])
        except KeyError:
            raise GraphError("Node '%s' does not exist!" % old_node)

    new_edges = list()
    attributes = dict()
    for s, t in graph.edges():
        new_edges.append((mapping[s], mapping[t]))
        attributes[(mapping[s], mapping[t])] =\
            graph.edge[s][t]

    add_edges_from(g, new_edges)
    for s, t in g.edges():
        if g.is_directed():
            set_edge(g, s, t, attributes[(s, t)])
        else:
            if (s, t) in attributes.keys():
                set_edge(g, s, t, attributes[(s, t)])
            else:
                set_edge(g, s, t, attributes[(t, s)])
    return g
Exemplo n.º 19
0
    def remove_edge(self, s, t):
        """Remove edge from the graph.

        Parameters
        ----------
        graph : networkx.(Di)Graph
        s : hashable, source node id.
        t : hashable, target node id.
        """
        if (s, t) not in self.edges():
            raise GraphError("Edge '{}->{}' does not exist!".format(s, t))
        self._graph.remove_edge(s, t)
Exemplo n.º 20
0
    def remove_node(self, node_id):
        """Remove node.

        Parameters
        ----------
        graph : networkx.(Di)Graph
        node_id : hashable, node to remove.
        """
        if node_id in self.nodes():
            self._graph.remove_node(node_id)
        else:
            raise GraphError("Node '{}' does not exist!".format(node_id))
        return
Exemplo n.º 21
0
def get_relabeled_graph(graph, mapping):
    """Return a graph with node labeling specified in the mapping.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    mapping: dict
        A dictionary with keys being old node ids and their values
        being new id's of the respective nodes.

    Returns
    -------
    g : networkx.(Di)Graph
        New graph object isomorphic to the `graph` with the relabled nodes.

    Raises
    ------
    ReGraphError
        If new id's do not define a set of distinct node id's.


    See also
    --------
    regraph.primitives.relabel_nodes
    """
    g = nx.DiGraph()
    old_nodes = set(mapping.keys())

    for old_node in old_nodes:
        try:
            new_node = mapping[old_node]
        except KeyError:
            continue
        try:
            g.add_node(new_node, **graph.get_node(old_node))
        except KeyError:
            raise GraphError("Node '%s' does not exist!" % old_node)

    new_edges = list()
    attributes = dict()
    for s, t in graph.edges():
        new_edges.append((mapping[s], mapping[t]))
        attributes[(mapping[s], mapping[t])] =\
            graph.get_edge(s, t)

    g.add_edges_from(new_edges)
    for s, t in g.edges():
        nx.set_edge_attributes(g, {(s, t): attributes[(s, t)]})
    return g
Exemplo n.º 22
0
    def add_node(self, node_id, attrs=None):
        """Abstract method for adding a node.

        Parameters
        ----------
        node_id : hashable
            Prefix that is prepended to the new unique name.
        attrs : dict, optional
            Node attributes.
        """
        if attrs is None:
            new_attrs = dict()
        else:
            new_attrs = safe_deepcopy_dict(attrs)
            normalize_attrs(new_attrs)
        if node_id not in self.nodes():
            self._graph.add_node(node_id, **new_attrs)
            return node_id
        else:
            raise GraphError("Node '{}' already exists!".format(node_id))
Exemplo n.º 23
0
def remove_edge(graph, s, t):
    """Remove edge from a graph.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    s : hashable, source node id.
    t : hashable, target node id.

    Raises
    ------
    GraphError
        If edge between `s` and `t` does not exist.

    """
    if graph.is_directed():
        if (s, t) not in graph.edges():
            raise GraphError("Edge '%s->%s' does not exist!" %
                             (str(s), str(t)))
    graph.remove_edge(s, t)
Exemplo n.º 24
0
    def add_node_attrs(self, node, attrs):
        """Add new attributes to a node.

        Parameters
        ----------
        node : hashable
            Id of a node to add attributes to.
        attrs : dict
            Attributes to add.

        Raises
        ------
        GraphError
            If a node `node_id` does not exist.
        """
        if node not in self.nodes():
            raise GraphError("Node '{}' does not exist!".format(node))

        node_attrs = safe_deepcopy_dict(self.get_node(node))
        add_attrs(node_attrs, attrs, normalize=True)
        self.update_node_attrs(node, node_attrs)
Exemplo n.º 25
0
def remove_node(graph, node_id):
    """Remove node.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    node_id : hashable, node to remove.

    Raises
    ------
    GraphError
        If a node with the specified id does not exist.

    """
    if node_id in graph.nodes():
        neighbors = set(graph.__getitem__(node_id).keys())
        neighbors -= {node_id}
        graph.remove_node(node_id)
    else:
        raise GraphError("Node %s does not exist!" % str(node_id))
    return
Exemplo n.º 26
0
    def remove_edge_attrs(self, s, t, attrs):
        """Remove attrs of an edge specified by attrs.

        Parameters
        ----------
        s : hashable
            Source node id.
        t : hashable
            Target node id.
        attrs : dict
            Dictionary with attributes to remove.

        Raises
        ------
        GraphError
            If an edge between `s` and `t` does not exist.
        """
        if not self.exists_edge(s, t):
            raise GraphError("Edge {}->{} does not exist".format(s, t))

        edge_attrs = safe_deepcopy_dict(self.get_edge(s, t))
        remove_attrs(edge_attrs, attrs, normalize=True)
        self.update_edge_attrs(s, t, edge_attrs)
Exemplo n.º 27
0
def merge_nodes(graph,
                nodes,
                node_id=None,
                method="union",
                edge_method="union"):
    """Merge a list of nodes.

    Parameters
    ----------

    graph : nx.(Di)Graph
    nodes : iterable
        Collection of node id's to merge.
    node_id : hashable, optional
        Id of a new node corresponding to the result of merge.
    method : optional
        Method of node attributes merge: if `"union"` the resulting node
        will contain the union of all attributes of the merged nodes,
        if `"intersection"`, the resulting node will contain their
        intersection. Default value is `"union"`.
    edge_method : optional
        Method of edge attributes merge: if `"union"` the edges that were
        merged will contain the union of all attributes,
        if `"intersection"` -- their ntersection. Default value is `"union"`.

    Returns
    -------
    node_id : hashable
        Id of a new node corresponding to the result of merge.

    Raises
    ------
    ReGraphError
        If unknown merging method is provided
    GraphError
        If some nodes from `nodes` do not exist in the graph.

    Examples
    --------

    >>> g = nx.DiGraph()
    >>> add_nodes_from(g, [(1, {"a": 1, "b": 1}), 2, (3, {"a": 3, "c": 3})])
    >>> add_edges_from(g, [(1, 3), (1, 2), (2, 3)])
    >>> merge_nodes(g, [1, 3], "merged_node")
    >>> g.nodes()
    ["merged_node", 2]
    >>> g.edges()
    [("merged_node", "merged_node"), ("merged_node", 2), (2, "merged_node")]
    >>> g.node["merged_node"]
    {"a": {1, 3}, "b": {1}, "c": {3}}

    """
    if len(nodes) == 1:
        if node_id is not None:
            relabel_node(graph, nodes[0], node_id)

    elif len(nodes) > 1:

        if method is None:
            method = "union"

        if edge_method is None:
            method = "union"

        # Generate name for new node
        if node_id is None:
            node_id = "_".join([str(n) for n in nodes])
        elif node_id in graph.nodes() and (node_id not in nodes):
            raise GraphError("New name for merged node is not valid: "
                             "node with name '%s' already exists!" % node_id)

        # Merge data attached to node according to the method specified
        # restore proper connectivity
        if method == "union":
            attr_accumulator = {}
        elif method == "intersection":
            attr_accumulator = deepcopy(graph.node[nodes[0]])
        else:
            raise ReGraphError("Merging method '%s' is not defined!" % method)

        self_loop = False
        self_loop_attrs = {}

        if graph.is_directed():
            source_nodes = set()
            target_nodes = set()

            source_dict = {}
            target_dict = {}
        else:
            neighbors = set()
            neighbors_dict = {}
        all_neighbors = set()

        for node in nodes:
            all_neighbors |= set(graph.__getitem__(node).keys())
            attr_accumulator = merge_attributes(attr_accumulator,
                                                graph.node[node], method)

            if graph.is_directed():
                in_edges = graph.in_edges(node)
                out_edges = graph.out_edges(node)

                # manage self loops
                for s, t in in_edges:
                    if s in nodes:
                        self_loop = True
                        if len(self_loop_attrs) == 0:
                            self_loop_attrs = graph.edge[s][t]
                        else:
                            self_loop_attrs = merge_attributes(
                                self_loop_attrs, graph.edge[s][t], edge_method)

                for s, t in out_edges:
                    if t in nodes:
                        self_loop = True
                        if len(self_loop_attrs) == 0:
                            self_loop_attrs = graph.edge[s][t]
                        else:
                            self_loop_attrs = merge_attributes(
                                self_loop_attrs, graph.edge[s][t], edge_method)

                source_nodes.update(
                    [n if n not in nodes else node_id for n, _ in in_edges])
                target_nodes.update(
                    [n if n not in nodes else node_id for _, n in out_edges])

                for edge in in_edges:
                    if not edge[0] in source_dict.keys():
                        attrs = graph.edge[edge[0]][edge[1]]
                        source_dict.update({edge[0]: attrs})
                    else:
                        attrs = merge_attributes(source_dict[edge[0]],
                                                 graph.edge[edge[0]][edge[1]],
                                                 edge_method)
                        source_dict.update({edge[0]: attrs})

                for edge in out_edges:
                    if not edge[1] in target_dict.keys():
                        attrs = graph.edge[edge[0]][edge[1]]
                        target_dict.update({edge[1]: attrs})
                    else:
                        attrs = merge_attributes(target_dict[edge[1]],
                                                 graph.edge[edge[0]][edge[1]],
                                                 edge_method)
                        target_dict.update({edge[1]: attrs})
            else:
                for n in graph.neighbors(node):
                    if n in nodes:
                        self_loop = True
                        if len(self_loop_attrs) == 0:
                            self_loop_attrs = graph.edge[n][node]
                        else:
                            self_loop_attrs = merge_attributes(
                                self_loop_attrs, graph.edge[n][node],
                                edge_method)

                neighbors.update(
                    [n for n in graph.neighbors(node) if n not in nodes])
                for n in graph.neighbors(node):
                    if n not in nodes:
                        if n not in neighbors_dict.keys():
                            attrs = graph.edge[n][node]
                            neighbors_dict.update({n: attrs})
                        else:
                            attrs = merge_attributes(neighbors_dict[n],
                                                     graph.edge[n][node],
                                                     edge_method)
                            neighbors_dict.update({n: attrs})

            graph.remove_node(node)
            all_neighbors -= {node}

        add_node(graph, node_id, attr_accumulator)
        all_neighbors.add(node_id)

        if graph.is_directed():
            if self_loop:
                add_edges_from(graph, [(node_id, node_id)])
                graph.edge[node_id][node_id] = self_loop_attrs
            for n in source_nodes:
                if not exists_edge(graph, n, node_id):
                    add_edge(graph, n, node_id)
            for n in target_nodes:
                if not exists_edge(graph, node_id, n):
                    add_edge(graph, node_id, n)

            # Attach accumulated attributes to edges
            for node, attrs in source_dict.items():
                if node not in nodes:
                    graph.edge[node][node_id] = attrs
            for node, attrs in target_dict.items():
                if node not in nodes:
                    graph.edge[node_id][node] = attrs
        else:
            if self_loop:
                add_edges_from(graph, [(node_id, node_id)])
                graph.edge[node_id][node_id] = self_loop_attrs

            add_edges_from(graph, [(n, node_id) for n in neighbors])

            # Attach accumulated attributes to edges
            for node, attrs in neighbors_dict.items():
                if node not in nodes:
                    graph.edge[node][node_id] = attrs
                    graph.edge[node_id][node] = attrs

        return node_id
Exemplo n.º 28
0
    def get_relabeled_graph(self, mapping, raw=False):
        """Return a graph with node labeling specified in the mapping.

        Parameters
        ----------
        graph : networkx.(Di)Graph
        mapping: dict
            A dictionary with keys being old node ids and their values
            being new id's of the respective nodes.

        Returns
        -------
        g : networkx.(Di)Graph
            New graph object isomorphic to the `graph` with the relabled nodes.

        Raises
        ------
        ReGraphError
            If new id's do not define a set of distinct node id's.


        See also
        --------
        regraph.primitives.relabel_nodes
        """
        g = nx.DiGraph()
        old_nodes = set(mapping.keys())

        for old_node in old_nodes:
            try:
                new_node = mapping[old_node]
            except KeyError:
                pass
            try:
                g.add_node(new_node, **self.get_node(old_node))
            except KeyError:
                raise GraphError("Node '%s' does not exist!" % old_node)

        new_edges = list()
        attributes = dict()
        for s, t in self.edges():
            new_s = None
            new_t = None
            try:
                new_s = mapping[s]
            except KeyError:
                pass
            try:
                new_t = mapping[t]
            except KeyError:
                pass
            if new_s and new_t:
                new_edges.append((new_s, new_t))
                attributes[(new_s, new_t)] = self.get_edge(s, t)

        g.add_edges_from(new_edges)
        for s, t in g.edges():
            for k, v in attributes[(s, t)].items():
                g.adj[s][t][k] = v
        if not raw:
            new_obj = NXGraph()
            new_obj._graph = g
            return new_obj
        return g
Exemplo n.º 29
0
def clone_node(graph, node_id, name=None):
    """Clone node.

    Create a new node, a copy of a node with `node_id`, and reconnect it
    with all the adjacent nodes of `node_id`.

    Parameters
    ----------
    graph : networkx.(Di)Graph
    node_id : id of a node to clone.
    name : id for the clone, optional
        If is not specified, new id will be generated.

    Returns
    -------
    new_node : hashable, clone's id

    Raises
    ------
    GraphError
        If node wiht `node_id` does not exists or a node with
        `name` (clone's name) already exists.

    Examples
    --------
    >>> g = nx.DiGraph()
    >>> add_nodes_from(g, [1, 2, 3])
    >>> add_edges_from(g, [(1, 2), (3, 2)])
    >>> clone_node(g, 2, "2_clone")
    >>> g.nodes()
    [1, 2, "2_clone", 3]
    >>> g.edges()
    [(1, 2), (1, "2_clone"), (3, 2), (3, "2_clone")]

    """
    if node_id not in graph.nodes():
        raise GraphError("Node '%s' does not exist!" % str(node_id))

    # generate new name for a clone
    if name is None:
        i = 1
        new_node = str(node_id) + str(i)
        while new_node in graph.nodes():
            i += 1
            new_node = str(node_id) + str(i)
    else:
        if name in graph.nodes():
            raise GraphError("Node '%s' already exists!" % str(name))
        else:
            new_node = name

    graph.add_node(new_node, deepcopy(graph.node[node_id]))

    # Connect all the edges
    if graph.is_directed():
        add_edges_from(graph,
                       [(n, new_node) for n, _ in graph.in_edges(node_id)])
        add_edges_from(graph,
                       [(new_node, n) for _, n in graph.out_edges(node_id)])

        # Copy the attributes of the edges
        for s, t in graph.in_edges(node_id):
            graph.edge[s][new_node] = deepcopy(graph.edge[s][t])
        for s, t in graph.out_edges(node_id):
            graph.edge[new_node][t] = deepcopy(graph.edge[s][t])
    else:
        add_edges_from(graph,
                       [(n, new_node) for n in graph.neighbors(node_id)])

        # Copy the attributes of the edges
        for n in graph.neighbors(node_id):
            graph.edge[new_node][n] = deepcopy(graph.edge[n][node_id])
            graph.edge[n][new_node] = graph.edge[new_node][n]

    return new_node
Exemplo n.º 30
0
    def merge_nodes(self,
                    nodes,
                    node_id=None,
                    method="union",
                    edge_method="union"):
        """Merge a list of nodes.

        Parameters
        ----------

        nodes : iterable
            Collection of node id's to merge.
        node_id : hashable, optional
            Id of a new node corresponding to the result of merge.
        method : optional
            Method of node attributes merge: if `"union"` the resulting node
            will contain the union of all attributes of the merged nodes,
            if `"intersection"`, the resulting node will contain their
            intersection. Default value is `"union"`.
        edge_method : optional
            Method of edge attributes merge: if `"union"` the edges that were
            merged will contain the union of all attributes,
            if `"intersection"` -- their ntersection.
            Default value is `"union"`.
        """
        if len(nodes) > 1:

            if method is None:
                method = "union"

            if edge_method is None:
                method = "union"

            # Generate name for new node
            if node_id is None:
                node_id = "_".join(sorted([str(n) for n in nodes]))
                if node_id in self.nodes():
                    node_id = self.generate_new_node_id(node_id)

            elif node_id in self.nodes() and (node_id not in nodes):
                raise GraphError("New name for merged node is not valid: "
                                 "node with name '%s' already exists!" %
                                 node_id)
            # Merge data attached to node according to the method specified
            # restore proper connectivity
            if method == "union":
                attr_accumulator = {}
            elif method == "intersection":
                attr_accumulator = safe_deepcopy_dict(self.get_node(nodes[0]))
            else:
                raise ReGraphError(
                    "Merging method '{}' is not defined!".format(method))

            self_loop = False
            self_loop_attrs = {}

            source_nodes = set()
            target_nodes = set()

            source_dict = {}
            target_dict = {}

            for node in nodes:
                attr_accumulator = merge_attributes(attr_accumulator,
                                                    self.get_node(node),
                                                    method)

                in_edges = self.in_edges(node)
                out_edges = self.out_edges(node)

                # manage self loops
                for s, t in in_edges:
                    if s in nodes:
                        self_loop = True
                        if len(self_loop_attrs) == 0:
                            self_loop_attrs = self.get_edge(s, t)
                        else:
                            self_loop_attrs = merge_attributes(
                                self_loop_attrs, self.get_edge(s, t),
                                edge_method)

                for s, t in out_edges:
                    if t in nodes:
                        self_loop = True
                        if len(self_loop_attrs) == 0:
                            self_loop_attrs = self.get_edge(s, t)
                        else:
                            self_loop_attrs = merge_attributes(
                                self_loop_attrs, self.get_edge(s, t),
                                edge_method)

                source_nodes.update(
                    [n if n not in nodes else node_id for n, _ in in_edges])
                target_nodes.update(
                    [n if n not in nodes else node_id for _, n in out_edges])

                for edge in in_edges:
                    if not edge[0] in source_dict.keys():
                        attrs = self.get_edge(edge[0], edge[1])
                        source_dict.update({edge[0]: attrs})
                    else:
                        attrs = merge_attributes(
                            source_dict[edge[0]],
                            self.get_edge(edge[0], edge[1]), edge_method)
                        source_dict.update({edge[0]: attrs})

                for edge in out_edges:
                    if not edge[1] in target_dict.keys():
                        attrs = self.get_edge(edge[0], edge[1])
                        target_dict.update({edge[1]: attrs})
                    else:
                        attrs = merge_attributes(
                            target_dict[edge[1]],
                            self.get_edge(edge[0], edge[1]), edge_method)
                        target_dict.update({edge[1]: attrs})
                self.remove_node(node)

            self.add_node(node_id, attr_accumulator)

            if self_loop:
                self.add_edges_from([(node_id, node_id)])
                self.set_edge(node_id, node_id, self_loop_attrs)
            for n in source_nodes:
                if not self.exists_edge(n, node_id):
                    self.add_edge(n, node_id)
            for n in target_nodes:
                if not self.exists_edge(node_id, n):
                    self.add_edge(node_id, n)

            # Attach accumulated attributes to edges
            for node, attrs in source_dict.items():
                if node not in nodes:
                    self.set_edge(node, node_id, attrs)
            for node, attrs in target_dict.items():
                if node not in nodes:
                    self.set_edge(node_id, node, attrs)

            return node_id
        else:
            raise ReGraphError(
                "More than two nodes should be specified for merging!")