def _gnx_vec(self, gnx: nx.Graph, node_order):
        final_vec = []
        if self._deg:
            degrees = gnx.degree(gnx.nodes)
            final_vec.append(
                np.matrix([np.log(degrees[d] + 1e-3) for d in node_order]).T)
        if self._in_deg and gnx.is_directed():
            degrees = gnx.in_degree(gnx.nodes)
            final_vec.append(
                np.matrix([np.log(degrees[d] + 1e-3) for d in node_order]).T)
        if self._out_deg and gnx.is_directed():
            degrees = gnx.out_degree(gnx.nodes)
            final_vec.append(
                np.matrix([np.log(degrees[d] + 1e-3) for d in node_order]).T)

        # TODO ========================== TODO handle external features
        # if self._is_external_data and self._external_data.is_value:
        #     final_vec.append(np.matrix([self._external_data.value_feature(gnx_id, d) for d in node_order]))
        # TODO ========================== TODO ========================

        if self._is_ftr:
            gnx_dir_path = os.path.join(self._gnx_features_pkl_dir)
            if not os.path.exists(gnx_dir_path):
                os.mkdir(gnx_dir_path)
            raw_ftr = GraphFeatures(gnx,
                                    self._ftr_meta,
                                    dir_path=gnx_dir_path,
                                    is_max_connected=False,
                                    logger=PrintLogger("logger"))
            raw_ftr.build(should_dump=True)  # build features
            final_vec.append(
                FeaturesProcessor(raw_ftr).as_matrix(norm_func=log_norm))

        return np.hstack(final_vec)
def erdos_renyi_like(G: nx.Graph):
    number_of_nodes = G.number_of_nodes()
    possible_connections = number_of_nodes * (number_of_nodes - 1)
    if not G.is_directed():
        possible_connections /= 2

    probability_of_connection = G.number_of_edges() / possible_connections

    G_erdos_renyi = nx.gnp_random_graph(number_of_nodes,
                                        probability_of_connection,
                                        directed=G.is_directed())

    return (G_erdos_renyi)
Beispiel #3
0
def _get_shortest_path_between_subgraphs_helper(
    graph: nx.Graph,
    a: nx.Graph,
    b: nx.Graph,
) -> List[List[Any]]:
    """Calculate the shortest path(s) between disconnected sub-graphs ``a`` and ``b`` through ``graph``.

    :param graph: A graph
    :param a: A sub-graph of :code:`graph`, disjoint from :code:`b`
    :param b: A sub-graph of :code:`graph`, disjoint from :code:`a`
    :return: A list of the shortest paths between the two sub-graphs
    """
    if graph.is_directed():
        shortest_paths = [
            shortest_path for na, nb in itt.product(a, b) for shortest_path in
            (  # do it going both ways because it's directed
                nx.shortest_path(graph, na, nb),
                nx.shortest_path(graph, nb, na),
            )
        ]
    else:
        shortest_paths = [
            nx.shortest_path(graph, na, nb) for na, nb in itt.product(a, b)
        ]

    min_len = min(map(len, shortest_paths))
    return [
        shortest_path for shortest_path in shortest_paths
        if len(shortest_path) == min_len
    ]
Beispiel #4
0
def convert_graph_to_db_dict(graph: nx.Graph, with_weights=False, cast_to_directed=False):
    """
    Encapsulates the convert_graph_to_db_format function by wrapping the returned lists with a dictionary.
    The dictionary has the keys 'indices','neighbors' , ['weights'].

    :param graph: the nx graph to convert
    :param with_weights: whether to return a weights list
    :param cast_to_directed: whether to process the graph as a directed one.
    :return: a dictionary with the specified keys and the lists as values.
    """
    ret_dict = {}
    if with_weights:
        i, n, w = convert_graph_to_db_format(graph, with_weights, cast_to_directed)
        ret_dict['indices'] = i
        ret_dict['neighbors'] = n
        ret_dict['weights'] = w
        ret_dict['with_weights'] = True
    else:
        i, n = convert_graph_to_db_format(graph, with_weights, cast_to_directed)
        ret_dict['indices'] = i
        ret_dict['neighbors'] = n
        ret_dict['with_weights'] = False

    ret_dict['directed'] = graph.is_directed()
    return ret_dict
Beispiel #5
0
def remove_edges_randomly(graph: nx.Graph, *, frac=None, number=None, keep_connected=False):
    """
    Removes edges randomly from the given graph. You must either give
    `frac` or `number` to specify how many edges should be removed.

    The parameter `keep_connected` can be used to ensure that all nodes remain
    connected. Some embedding algorithms (DAOR) lead to subsequent problems in
    later tasks otherwise.

    A set of all edges that were removed is returned. The graph is altered in
    place.
    """
    number = number_random_edges(graph, frac=frac, number=number)

    connected = nx.is_weakly_connected if graph.is_directed() else nx.is_connected
    if keep_connected and not connected(graph):
        raise RuntimeError("The graph is already not connected before removing any edges.")

    removed_edges = set()
    infeasible_edges = set()
    while len(removed_edges) < number:
        to_remove = sample(graph.edges - infeasible_edges, number - len(removed_edges))

        for edge in to_remove:
            edge_data = graph[edge[0]][edge[1]]
            graph.remove_edge(*edge)
            if keep_connected and not connected(graph):
                # The removed edge made the graph disconnected, add the edge
                # again and re-sample a new edge as replacement later.
                graph.add_edge(*edge, **edge_data)
                infeasible_edges.add(edge)
            else:
                removed_edges.add(edge)

    return removed_edges
 def _convert_gnx_to_int_based(self, gnx: nx.Graph):
     nodes = {node: i for i, node in enumerate(gnx.nodes)}
     new_gnx = nx.DiGraph() if gnx.is_directed() else nx.Graph()
     for u, v in gnx.edges:
         new_gnx.add_edge(nodes[u], nodes[v])
     return new_gnx, [
         n for n, i in sorted(nodes.items(), key=lambda x: x[1])
     ]
Beispiel #7
0
def assert_is_undirected(graph: nx.Graph):
    """
    Asserts that an object is an undirected graph

    :param graph: Graph to check
    :raises ValueError: If a graph is not an undirected graph
    """
    if graph.is_directed():
        raise ValueError("graph must be an undirected graph")
