#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# This file digraph.py is referred and derived from project NetworkX,
#
# https://github.com/networkx/networkx/blob/master/networkx/classes/digraph.py
#
# which has the following license:
#
# Copyright (C) 2004-2020, NetworkX Developers
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# All rights reserved.
#
# This file is part of NetworkX.
#
# NetworkX is distributed under a BSD license; see LICENSE.txt for more
# information.
#
import networkx.classes.function as func
from graphscope.nx.classes.cache import get_node_data
from graphscope.nx.utils.compat import patch_docstring
__all__ = [
"nodes",
"edges",
"degree",
"degree_histogram",
"neighbors",
"number_of_nodes",
"number_of_edges",
"density",
"is_directed",
"info",
"freeze",
"is_frozen",
"subgraph",
"induced_subgraph",
"edge_subgraph",
"to_directed",
"to_undirected",
"add_star",
"add_path",
"add_cycle",
"create_empty_copy",
"all_neighbors",
"non_neighbors",
"non_edges",
"common_neighbors",
"set_node_attributes",
"get_node_attributes",
"set_edge_attributes",
"get_edge_attributes",
"is_weighted",
"is_negatively_weighted",
"is_empty",
"selfloop_edges",
"nodes_with_selfloops",
"number_of_selfloops",
]
# forward the NetworkX functions
from networkx.classes.function import add_cycle
from networkx.classes.function import add_path
from networkx.classes.function import add_star
from networkx.classes.function import all_neighbors
from networkx.classes.function import common_neighbors
from networkx.classes.function import create_empty_copy
from networkx.classes.function import degree
from networkx.classes.function import degree_histogram
from networkx.classes.function import density
from networkx.classes.function import edges
from networkx.classes.function import freeze
from networkx.classes.function import get_edge_attributes
from networkx.classes.function import get_node_attributes
from networkx.classes.function import info
from networkx.classes.function import is_directed
from networkx.classes.function import is_empty
from networkx.classes.function import is_frozen
from networkx.classes.function import is_negatively_weighted
from networkx.classes.function import is_weighted
from networkx.classes.function import neighbors
from networkx.classes.function import nodes
from networkx.classes.function import nodes_with_selfloops
from networkx.classes.function import non_edges
from networkx.classes.function import non_neighbors
from networkx.classes.function import number_of_edges
from networkx.classes.function import number_of_nodes
from networkx.classes.function import selfloop_edges
from networkx.classes.function import subgraph
from networkx.classes.function import to_directed
from networkx.classes.function import to_undirected
[docs]def induced_subgraph(G, nbunch):
"""Returns a independent deep copy subgraph induced on nbunch.
The induced subgraph of a graph on a set of nodes N is the
graph with nodes N and edges from G which have both ends in N.
Parameters
----------
G : NetworkX Graph
nbunch : node, container of nodes or None (for all nodes)
Returns
-------
subgraph : SubGraph
A independent deep copy of the subgraph in `G` induced by the nodes.
Examples
--------
>>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc
>>> H = G.subgraph([0, 1, 2])
>>> list(H.edges)
[(0, 1), (1, 2)]
"""
induced_nodes = G.nbunch_iter(nbunch)
return G.subgraph(induced_nodes)
[docs]def edge_subgraph(G, edges):
"""Returns a independent deep copy subgraph induced by the specified edges.
The induced subgraph contains each edge in `edges` and each
node incident to any of those edges.
Parameters
----------
G : NetworkX Graph
edges : iterable
An iterable of edges. Edges not present in `G` are ignored.
Returns
-------
subgraph : SubGraph
A edge-induced subgraph of subgraph of `G`.
Examples
--------
>>> G = nx.path_graph(5)
>>> H = G.edge_subgraph([(0, 1), (3, 4)])
>>> list(H.nodes)
[0, 1, 3, 4]
>>> list(H.edges)
[(0, 1), (3, 4)]
"""
return G.edge_subgraph(edges)
[docs]@patch_docstring(func.number_of_selfloops)
def number_of_selfloops(G):
if G.is_multigraph():
# we forward the MultiGraph nd MultiDiGraph
return sum(1 for _ in selfloop_edges(G))
return G.number_of_selfloops()
@patch_docstring(func.set_node_attributes)
def set_node_attributes(G, values, name=None):
if G.is_multigraph():
# multigraph forward NetworkX
func.set_node_attributes(G, values, name)
return
# Set node attributes based on type of `values`
if name is not None: # `values` must not be a dict of dict
try: # `values` is a dict
for n, v in values.items():
if n in G:
dd = get_node_data(G, n)
dd[name] = values[n]
G.set_node_data(n, dd)
except AttributeError: # `values` is a constant
for n in G:
dd = get_node_data(G, n)
dd[name] = values
G.set_node_data(n, dd)
else: # `values` must be dict of dict
for n, d in values.items():
if n in G:
dd = get_node_data(G, n)
dd.update(d)
G.set_node_data(n, dd)
@patch_docstring(func.set_edge_attributes)
def set_edge_attributes(G, values, name=None): # noqa: C901
if G.is_multigraph():
# multigraph forward NetworkX
func.set_edge_attributes(G, values, name)
return
if name is not None:
# `values` does not contain attribute names
try:
# if `values` is a dict using `.items()` => {edge: value}
for (u, v), value in values.items():
dd = G.get_edge_data(u, v)
if dd is not None:
dd[name] = value
G.set_edge_data(u, v, dd)
except AttributeError:
# treat `values` as a constant
for u, v, data in G.edges(data=True):
data[name] = values
else:
for (u, v), d in values.items():
dd = G.get_edge_data(u, v)
if dd is not None:
dd.update(d)
G.set_edge_data(u, v, dd)