Beispiel #8
0
def graph_info(g: nx.Graph, display_using: Callable = print) -> None:
    """Display basic information about a graph.

    Note: the connected component structure is calculated using
    the undirected equivalent of the graph.

    :param g: networkx Graph
    :param display_using: function to use to display
    """

    graph_type = repr(type(g))
    info = f'{graph_type}\n'
    info += '-' * len(graph_type) + '\n'

    info += f'Nodes, Edges\t\t{g.number_of_nodes()}, {g.number_of_edges()}\n'

    is_directed = g.is_directed()
    info += f'Directed\t\t{is_directed}\n'

    connected_components = sorted(nx.connected_components(g.to_undirected()),
                                  key=len)
    n_connected_components = len(connected_components)
    is_connected = n_connected_components == 1
    info += f'Connected\t\t{is_connected}\n'

    if not is_connected:
        info += f'Number of components\t{n_connected_components}\n'
        info += f'Max component size\t{len(max(connected_components, key=len))}\n'

    adj_mx = nx.to_scipy_sparse_matrix(g)

    if is_directed:
        out_degree = adj_mx.sum(axis=1)
        info += f'Degree range (out)\t{out_degree.min()} to {out_degree.max()}\n'

        in_degree = adj_mx.sum(axis=0)
        info += f'Degree range (in)\t{in_degree.min()} to {in_degree.max()}\n'

    else:
        degree = adj_mx.sum(axis=0)
        info += f'Degree range\t\t{degree.min()} to {degree.max()}\n'

    node_label_types = repr(list(set(map(type, g.nodes))))
    info += f'Node label types\t{node_label_types}\n'

    for u in g.nodes:
        node_attributes = repr(list(g.nodes[u]))
        info += f'Node attributes\t\t{node_attributes}\n'
        break

    for u, v in g.edges:
        edge_attributes = repr(list(g[u][v]))
        info += f'Edge attributes\t\t{edge_attributes}'
        break

    display_using(info)
def draw_graph(gnx: nx.Graph):
    pos = nx.layout.spring_layout(gnx)
    nx.draw_networkx_nodes(gnx, pos)
    if gnx.is_directed():
        nx.draw_networkx_edges(gnx, pos, arrowstyle='->', arrowsize=30)
    else:
        nx.draw_networkx_edges(gnx, pos)

    nx.draw_networkx_labels(gnx, pos, font_size=10, font_family='sans-serif')

    plt.axis('off')
    plt.show()
Beispiel #10
0
def largest_connected_component(G: nx.Graph, connection='weak'):
    if G.is_directed():
        if connection == 'weak':
            largest_connected_component_nodes =\
                max(nx.weakly_connected_components(G), key=len)
        elif connection == 'strong':
            largest_connected_component_nodes = \
                max(nx.strongly_connected_components(G), key=len)
        else:
            raise Exception('Invalid connection: "' + connection + '".')

    else:
        largest_connected_component_nodes = \
            max(nx.connected_components(G), key=len)

    return G.subgraph(largest_connected_component_nodes).copy()
Beispiel #11
0
def get_distinct_cliques(G: nx.Graph, n=None):
    if G.is_directed():
        G = G.to_undirected()

    cliques = sorted(list(nx.find_cliques(G)),
                     key=lambda c: len(c),
                     reverse=True)
    nodes = set()
    distinct_cliques = []
    for c in cliques:
        if n is not None and len(distinct_cliques) >= n:
            break
        if len(nodes.intersection(set(c))) == 0:
            nodes = nodes.union(set(c))
            distinct_cliques.append(c)
    return distinct_cliques
Beispiel #12
0
def reeb_process(gr: nx.Graph) -> Sequence[Tuple[int, int, int, int]]:
    # """
    # Convert the Reeb graph from NetworkX object to the preferred representation
    # for the Chinese postman algorithm.

    # Format:
    # [(crit pt on left, crit pt on right, cell #, pixels in cell), ...]
    # """

    assert gr.is_directed() and gr.is_multigraph(), "Wrong kind of graph"

    out = []

    for tail, head, data in gr.edges(data=True):
        out.append((tail, head, data["cell"], data["weight"]))

    return out
Beispiel #13
0
def _nx_to_edge_list(
    graph: nx.Graph,
    identifier: _IdentityMapper,
    is_weighted: Optional[bool],
    weight_attribute: str,
    weight_default: float,
) -> Tuple[int, List[Tuple[str, str, float]]]:
    check_argument(
        isinstance(graph, nx.Graph)
        and not (graph.is_directed() or graph.is_multigraph()),
        "Only undirected non-multi-graph networkx graphs are supported",
    )
    native_safe: List[Tuple[str, str, float]] = []
    edge_iter = (graph.edges(data=weight_attribute) if is_weighted is True else
                 graph.edges(data=weight_attribute, default=weight_default))
    for source, target, weight in edge_iter:
        source_str = identifier(source)
        target_str = identifier(target)
        native_safe.append((source_str, target_str, float(weight)))
    return graph.number_of_nodes(), native_safe
Beispiel #14
0
def _assertions(
    graph: nx.Graph,
    partitions: Dict[Any, int],
    weight_attribute: str,
    resolution: float,
) -> None:
    if not isinstance(graph, nx.Graph):
        raise TypeError("graph must be a networkx undirected graph")
    if graph.is_directed():
        raise ValueError("The graph must be an undirected graph")
    if graph.is_multigraph():
        raise ValueError(
            "Multigraphs must be provided in the form of a non multigraph.")
    if not nx.is_weighted(graph, weight=weight_attribute):
        raise ValueError(
            f"weight_attribute {weight_attribute} not found on every edge in the provided graph"
        )
    if not isinstance(partitions, dict):
        raise TypeError("partitions must be a dictionary")
    if not isinstance(resolution, float):
        raise TypeError("resolution must be a float")
Beispiel #15
0
def get_dead_ends(graph: nx.Graph, node_filter=no_filter, only_strict=False) -> list:
    """Return the list of dead end in the given graph. A dead end is defined as a node having only one neighbor. For
    directed graphs, a strict dead end is a node having a unique predecessor and no successors. A weak dead end is a
    node having a unique predecessor that is also its unique successor.

    Parameters
    ----------
    graph : nx.Graph
        Graph to parse.
    node_filter :
        Evaluates to true if a node can be considered as dead end, false otherwise. (Default value = no_filter)
    only_strict :
        If true, remove only strict dead ends. Used only for directed graphs. (Default value = False)

    Returns
    -------
    list
        List of node name that are dead ends.
    """
    if graph.is_directed():
        dead_ends = []
        for n in graph.nodes():
            if not node_filter(n):
                continue
            nb_predecessors = len(graph.pred[n])
            if nb_predecessors != 1:
                continue
            nb_successors = len(graph.succ[n])
            if nb_successors == 0:
                dead_ends.append(n)
            elif not only_strict and nb_successors == 1:
                pred = next(iter(graph.pred[n]))
                if pred in graph.successors(n):
                    dead_ends.append(n)
        return dead_ends
    else:
        return [n for n in graph.nodes() if node_filter(n) and len(graph.neighbors(n)) == 1]
Beispiel #16
0
def sample_negative_edges(graph: nx.Graph, *, frac=None, number=None, exclude=None):
    number = number_random_edges(graph, frac=frac, number=number)
    if exclude is None:
        exclude = set()

    negative_edges = set()
    while len(negative_edges) < number:
        us = choices(list(graph.nodes), k=number - len(negative_edges))
        vs = choices(list(graph.nodes), k=number - len(negative_edges))

        for u, v in zip(us, vs):
            if u == v:
                # we don't want to generate self-loops
                continue
            if v < u and not graph.is_directed():
                # for undirected graphs don't consider edges in both directions
                continue
            if graph.has_edge(u, v):
                continue
            if (u, v) in exclude:
                continue
            negative_edges.add((u, v))

    return negative_edges
Beispiel #17
0
def clustering_coefficient(g: nx.Graph):
    if g.is_directed():
        print("clustering coefficient not implemented for directed graphs")
    else:
        print(f"clustering coefficient: {str(nx.average_clustering(g))}")
Beispiel #18
0
class NetworkXGraphBackend(GenericGraphBackend):
    """
    A wrapper for NetworkX as the backend of a graph.

    TESTS::

        sage: import sage.graphs.base.graph_backends

    """

    _nxg = None

    def __init__(self, N=None):
        """
        Initialize the backend with NetworkX graph N.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_edges([],True)
            <generator object iterator_edges at ...>
        """
        if N is None:
            import networkx
            N = networkx.MultiGraph()
        self._nxg = N

        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

    def add_edge(self, u, v, l, directed):
        """
        Add an edge (u,v) to self, with label l.  If directed is True, this is
        interpreted as an arc from u to v.

        INPUT:

        - ``u,v`` -- vertices
        - ``l`` -- edge label
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_edge(1,2,'a',True)
        """

        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if u is None: u = self.add_vertex(None)
        if v is None: v = self.add_vertex(None)

        if l:
            self._nxg.add_edge(u, v, weight=l)
        else:
            self._nxg.add_edge(u, v)

    def add_edges(self, edges, directed):
        """
        Add a sequence of edges to self.  If directed is True, these are
        interpreted as arcs.

        INPUT:

        - ``edges`` -- list/iterator of edges to be added.
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_edges([],True)
        """
        for e in edges:
            try:
                u, v, l = e
            except ValueError:
                u, v = e
                l = None
            self.add_edge(u, v, l, directed)

    def add_vertex(self, name):
        """
        Add a labelled vertex to self.

        INPUT:

        - ``name``: vertex label

        OUTPUT:

        If ``name=None``, the new vertex name is returned. ``None`` otherwise.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertex(0)
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        retval = None
        if name is None:  # then find an integer to use as a key
            i = 0
            while self.has_vertex(i):
                i = i + 1
            name = i
            retval = name

        self._nxg.add_node(name)

        return retval

    def add_vertices(self, vertices):
        """
        Add labelled vertices to self.

        INPUT:

        - ``vertices``: iterator of vertex labels. A new label is created, used and returned in
          the output list for all ``None`` values in ``vertices``.

        OUTPUT:

        Generated names of new vertices if there is at least one ``None`` value
        present in ``vertices``. ``None`` otherwise.

        EXAMPLES::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertices([1,2,3])
            sage: G.add_vertices([4,None,None,5])
            [0, 6]
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        vertices = list(vertices)
        nones = vertices.count(None)
        vertices = [v for v in vertices if v is not None]
        self._nxg.add_nodes_from(vertices)

        new_names = []
        i = 0
        while nones > 0:
            while self.has_vertex(i):
                i += 1
            self._nxg.add_node(i)
            new_names.append(i)

            nones -= 1
            i += 1

        return new_names if new_names != [] else None

    def degree(self, v, directed):
        """
        Returns the total number of vertices incident to v.

        INPUT:

        - ``v`` -- a vertex label
        - ``directed`` -- boolean

        OUTPUT:

            degree of v

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertices(range(3))
            sage: G.degree(1, False)
            0
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.degree(v)

    def del_edge(self, u, v, l, directed):
        """
        Deletes the edge (u,v) with label l.

        INPUT:

        - ``u,v`` -- vertices
        - ``l`` -- edge label
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.del_edge(1,2,'a',True)
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        import networkx
        try:
            if self._nxg.is_multigraph():
                for k, d in self._nxg.edge[u][v].iteritems():
                    if d.get('weight', None) == l:
                        self._nxg.remove_edge(u, v, k)
                        break
            else:
                if l is None or self._nxg.edge[u][v].get('weight', None) == l:
                    self._nxg.remove_edge(u, v)
        except (KeyError, networkx.NetworkXError):
            pass

    def del_vertex(self, v):
        """
        Delete a labelled vertex in self.

        INPUT:

        - ``v`` -- vertex label

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.del_vertex(0)
            Traceback (most recent call last):
            ...
            NetworkXError: The node 0 is not in the graph.
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        self._nxg.remove_node(v)

    def del_vertices(self, vertices):
        """
        Delete labelled vertices in self.

        INPUT:

        - ``vertices`` -- iterator of vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.del_vertices([1,2,3])
            Traceback (most recent call last):
            ...
            NetworkXError: The node 1 is not in the graph.
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        for v in vertices:
            self._nxg.remove_node(v)

    def get_edge_label(self, u, v):
        """
        Returns the edge label of (u,v).

        INPUT:

        - ``u,v`` -- vertex labels

        OUTPUT:
            label of (u,v)

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.get_edge_label(1,2)
            Traceback (most recent call last):
            ...
            NetworkXError: Edge (1,2) requested via get_edge_label does not exist.
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        try:
            E = self._nxg.edge[u][v]
        except KeyError:
            from networkx import NetworkXError
            raise NetworkXError(
                "Edge (%s,%s) requested via get_edge_label does not exist." %
                (u, v))

        if self._nxg.is_multigraph():
            return [e.get('weight', None) for e in E.itervalues()]
        else:
            return E.get('weight', None)

    def has_edge(self, u, v, l):
        """
        True if self has an edge (u,v) with label l.

        INPUT:

        - ``u,v`` -- vertex labels
        - ``l`` -- label

        OUTPUT:
            boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.has_edge(1,2,'a')
            False
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if not self._nxg.has_edge(u, v):
            return False
        if l is None:
            return True
        if self._nxg.is_multigraph():
            return any(
                e.get('weight', None) == l
                for e in self._nxg.adj[u][v].itervalues())
        else:
            return any(e == l for e in self._nxg.adj[u][v].itervalues())

    def has_vertex(self, v):
        """
        True if self has a vertex with label v.

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.has_vertex(0)
            False
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.has_node(v)

    def iterator_edges(self, vertices, labels):
        """
        Iterate over the edges incident to a sequence of vertices. Edges are
        assumed to be undirected.

        INPUT:

        - ``vertices`` -- a list of vertex labels
        - ``labels`` -- boolean

        OUTPUT:
            a generator which yields edges, with or without labels
            depending on the labels parameter.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_edges([],True)
            <generator object iterator_edges at ...>
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if labels:
            for u, v, d in self._nxg.edges_iter(data=True):
                if u in vertices or v in vertices:
                    yield (u, v, d.get('weight', None))
        else:
            for u, v in self._nxg.edges_iter():
                if u in vertices or v in vertices:
                    yield (u, v)

    def _iterator_in_edges_with_labels(self, vertices):
        """
        Iterate over the incoming edges incident to a sequence of vertices.
        Special case, only for internal use.

        EXAMPLE::

            sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend
            sage: sorted(list(g.iterator_in_edges([0,1], True)))
            [(0, 1, None), (1, 0, None), (2, 1, None), (4, 0, None), (5, 0, None), (6, 1, None)]
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        for u, v, d in self._nxg.in_edges_iter(vertices, data=True):
            yield (u, v, d.get('weight', None))

    def iterator_in_edges(self, vertices, labels):
        """
        Iterate over the incoming edges incident to a sequence of vertices.

        INPUT:

        - ``vertices`` -- a list of vertex labels
        - ``labels`` -- boolean

        OUTPUT:
            a generator which yields edges, with or without labels
            depending on the labels parameter.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: i = G.iterator_in_edges([],True)
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if self._nxg.is_directed():
            if labels:
                return self._iterator_in_edges_with_labels(vertices)
            else:
                return self._nxg.in_edges_iter(vertices)
        else:
            return self.iterator_edges(vertices, labels)

    def _iterator_out_edges_with_labels(self, vertices):
        """
        Iterate over the outbound edges incident to a sequence of vertices.
        Special case, only for internal use.

        EXAMPLE::

            sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend
            sage: sorted(list(g.iterator_out_edges([0,1], True)))
            [(0, 1, None), (0, 4, None), (0, 5, None), (1, 0, None), (1, 2, None), (1, 6, None)]
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        for u, v, d in self._nxg.out_edges_iter(vertices, data=True):
            yield (u, v, d.get('weight', None))

    def iterator_out_edges(self, vertices, labels):
        """
        Iterate over the outbound edges incident to a sequence of vertices.

        INPUT:

        - ``vertices`` -- a list of vertex labels
        - ``labels`` -- boolean

        OUTPUT:
            a generator which yields edges, with or without labels
            depending on the labels parameter.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: i = G.iterator_out_edges([],True)
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if self._nxg.is_directed():
            if labels:
                return self._iterator_out_edges_with_labels(vertices)
            else:
                return self._nxg.out_edges_iter(vertices)
        else:
            return self.iterator_edges(vertices, labels)

    def iterator_nbrs(self, v):
        """
        Iterate over the vertices adjacent to v.

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            a generator which yields vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertex(0)
            sage: G.iterator_nbrs(0)
            <dictionary-keyiterator object at ...>
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.neighbors_iter(v)

    def iterator_in_nbrs(self, v):
        """
        Iterate over the vertices u such that the edge (u,v) is in self
        (that is, predecessors of v).

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            a generator which yields vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_in_nbrs(0)
            Traceback (most recent call last):
            ...
            AttributeError: 'MultiGraph' object has no attribute 'predecessors_iter'
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.predecessors_iter(v)

    def iterator_out_nbrs(self, v):
        """
        Iterate over the vertices u such that the edge (v,u) is in self
        (that is, successors of v).

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            a generator which yields vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_out_nbrs(0)
            Traceback (most recent call last):
            ...
            AttributeError: 'MultiGraph' object has no attribute 'successors_iter'
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.successors_iter(v)

    def iterator_verts(self, verts):
        """
        Iterate over the vertices v with labels in verts.

        INPUT:

        - ``vertex`` -- vertex labels

        OUTPUT:
            a generator which yields vertices

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_verts(0)
            <generator object bunch_iter at ...>
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.nbunch_iter(verts)

    def loops(self, new=None):
        """
        Get/set whether or not self allows loops.

        INPUT:

        - ``new`` -- can be a boolean (in which case it sets the value) or
          ``None``, in which case the current value is returned. It is set to
          ``None`` by default.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.loops(True)
            sage: G.loops(None)
            True
        """
        if new is None:
            return self._loops
        if new:
            self._loops = True
        else:
            self._loops = False

    def multiple_edges(self, new=None):
        """
        Get/set whether or not self allows multiple edges.

        INPUT:

        - ``new`` -- can be a boolean (in which case it sets the value) or
          ``None``, in which case the current value is returned. It is set to
          ``None`` by default.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.multiple_edges(True)
            sage: G.multiple_edges(None)
            True
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        from networkx import Graph, MultiGraph, DiGraph, MultiDiGraph
        if new is None:
            return self._nxg.is_multigraph()
        if new == self._nxg.is_multigraph():
            return
        if new:
            if self._nxg.is_directed():
                self._nxg = MultiDiGraph(self._nxg)
            else:
                self._nxg = MultiGraph(self._nxg)
        else:
            if self._nxg.is_directed():
                self._nxg = DiGraph(self._nxg)
            else:
                self._nxg = Graph(self._nxg)

    def name(self, new=None):
        """
        Get/set name of self.

        INPUT:

        - ``new`` -- can be a string (in which case it sets the value) or
          ``None``, in which case the current value is returned. It is set to
          ``None`` by default.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.name("A NetworkX Graph")
            sage: G.name(None)
            'A NetworkX Graph'
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if new is None:
            return self._nxg.name
        self._nxg.name = new

    def num_edges(self, directed):
        """
        The number of edges in self

        INPUT:

        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.num_edges(True)
            0
            sage: G.num_edges(False)
            0
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.size()

    def num_verts(self):
        """
        The number of vertices in self

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.num_verts()
            0
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        return self._nxg.order()

    def relabel(self, perm, directed):
        """
        Relabel the vertices of self by a permutation.

        INPUT:

        - ``perm`` -- permutation
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.relabel([],False)
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        from networkx import relabel_nodes
        name = self._nxg.name
        self._nxg = relabel_nodes(self._nxg, perm)
        self._nxg.name = name

    def set_edge_label(self, u, v, l, directed):
        """
        Label the edge (u,v) by l.

        INPUT:

        - ``u,v`` -- vertices
        - ``l`` -- edge label
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.set_edge_label(1,2,'a',True)
        """
        try:
            assert (not isinstance(
                self._nxg,
                (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)))
        except AssertionError:
            self._nxg = self._nxg.mutate()

        if not self.has_edge(u, v, None):
            return
        if self.multiple_edges(None):
            self._nxg[u][v].clear()
            self._nxg[u][v][0] = dict(weight=l)
            if directed is False:
                self._nxg[v][u].clear()
                self._nxg[v][u][0] = dict(weight=l)
        else:
            self._nxg[u][v]['weight'] = l
            if directed is False:
                self._nxg[v][u]['weight'] = l
Beispiel #19
0
class NetworkXGraphBackend(GenericGraphBackend):
    """
    A wrapper for NetworkX as the backend of a graph.

    TESTS::

        sage: import sage.graphs.base.graph_backends

    """

    _nxg = None

    def __init__(self, N=None):
        """
        Initialize the backend with NetworkX graph N.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_edges([],True)
            <generator object iterator_edges at ...>
        """
        if N is None:
            import networkx
            N = networkx.MultiGraph()
        self._nxg = N

        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

    def add_edge(self, u, v, l, directed):
        """
        Add an edge (u,v) to self, with label l.  If directed is True, this is
        interpreted as an arc from u to v.

        INPUT:

        - ``u,v`` -- vertices
        - ``l`` -- edge label
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_edge(1,2,'a',True)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if u is None: u = self.add_vertex(None)
        if v is None: v = self.add_vertex(None)

        if l:
            self._nxg.add_edge(u, v, weight=l)
        else:
            self._nxg.add_edge(u, v)

    def add_edges(self, edges, directed):
        """
        Add a sequence of edges to self.  If directed is True, these are
        interpreted as arcs.

        INPUT:

        - ``edges`` -- list/iterator of edges to be added.
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_edges([],True)
        """
        for e in edges:
            try:
                u,v,l = e
            except ValueError:
                u,v = e
                l = None
            self.add_edge(u,v,l,directed)

    def add_vertex(self, name):
        """
        Add a labelled vertex to self.

        INPUT:

        - ``name``: vertex label

        OUTPUT:

        If ``name=None``, the new vertex name is returned. ``None`` otherwise.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertex(0)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        retval = None
        if name is None: # then find an integer to use as a key
            i = 0
            while self.has_vertex(i):
                i=i+1
            name = i
            retval = name

        self._nxg.add_node(name)

        return retval

    def add_vertices(self, vertices):
        """
        Add labelled vertices to self.

        INPUT:

        - ``vertices``: iterator of vertex labels. A new label is created, used and returned in
          the output list for all ``None`` values in ``vertices``.

        OUTPUT:

        Generated names of new vertices if there is at least one ``None`` value
        present in ``vertices``. ``None`` otherwise.

        EXAMPLES::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertices([1,2,3])
            sage: G.add_vertices([4,None,None,5])
            [0, 6]
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        vertices = list(vertices)
        nones = vertices.count(None)
        vertices = [v for v in vertices if v is not None]
        self._nxg.add_nodes_from(vertices)

        new_names = []
        i = 0
        while nones > 0:
            while self.has_vertex(i):
                i += 1
            self._nxg.add_node(i)
            new_names.append(i)

            nones -= 1
            i += 1

        return new_names if new_names != [] else None

    def degree(self, v, directed):
        """
        Returns the total number of vertices incident to v.

        INPUT:

        - ``v`` -- a vertex label
        - ``directed`` -- boolean

        OUTPUT:

            degree of v

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertices(range(3))
            sage: G.degree(1, False)
            0
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.degree(v)

    def in_degree(self, v):
        """
        Returns the in-degree of v.

        INPUT:

        - ``v`` -- a vertex label

        OUTPUT:

            degree of v

        TESTS::

            sage: G = DiGraph(digraphs.Path(5),implementation="networkx")
            sage: G = G._backend
            sage: G.in_degree(0)
            0
            sage: G.in_degree(4)
            1
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.in_degree(v)

    def out_degree(self, v):
        """
        Returns the out-degree of v.

        INPUT:

        - ``v`` -- a vertex label

        OUTPUT:

            degree of v

        TESTS::

            sage: G = DiGraph(digraphs.Path(5),implementation="networkx")
            sage: G = G._backend
            sage: G.out_degree(0)
            1
            sage: G.out_degree(4)
            0
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.out_degree(v)

    def del_edge(self, u, v, l, directed):
        """
        Deletes the edge (u,v) with label l.

        INPUT:

        - ``u,v`` -- vertices
        - ``l`` -- edge label
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.del_edge(1,2,'a',True)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        import networkx
        try:
            if self._nxg.is_multigraph():
                for k,d in self._nxg.edge[u][v].iteritems():
                    if d.get('weight',None) == l:
                        self._nxg.remove_edge(u,v,k)
                        break
            else:
                if l is None or self._nxg.edge[u][v].get('weight',None) == l:
                    self._nxg.remove_edge(u,v)
        except (KeyError, networkx.NetworkXError):
            pass


    def del_vertex(self, v):
        """
        Delete a labelled vertex in self.

        INPUT:

        - ``v`` -- vertex label

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.del_vertex(0)
            Traceback (most recent call last):
            ...
            NetworkXError: The node 0 is not in the graph.
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        self._nxg.remove_node(v)

    def del_vertices(self, vertices):
        """
        Delete labelled vertices in self.

        INPUT:

        - ``vertices`` -- iterator of vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.del_vertices([1,2,3])
            Traceback (most recent call last):
            ...
            NetworkXError: The node 1 is not in the graph.
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        for v in vertices:
            self._nxg.remove_node(v)

    def get_edge_label(self, u, v):
        """
        Returns the edge label of (u,v).

        INPUT:

        - ``u,v`` -- vertex labels

        OUTPUT:
            label of (u,v)

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.get_edge_label(1,2)
            Traceback (most recent call last):
            ...
            NetworkXError: Edge (1,2) requested via get_edge_label does not exist.
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        try:
            E = self._nxg.edge[u][v]
        except KeyError:
            from networkx import NetworkXError
            raise NetworkXError("Edge (%s,%s) requested via get_edge_label does not exist."%(u,v))

        if self._nxg.is_multigraph():
            return [ e.get('weight',None) for e in E.itervalues() ]
        else:
            return E.get('weight',None)

    def has_edge(self, u, v, l):
        """
        True if self has an edge (u,v) with label l.

        INPUT:

        - ``u,v`` -- vertex labels
        - ``l`` -- label

        OUTPUT:
            boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.has_edge(1,2,'a')
            False
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if not self._nxg.has_edge(u, v):
            return False
        if l is None:
            return True
        if self._nxg.is_multigraph():
            return any( e.get('weight',None) == l for e in self._nxg.adj[u][v].itervalues() )
        else:
            return any( e == l for e in self._nxg.adj[u][v].itervalues() )

    def has_vertex(self, v):
        """
        True if self has a vertex with label v.

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.has_vertex(0)
            False
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.has_node(v)

    def iterator_edges(self, vertices, labels):
        """
        Iterate over the edges incident to a sequence of vertices. Edges are
        assumed to be undirected.

        INPUT:

        - ``vertices`` -- a list of vertex labels
        - ``labels`` -- boolean

        OUTPUT:
            a generator which yields edges, with or without labels
            depending on the labels parameter.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_edges([],True)
            <generator object iterator_edges at ...>
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if labels:
            for u,v,d in self._nxg.edges_iter(data=True):
                if u in vertices or v in vertices:
                    yield (u,v,d.get('weight',None))
        else:
            for u,v in self._nxg.edges_iter():
                if u in vertices or v in vertices:
                    yield (u,v)

    def _iterator_in_edges_with_labels(self, vertices):
        """
        Iterate over the incoming edges incident to a sequence of vertices.
        Special case, only for internal use.

        EXAMPLE::

            sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend
            sage: sorted(list(g.iterator_in_edges([0,1], True)))
            [(0, 1, None), (1, 0, None), (2, 1, None), (4, 0, None), (5, 0, None), (6, 1, None)]
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        for u,v,d in self._nxg.in_edges_iter(vertices,data=True):
            yield (u,v,d.get('weight',None))

    def iterator_in_edges(self, vertices, labels):
        """
        Iterate over the incoming edges incident to a sequence of vertices.

        INPUT:

        - ``vertices`` -- a list of vertex labels
        - ``labels`` -- boolean

        OUTPUT:
            a generator which yields edges, with or without labels
            depending on the labels parameter.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: i = G.iterator_in_edges([],True)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if self._nxg.is_directed():
            if labels:
                return self._iterator_in_edges_with_labels(vertices)
            else:
                return self._nxg.in_edges_iter(vertices)
        else:
            return self.iterator_edges(vertices,labels)

    def _iterator_out_edges_with_labels(self, vertices):
        """
        Iterate over the outbound edges incident to a sequence of vertices.
        Special case, only for internal use.

        EXAMPLE::

            sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend
            sage: sorted(list(g.iterator_out_edges([0,1], True)))
            [(0, 1, None), (0, 4, None), (0, 5, None), (1, 0, None), (1, 2, None), (1, 6, None)]
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        for u,v,d in self._nxg.out_edges_iter(vertices,data=True):
            yield (u,v,d.get('weight',None))

    def iterator_out_edges(self, vertices, labels):
        """
        Iterate over the outbound edges incident to a sequence of vertices.

        INPUT:

        - ``vertices`` -- a list of vertex labels
        - ``labels`` -- boolean

        OUTPUT:
            a generator which yields edges, with or without labels
            depending on the labels parameter.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: i = G.iterator_out_edges([],True)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if self._nxg.is_directed():
            if labels:
                return self._iterator_out_edges_with_labels(vertices)
            else:
                return self._nxg.out_edges_iter(vertices)
        else:
            return self.iterator_edges(vertices,labels)

    def iterator_nbrs(self, v):
        """
        Iterate over the vertices adjacent to v.

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            a generator which yields vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.add_vertex(0)
            sage: G.iterator_nbrs(0)
            <dictionary-keyiterator object at ...>
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.neighbors_iter(v)

    def iterator_in_nbrs(self, v):
        """
        Iterate over the vertices u such that the edge (u,v) is in self
        (that is, predecessors of v).

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            a generator which yields vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_in_nbrs(0)
            Traceback (most recent call last):
            ...
            AttributeError: 'MultiGraph' object has no attribute 'predecessors_iter'
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.predecessors_iter(v)

    def iterator_out_nbrs(self, v):
        """
        Iterate over the vertices u such that the edge (v,u) is in self
        (that is, successors of v).

        INPUT:

        - ``v`` -- vertex label

        OUTPUT:
            a generator which yields vertex labels

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_out_nbrs(0)
            Traceback (most recent call last):
            ...
            AttributeError: 'MultiGraph' object has no attribute 'successors_iter'
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.successors_iter(v)

    def iterator_verts(self, verts):
        """
        Iterate over the vertices v with labels in verts.

        INPUT:

        - ``vertex`` -- vertex labels

        OUTPUT:
            a generator which yields vertices

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.iterator_verts(0)
            <generator object bunch_iter at ...>
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.nbunch_iter(verts)

    def loops(self, new=None):
        """
        Get/set whether or not self allows loops.

        INPUT:

        - ``new`` -- can be a boolean (in which case it sets the value) or
          ``None``, in which case the current value is returned. It is set to
          ``None`` by default.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.loops(True)
            sage: G.loops(None)
            True
        """
        if new is None:
            return self._loops
        if new:
            self._loops = True
        else:
            self._loops = False

    def multiple_edges(self, new=None):
        """
        Get/set whether or not self allows multiple edges.

        INPUT:

        - ``new`` -- can be a boolean (in which case it sets the value) or
          ``None``, in which case the current value is returned. It is set to
          ``None`` by default.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.multiple_edges(True)
            sage: G.multiple_edges(None)
            True
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        from networkx import Graph,MultiGraph,DiGraph,MultiDiGraph
        if new is None:
            return self._nxg.is_multigraph()
        if new == self._nxg.is_multigraph():
            return
        if new:
            if self._nxg.is_directed():
                self._nxg = MultiDiGraph(self._nxg)
            else:
                self._nxg = MultiGraph(self._nxg)
        else:
            if self._nxg.is_directed():
                self._nxg = DiGraph(self._nxg)
            else:
                self._nxg = Graph(self._nxg)

    def name(self, new=None):
        """
        Get/set name of self.

        INPUT:

        - ``new`` -- can be a string (in which case it sets the value) or
          ``None``, in which case the current value is returned. It is set to
          ``None`` by default.

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.name("A NetworkX Graph")
            sage: G.name(None)
            'A NetworkX Graph'
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if new is None:
            return self._nxg.name
        self._nxg.name = new

    def num_edges(self, directed):
        """
        The number of edges in self

        INPUT:

        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.num_edges(True)
            0
            sage: G.num_edges(False)
            0
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.size()

    def num_verts(self):
        """
        The number of vertices in self

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.num_verts()
            0
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        return self._nxg.order()

    def relabel(self, perm, directed):
        """
        Relabel the vertices of self by a permutation.

        INPUT:

        - ``perm`` -- permutation
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.relabel([],False)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        from networkx import relabel_nodes
        name = self._nxg.name
        self._nxg = relabel_nodes(self._nxg,perm)
        self._nxg.name = name

    def set_edge_label(self, u, v, l, directed):
        """
        Label the edge (u,v) by l.

        INPUT:

        - ``u,v`` -- vertices
        - ``l`` -- edge label
        - ``directed`` -- boolean

        TESTS::

            sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend()
            sage: G.set_edge_label(1,2,'a',True)
        """
        if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)):
            self._nxg = self._nxg.mutate()

        if not self.has_edge(u, v, None):
            return
        if self.multiple_edges(None):
            self._nxg[u][v].clear()
            self._nxg[u][v][0] = dict(weight=l)
            if directed is False:
                self._nxg[v][u].clear()
                self._nxg[v][u][0] = dict(weight=l)
        else:
            self._nxg[u][v]['weight'] = l
            if directed is False:
                self._nxg[v][u]['weight'] = l
Beispiel #20
0
 def __init__(self, G: nx.Graph) -> None:
     """
     :param G: Networkx Graph
     """
     self.G = G
     self.directed = G.is_directed()
Beispiel #21
0
def rsc_evaluate_graph(graph: nx.Graph,
                       n_clusters=2,
                       method="vanilla",
                       percentile=None):
    """
    Reconsutrction of [1]Understanding Regularized Spectral Clustering via Graph Conductance, Yilin Zhang, Karl Rohe
    :param graph: Graph to be evaluated
    :param n_clusters: How many clusters to look at
    :param method: one among "vanilla", "regularized", "regularized_with_kmeans", "sklearn_spectral_embedding", "sklearn_kmeans", "percentile".
    :param percentile: value in [0, 100]. Mandatory if method="percentile", otherwise None
    :return:
    """
    # Experiment only on undirected graphs
    if graph.is_directed():
        graph = graph.to_undirected()

    # Before computing anything, largest connected component identified and used
    graph = graph.subgraph(max(nx.connected_components(graph), key=len)).copy()

    adj_matrix = nx.to_scipy_sparse_matrix(graph, format="csr")

    if method == "sklearn_spectral_embedding":
        (
            labels,
            num_iterations,
            smallest_cluster_size,
        ) = __sklearn_spectral_clustering(adj_matrix, n_clusters)

    elif method == "sklearn_kmeans":
        labels, num_iterations, smallest_cluster_size = __sklearn_kmeans(
            adj_matrix, n_clusters)

    elif method == "vanilla":
        (
            labels,
            num_iterations,
            smallest_cluster_size,
        ) = __regularized_spectral_clustering(adj_matrix, 0, n_clusters)

    elif method == "regularized_with_kmeans":

        graph_degree = graph.degree()
        graph_average_degree = (np.sum(val for (node, val) in graph_degree) /
                                graph.number_of_nodes())
        (
            labels,
            num_iterations,
            smallest_cluster_size,
        ) = __regularized_spectral_clustering(adj_matrix, graph_average_degree,
                                              n_clusters, "kmeans++")
    else:
        graph_degree = graph.degree()
        np.percentile(graph_degree, percentile)
        (
            labels,
            num_iterations,
            smallest_cluster_size,
        ) = __regularized_spectral_clustering(adj_matrix, percentile,
                                              n_clusters, "scan")

    return labels
Beispiel #22
0
 def __init__(self, gnx: nx.Graph, direct=False):
     self._gnx = gnx
     self._direct = gnx.is_directed() and direct
Beispiel #23
0
def graph_to_construction_sequence(graph: nx.Graph,
                                   root_node=None,
                                   node_offset: int = 0,
                                   traversal='bfs'):
    num_components = nx.algorithms.components.number_connected_components(
        graph)
    if num_components > 1:
        subgraphs = [
            graph.subgraph(c) for c in sorted(nx.connected_components(graph))
        ]
        current_offset = node_offset
        sequences = []
        for subgraph in subgraphs:
            sequences.append(
                graph_to_construction_sequence(subgraph,
                                               node_offset=current_offset,
                                               traversal=traversal))
            current_offset += len(subgraph.nodes)
        return list(itertools.chain(*sequences))

    if root_node is None:
        root_node = random.choice(list(graph.nodes))

    construction_sequence = []
    last_node_offset = node_offset
    node_map = {root_node: last_node_offset}
    visits = set()

    #"""
    traverser = nx.dfs_edges if traversal != 'bfs' else nx.bfs_edges
    for source, target in traverser(graph, source=root_node):
        if target not in node_map:
            construction_sequence.append(ConstructionAction.add_node)
            last_node_offset += 1
            node_map[target] = last_node_offset
        visits.add(target)
        for visit in [n for n in graph.neighbors(target) if n not in visits]:
            if visit not in node_map:
                construction_sequence.append(ConstructionAction.add_node)
                last_node_offset += 1
                node_map[visit] = last_node_offset
                construction_sequence.extend([
                    ConstructionAction.add_edge, node_map[target],
                    node_map[visit]
                ])
            if not graph.is_directed():
                construction_sequence.extend([
                    ConstructionAction.add_edge, node_map[visit],
                    node_map[target]
                ])
    #"""
    """
    for source_node, to_visit in nx.bfs_successors(graph, source=root_node):
        for visit in to_visit:
            visits.add(visit)
            if visit not in node_map:
                construction_sequence.append(ConstructionAction.add_node)
                last_node_offset += 1
                node_map[visit] = last_node_offset
            for target in [n for n in graph.neighbors(visit) if n not in visits]:
                if target not in node_map:
                    construction_sequence.append(ConstructionAction.add_node)
                    last_node_offset += 1
                    node_map[target] = last_node_offset
                construction_sequence.extend([ConstructionAction.add_edge, node_map[visit], node_map[target]])
                if not graph.is_directed():
                    construction_sequence.extend([ConstructionAction.add_edge,  node_map[target], node_map[visit]])
    """

    return construction_sequence
Beispiel #24
0
def translate(G: nx.Graph, l2n: Dict[str, str]) -> nx.Graph:
    G_c = nx.Graph() if not G.is_directed() else nx.DiGraph()

    for u, v in G.edges:
        G_c.add_edge(l2n.get(u, u), l2n.get(v, v), **G.get_edge_data(u, v), default=dict())
    return G_c
Beispiel #25
0
def diameter(g: nx.Graph):
    if not g.is_directed() and nx.is_connected(g):
        print(f"Diameter: {nx.diameter(g)}")
    else:
        print("Diameter not computable, graph not connected or is directed")
def plot_force_atlas_2(G: nx.Graph,
                       alpha=None,
                       edge_color=(0, 0, 0, 0.1),
                       node_color=np.array([(0, 0, 1, 0.6)]),
                       node_size=30,
                       edge_width=0.15,
                       iterations=100,
                       outboundAttractionDistribution=False,
                       edgeWeightInfluence=0.5,
                       jitterTolerance=0.05,
                       barnesHutOptimize=True,
                       barnesHutTheta=0.6,
                       scalingRatio=5,
                       strongGravityMode=False,
                       gravity=1,
                       verbose=True):
    if G.is_directed():
        G = G.to_undirected()

    # Calculate the positions of the nodes
    forceatlas2 = ForceAtlas2(
        # Behavior alternatives
        outboundAttractionDistribution=outboundAttractionDistribution,
        # Dissuade hubs
        linLogMode=False,  # NOT IMPLEMENTED
        adjustSizes=False,  # Prevent overlap (NOT IMPLEMENTED)
        edgeWeightInfluence=edgeWeightInfluence,

        # Performance
        jitterTolerance=jitterTolerance,  # Tolerance
        barnesHutOptimize=barnesHutOptimize,
        barnesHutTheta=barnesHutTheta,
        multiThreaded=False,  # NOT IMPLEMENTED

        # Tuning
        scalingRatio=scalingRatio,
        strongGravityMode=strongGravityMode,
        gravity=gravity,

        # Log
        verbose=verbose)

    positions = forceatlas2.forceatlas2_networkx_layout(G,
                                                        pos=None,
                                                        iterations=iterations)

    # If required by user, compute node sizes.
    def compute_node_sizes(quantity_array):
        size_biggest_node = 300
        return (quantity_array / np.max(quantity_array) * size_biggest_node)

    if node_size == 'by degree':
        node_size = compute_node_sizes(w.graph.degrees(G))

    # Create the plot
    figure = plt.figure(figsize=(12, 8))
    axes = figure.gca()

    nx.draw(
        G,
        positions,
        edge_color=edge_color,
        node_size=node_size,
        node_color=node_color,
        width=edge_width,
        # alpha=alpha,
        ax=axes)
def evaluate_graph(graph: nx.Graph, n_clusters, graph_name):
    """
    Reconsutrction of [1]Understanding Regularized Spectral Clustering via Graph Conductance, Yilin Zhang, Karl Rohe

    :param graph: Graph to be evaluated
    :param n_clusters: How many clusters to look at
    :param graph_name: the graph name used to create checkpoints and figures
    :return:
    """
    # Experiment only on undirected graphs
    if graph.is_directed():
        logging.debug('Graph is directed graph, mirroring the edges to undirected')
        graph = graph.to_undirected()

    graph_size_before_trimming = graph.number_of_nodes()
    # Before computing anything, largest connected component identified and used
    graph = graph.subgraph(max(nx.connected_components(graph), key=len)).copy()

    if is_logging_enabled:  # avoid needless mathematical operations
        logging.debug('Removing all components not connected to largest subgraph')
        graph_size_after_trimming = graph.number_of_nodes()
        logging.debug(
            'Total nodes removed: {}'.format(graph_size_after_trimming - graph_size_before_trimming))

    training_graph, testing_graph = split_graph_edges(graph)

    training_graph_size_before_removing_dangling_set = training_graph.number_of_nodes()
    training_graph: nx.Graph = training_graph.subgraph(max(nx.connected_components(training_graph), key=len)).copy()

    if is_logging_enabled:
        logging.debug('Total nodes removed from training set: {}'.format(
            training_graph_size_before_removing_dangling_set - training_graph.number_of_nodes()))

    results = {
        'graph_size': graph.number_of_nodes(),
        'vanilla': {},
        'regularized': {},
        'regularized_with_kmeans': {},
        'sklearn_spectral_embedding': {},
        'sklearn_kmeans': {},
        'tau_p30': {},
        'tau_p40': {},
        'tau_p50': {},
        'tau_p90': {},
        'tau_p99': {},
        'tau_max': {},
    }

    graph_degree = graph.degree()
    graph_average_degree = np.sum(val for (node, val) in graph_degree) / graph.number_of_nodes()
    logging.debug('Average degree regularisation: %f', graph_average_degree)

    adj_matrix = nx.to_scipy_sparse_matrix(training_graph, format='csr')
    tau_values = {
        'vanilla': graph_average_degree,
        'regularized': graph_average_degree,
        'regularized_with_kmeans': graph_average_degree,
        'sklearn_spectral_embedding': graph_average_degree,
        'sklearn_kmeans': graph_average_degree,
        'tau_p30': np.percentile(graph_degree, 30),
        'tau_p40': np.percentile(graph_degree, 40),
        'tau_p50': np.percentile(graph_degree, 50),
        'tau_p90': np.percentile(graph_degree, 90),
        'tau_p99': np.percentile(graph_degree, 99),
        'tau_max': np.percentile(graph_degree, 100)
    }

    for method, tau in tau_values.items():
        if method not in EXPERIMENTS:
            continue
        # tau = np.sum(adj_matrix) / adj_matrix.shape[0] Unclear from the paper if they recalculate tau after or before
        logging.info('Spectral clustering with tau = %f', tau)

        if method == 'sklearn_spectral_embedding':
            labels, num_iterations, smallest_cluster_size, execution_time = sklearn_spectral_clustering(adj_matrix,
                                                                                                        n_clusters)
        elif method == 'sklearn_kmeans':
            labels, num_iterations, smallest_cluster_size, execution_time = sklearn_kmeans(adj_matrix,
                                                                                           n_clusters)

        elif method == 'vanilla':
            labels, num_iterations, smallest_cluster_size, execution_time = regularized_spectral_clustering(adj_matrix,
                                                                                                            0,
                                                                                                            n_clusters)
        elif method == 'regularized_with_kmeans':
            labels, num_iterations, smallest_cluster_size, execution_time = regularized_spectral_clustering(adj_matrix,
                                                                                                            tau,
                                                                                                            n_clusters,
                                                                                                            'kmeans++')
        else:
            labels, num_iterations, smallest_cluster_size, execution_time = regularized_spectral_clustering(adj_matrix,
                                                                                                            tau,
                                                                                                            n_clusters,
                                                                                                            'scan')
        # Create subgraphs based on clusters identified using spectral clustering
        training_nodes = list(training_graph.nodes())
        subgraphs = {i: [] for i in range(n_clusters)}

        nodes_color = dict()
        for idx, label in enumerate(labels):
            node_id = training_nodes[idx]
            subgraphs[label].append(node_id)
            if SAVE_PLOTS:
                nodes_color[node_id] = COLORS[label]

        logging.debug('Evaluating Training Edges')
        training_core_cut, training_vanilla_conductance = evaluate_conductance(training_graph,
                                                                               subgraphs,
                                                                               tau)
        logging.debug('Evaluating Testing Edges')
        testing_core_cut, testing_vanilla_conductance = evaluate_conductance(testing_graph,
                                                                             subgraphs,
                                                                             tau)

        results[method]['training_core_cut'] = training_core_cut
        results[method]['training_vanilla_conductance'] = training_vanilla_conductance

        results[method]['testing_core_cut'] = testing_core_cut
        results[method]['testing_vanilla_conductance'] = testing_vanilla_conductance

        results[method]['num_iterations'] = num_iterations
        results[method]['smallest_cluster_size'] = smallest_cluster_size
        results[method]['execution_time'] = execution_time
        logging.info(method, results[method])

        print(method, results[method])
        if SAVE_PLOTS:
            nodes_color_list = []  # because networkx is weird...
            nodes_size = []
            for node_id in set(graph.nodes()):
                nodes_color_list.append(nodes_color.get(node_id, TRAINING_NODE_COLOR))
                nodes_size.append(5 if node_id in nodes_color else 1)
            plot_name = '{}_graph_{}_clusters_{}'.format(graph_name, method, n_clusters)
            plot_graph(graph, nodes_color_list, nodes_size,
                       plot_name)

    return results