Fixed database typo and removed unnecessary class identifier.

This commit is contained in:
Batuhan Berk Başoğlu 2020-10-14 10:10:37 -04:00
parent 00ad49a143
commit 45fb349a7d
5098 changed files with 952558 additions and 85 deletions

View file

@ -0,0 +1,76 @@
"""
NetworkX
========
NetworkX is a Python package for the creation, manipulation, and study of the
structure, dynamics, and functions of complex networks.
See https://networkx.github.io for complete documentation.
"""
import sys
if sys.version_info[:2] < (3, 6):
m = "Python 3.6 or later is required for NetworkX (%d.%d detected)."
raise ImportError(m % sys.version_info[:2])
del sys
# Release data
from networkx import release
__author__ = (
f"{release.authors['Hagberg'][0]} <{release.authors['Hagberg'][1]}>\n"
f"{release.authors['Schult'][0]} <{release.authors['Schult'][1]}>\n"
f"{release.authors['Swart'][0]} <{release.authors['Swart'][1]}>"
)
__date__ = release.date
__version__ = release.version
__bibtex__ = """@inproceedings{hagberg-2008-exploring,
author = {Aric A. Hagberg and Daniel A. Schult and Pieter J. Swart},
title = {Exploring network structure, dynamics, and function using {NetworkX}},
year = {2008},
month = Aug,
urlpdf = {http://math.lanl.gov/~hagberg/Papers/hagberg-2008-exploring.pdf},
booktitle = {Proceedings of the 7th Python in Science Conference (SciPy2008)},
editors = {G\"{a}el Varoquaux, Travis Vaught, and Jarrod Millman},
address = {Pasadena, CA USA},
pages = {11--15}
}"""
# These are import orderwise
from networkx.exception import *
import networkx.utils
import networkx.classes.filters
import networkx.classes
from networkx.classes import *
import networkx.convert
from networkx.convert import *
import networkx.convert_matrix
from networkx.convert_matrix import *
import networkx.relabel
from networkx.relabel import *
import networkx.generators
from networkx.generators import *
import networkx.readwrite
from networkx.readwrite import *
# Need to test with SciPy, when available
import networkx.algorithms
from networkx.algorithms import *
import networkx.linalg
from networkx.linalg import *
from networkx.testing.test import run as test
import networkx.drawing
from networkx.drawing import *

View file

@ -0,0 +1,125 @@
from networkx.algorithms.assortativity import *
from networkx.algorithms.asteroidal import *
from networkx.algorithms.boundary import *
from networkx.algorithms.bridges import *
from networkx.algorithms.chains import *
from networkx.algorithms.centrality import *
from networkx.algorithms.chordal import *
from networkx.algorithms.cluster import *
from networkx.algorithms.clique import *
from networkx.algorithms.communicability_alg import *
from networkx.algorithms.components import *
from networkx.algorithms.coloring import *
from networkx.algorithms.core import *
from networkx.algorithms.covering import *
from networkx.algorithms.cycles import *
from networkx.algorithms.cuts import *
from networkx.algorithms.d_separation import *
from networkx.algorithms.dag import *
from networkx.algorithms.distance_measures import *
from networkx.algorithms.distance_regular import *
from networkx.algorithms.dominance import *
from networkx.algorithms.dominating import *
from networkx.algorithms.efficiency_measures import *
from networkx.algorithms.euler import *
from networkx.algorithms.graphical import *
from networkx.algorithms.hierarchy import *
from networkx.algorithms.hybrid import *
from networkx.algorithms.link_analysis import *
from networkx.algorithms.link_prediction import *
from networkx.algorithms.lowest_common_ancestors import *
from networkx.algorithms.isolate import *
from networkx.algorithms.matching import *
from networkx.algorithms.minors import *
from networkx.algorithms.mis import *
from networkx.algorithms.moral import *
from networkx.algorithms.non_randomness import *
from networkx.algorithms.operators import *
from networkx.algorithms.planarity import *
from networkx.algorithms.planar_drawing import *
from networkx.algorithms.reciprocity import *
from networkx.algorithms.regular import *
from networkx.algorithms.richclub import *
from networkx.algorithms.shortest_paths import *
from networkx.algorithms.similarity import *
from networkx.algorithms.graph_hashing import *
from networkx.algorithms.simple_paths import *
from networkx.algorithms.smallworld import *
from networkx.algorithms.smetric import *
from networkx.algorithms.structuralholes import *
from networkx.algorithms.sparsifiers import *
from networkx.algorithms.swap import *
from networkx.algorithms.traversal import *
from networkx.algorithms.triads import *
from networkx.algorithms.vitality import *
from networkx.algorithms.voronoi import *
from networkx.algorithms.wiener import *
# Make certain subpackages available to the user as direct imports from
# the `networkx` namespace.
import networkx.algorithms.assortativity
import networkx.algorithms.bipartite
import networkx.algorithms.node_classification
import networkx.algorithms.centrality
import networkx.algorithms.chordal
import networkx.algorithms.cluster
import networkx.algorithms.clique
import networkx.algorithms.components
import networkx.algorithms.connectivity
import networkx.algorithms.community
import networkx.algorithms.coloring
import networkx.algorithms.flow
import networkx.algorithms.isomorphism
import networkx.algorithms.link_analysis
import networkx.algorithms.lowest_common_ancestors
import networkx.algorithms.operators
import networkx.algorithms.shortest_paths
import networkx.algorithms.tournament
import networkx.algorithms.traversal
import networkx.algorithms.tree
# Make certain functions from some of the previous subpackages available
# to the user as direct imports from the `networkx` namespace.
from networkx.algorithms.bipartite import complete_bipartite_graph
from networkx.algorithms.bipartite import is_bipartite
from networkx.algorithms.bipartite import project
from networkx.algorithms.bipartite import projected_graph
from networkx.algorithms.connectivity import all_pairs_node_connectivity
from networkx.algorithms.connectivity import all_node_cuts
from networkx.algorithms.connectivity import average_node_connectivity
from networkx.algorithms.connectivity import edge_connectivity
from networkx.algorithms.connectivity import edge_disjoint_paths
from networkx.algorithms.connectivity import k_components
from networkx.algorithms.connectivity import k_edge_components
from networkx.algorithms.connectivity import k_edge_subgraphs
from networkx.algorithms.connectivity import k_edge_augmentation
from networkx.algorithms.connectivity import is_k_edge_connected
from networkx.algorithms.connectivity import minimum_edge_cut
from networkx.algorithms.connectivity import minimum_node_cut
from networkx.algorithms.connectivity import node_connectivity
from networkx.algorithms.connectivity import node_disjoint_paths
from networkx.algorithms.connectivity import stoer_wagner
from networkx.algorithms.flow import capacity_scaling
from networkx.algorithms.flow import cost_of_flow
from networkx.algorithms.flow import gomory_hu_tree
from networkx.algorithms.flow import max_flow_min_cost
from networkx.algorithms.flow import maximum_flow
from networkx.algorithms.flow import maximum_flow_value
from networkx.algorithms.flow import min_cost_flow
from networkx.algorithms.flow import min_cost_flow_cost
from networkx.algorithms.flow import minimum_cut
from networkx.algorithms.flow import minimum_cut_value
from networkx.algorithms.flow import network_simplex
from networkx.algorithms.isomorphism import could_be_isomorphic
from networkx.algorithms.isomorphism import fast_could_be_isomorphic
from networkx.algorithms.isomorphism import faster_could_be_isomorphic
from networkx.algorithms.isomorphism import is_isomorphic
from networkx.algorithms.tree.branchings import maximum_branching
from networkx.algorithms.tree.branchings import maximum_spanning_arborescence
from networkx.algorithms.tree.branchings import minimum_branching
from networkx.algorithms.tree.branchings import minimum_spanning_arborescence
from networkx.algorithms.tree.coding import *
from networkx.algorithms.tree.decomposition import *
from networkx.algorithms.tree.mst import *
from networkx.algorithms.tree.operations import *
from networkx.algorithms.tree.recognition import *

View file

@ -0,0 +1,22 @@
"""Approximations of graph properties and Heuristic functions for optimization
problems.
.. warning:: The approximation submodule is not imported in the top-level
``networkx``.
These functions can be imported with
``from networkx.algorithms import approximation``.
"""
from networkx.algorithms.approximation.clustering_coefficient import *
from networkx.algorithms.approximation.clique import *
from networkx.algorithms.approximation.connectivity import *
from networkx.algorithms.approximation.dominating_set import *
from networkx.algorithms.approximation.kcomponents import *
from networkx.algorithms.approximation.independent_set import *
from networkx.algorithms.approximation.matching import *
from networkx.algorithms.approximation.ramsey import *
from networkx.algorithms.approximation.steinertree import *
from networkx.algorithms.approximation.vertex_cover import *
from networkx.algorithms.approximation.treewidth import *

View file

@ -0,0 +1,159 @@
"""Functions for computing large cliques."""
import networkx as nx
from networkx.utils import not_implemented_for
from networkx.algorithms.approximation import ramsey
__all__ = ["clique_removal", "max_clique", "large_clique_size"]
def max_clique(G):
r"""Find the Maximum Clique
Finds the $O(|V|/(log|V|)^2)$ apx of maximum clique/independent set
in the worst case.
Parameters
----------
G : NetworkX graph
Undirected graph
Returns
-------
clique : set
The apx-maximum clique of the graph
Notes
------
A clique in an undirected graph G = (V, E) is a subset of the vertex set
`C \subseteq V` such that for every two vertices in C there exists an edge
connecting the two. This is equivalent to saying that the subgraph
induced by C is complete (in some cases, the term clique may also refer
to the subgraph).
A maximum clique is a clique of the largest possible size in a given graph.
The clique number `\omega(G)` of a graph G is the number of
vertices in a maximum clique in G. The intersection number of
G is the smallest number of cliques that together cover all edges of G.
https://en.wikipedia.org/wiki/Maximum_clique
References
----------
.. [1] Boppana, R., & Halldórsson, M. M. (1992).
Approximating maximum independent sets by excluding subgraphs.
BIT Numerical Mathematics, 32(2), 180196. Springer.
doi:10.1007/BF01994876
"""
if G is None:
raise ValueError("Expected NetworkX graph!")
# finding the maximum clique in a graph is equivalent to finding
# the independent set in the complementary graph
cgraph = nx.complement(G)
iset, _ = clique_removal(cgraph)
return iset
def clique_removal(G):
r""" Repeatedly remove cliques from the graph.
Results in a $O(|V|/(\log |V|)^2)$ approximation of maximum clique
and independent set. Returns the largest independent set found, along
with found maximal cliques.
Parameters
----------
G : NetworkX graph
Undirected graph
Returns
-------
max_ind_cliques : (set, list) tuple
2-tuple of Maximal Independent Set and list of maximal cliques (sets).
References
----------
.. [1] Boppana, R., & Halldórsson, M. M. (1992).
Approximating maximum independent sets by excluding subgraphs.
BIT Numerical Mathematics, 32(2), 180196. Springer.
"""
graph = G.copy()
c_i, i_i = ramsey.ramsey_R2(graph)
cliques = [c_i]
isets = [i_i]
while graph:
graph.remove_nodes_from(c_i)
c_i, i_i = ramsey.ramsey_R2(graph)
if c_i:
cliques.append(c_i)
if i_i:
isets.append(i_i)
# Determine the largest independent set as measured by cardinality.
maxiset = max(isets, key=len)
return maxiset, cliques
@not_implemented_for("directed")
@not_implemented_for("multigraph")
def large_clique_size(G):
"""Find the size of a large clique in a graph.
A *clique* is a subset of nodes in which each pair of nodes is
adjacent. This function is a heuristic for finding the size of a
large clique in the graph.
Parameters
----------
G : NetworkX graph
Returns
-------
int
The size of a large clique in the graph.
Notes
-----
This implementation is from [1]_. Its worst case time complexity is
:math:`O(n d^2)`, where *n* is the number of nodes in the graph and
*d* is the maximum degree.
This function is a heuristic, which means it may work well in
practice, but there is no rigorous mathematical guarantee on the
ratio between the returned number and the actual largest clique size
in the graph.
References
----------
.. [1] Pattabiraman, Bharath, et al.
"Fast Algorithms for the Maximum Clique Problem on Massive Graphs
with Applications to Overlapping Community Detection."
*Internet Mathematics* 11.4-5 (2015): 421--448.
<https://doi.org/10.1080/15427951.2014.986778>
See also
--------
:func:`networkx.algorithms.approximation.clique.max_clique`
A function that returns an approximate maximum clique with a
guarantee on the approximation ratio.
:mod:`networkx.algorithms.clique`
Functions for finding the exact maximum clique in a graph.
"""
degrees = G.degree
def _clique_heuristic(G, U, size, best_size):
if not U:
return max(best_size, size)
u = max(U, key=degrees)
U.remove(u)
N_prime = {v for v in G[u] if degrees[v] >= best_size}
return _clique_heuristic(G, U & N_prime, size + 1, best_size)
best_size = 0
nodes = (u for u in G if degrees[u] >= best_size)
for u in nodes:
neighbors = {v for v in G[u] if degrees[v] >= best_size}
best_size = _clique_heuristic(G, neighbors, 1, best_size)
return best_size

View file

@ -0,0 +1,58 @@
from networkx.utils import not_implemented_for
from networkx.utils import py_random_state
__all__ = ["average_clustering"]
@py_random_state(2)
@not_implemented_for("directed")
def average_clustering(G, trials=1000, seed=None):
r"""Estimates the average clustering coefficient of G.
The local clustering of each node in `G` is the fraction of triangles
that actually exist over all possible triangles in its neighborhood.
The average clustering coefficient of a graph `G` is the mean of
local clusterings.
This function finds an approximate average clustering coefficient
for G by repeating `n` times (defined in `trials`) the following
experiment: choose a node at random, choose two of its neighbors
at random, and check if they are connected. The approximate
coefficient is the fraction of triangles found over the number
of trials [1]_.
Parameters
----------
G : NetworkX graph
trials : integer
Number of trials to perform (default 1000).
seed : integer, random_state, or None (default)
Indicator of random number generation state.
See :ref:`Randomness<randomness>`.
Returns
-------
c : float
Approximated average clustering coefficient.
References
----------
.. [1] Schank, Thomas, and Dorothea Wagner. Approximating clustering
coefficient and transitivity. Universität Karlsruhe, Fakultät für
Informatik, 2004.
http://www.emis.ams.org/journals/JGAA/accepted/2005/SchankWagner2005.9.2.pdf
"""
n = len(G)
triangles = 0
nodes = list(G)
for i in [int(seed.random() * n) for i in range(trials)]:
nbrs = list(G[nodes[i]])
if len(nbrs) < 2:
continue
u, v = seed.sample(nbrs, 2)
if u in G[v]:
triangles += 1
return triangles / float(trials)

View file

@ -0,0 +1,403 @@
""" Fast approximation for node connectivity
"""
import itertools
from operator import itemgetter
import networkx as nx
__all__ = [
"local_node_connectivity",
"node_connectivity",
"all_pairs_node_connectivity",
]
INF = float("inf")
def local_node_connectivity(G, source, target, cutoff=None):
"""Compute node connectivity between source and target.
Pairwise or local node connectivity between two distinct and nonadjacent
nodes is the minimum number of nodes that must be removed (minimum
separating cutset) to disconnect them. By Menger's theorem, this is equal
to the number of node independent paths (paths that share no nodes other
than source and target). Which is what we compute in this function.
This algorithm is a fast approximation that gives an strict lower
bound on the actual number of node independent paths between two nodes [1]_.
It works for both directed and undirected graphs.
Parameters
----------
G : NetworkX graph
source : node
Starting node for node connectivity
target : node
Ending node for node connectivity
cutoff : integer
Maximum node connectivity to consider. If None, the minimum degree
of source or target is used as a cutoff. Default value None.
Returns
-------
k: integer
pairwise node connectivity
Examples
--------
>>> # Platonic octahedral graph has node connectivity 4
>>> # for each non adjacent node pair
>>> from networkx.algorithms import approximation as approx
>>> G = nx.octahedral_graph()
>>> approx.local_node_connectivity(G, 0, 5)
4
Notes
-----
This algorithm [1]_ finds node independents paths between two nodes by
computing their shortest path using BFS, marking the nodes of the path
found as 'used' and then searching other shortest paths excluding the
nodes marked as used until no more paths exist. It is not exact because
a shortest path could use nodes that, if the path were longer, may belong
to two different node independent paths. Thus it only guarantees an
strict lower bound on node connectivity.
Note that the authors propose a further refinement, losing accuracy and
gaining speed, which is not implemented yet.
See also
--------
all_pairs_node_connectivity
node_connectivity
References
----------
.. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for
Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035
http://eclectic.ss.uci.edu/~drwhite/working.pdf
"""
if target == source:
raise nx.NetworkXError("source and target have to be different nodes.")
# Maximum possible node independent paths
if G.is_directed():
possible = min(G.out_degree(source), G.in_degree(target))
else:
possible = min(G.degree(source), G.degree(target))
K = 0
if not possible:
return K
if cutoff is None:
cutoff = INF
exclude = set()
for i in range(min(possible, cutoff)):
try:
path = _bidirectional_shortest_path(G, source, target, exclude)
exclude.update(set(path))
K += 1
except nx.NetworkXNoPath:
break
return K
def node_connectivity(G, s=None, t=None):
r"""Returns an approximation for node connectivity for a graph or digraph G.
Node connectivity is equal to the minimum number of nodes that
must be removed to disconnect G or render it trivial. By Menger's theorem,
this is equal to the number of node independent paths (paths that
share no nodes other than source and target).
If source and target nodes are provided, this function returns the
local node connectivity: the minimum number of nodes that must be
removed to break all paths from source to target in G.
This algorithm is based on a fast approximation that gives an strict lower
bound on the actual number of node independent paths between two nodes [1]_.
It works for both directed and undirected graphs.
Parameters
----------
G : NetworkX graph
Undirected graph
s : node
Source node. Optional. Default value: None.
t : node
Target node. Optional. Default value: None.
Returns
-------
K : integer
Node connectivity of G, or local node connectivity if source
and target are provided.
Examples
--------
>>> # Platonic octahedral graph is 4-node-connected
>>> from networkx.algorithms import approximation as approx
>>> G = nx.octahedral_graph()
>>> approx.node_connectivity(G)
4
Notes
-----
This algorithm [1]_ finds node independents paths between two nodes by
computing their shortest path using BFS, marking the nodes of the path
found as 'used' and then searching other shortest paths excluding the
nodes marked as used until no more paths exist. It is not exact because
a shortest path could use nodes that, if the path were longer, may belong
to two different node independent paths. Thus it only guarantees an
strict lower bound on node connectivity.
See also
--------
all_pairs_node_connectivity
local_node_connectivity
References
----------
.. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for
Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035
http://eclectic.ss.uci.edu/~drwhite/working.pdf
"""
if (s is not None and t is None) or (s is None and t is not None):
raise nx.NetworkXError("Both source and target must be specified.")
# Local node connectivity
if s is not None and t is not None:
if s not in G:
raise nx.NetworkXError(f"node {s} not in graph")
if t not in G:
raise nx.NetworkXError(f"node {t} not in graph")
return local_node_connectivity(G, s, t)
# Global node connectivity
if G.is_directed():
connected_func = nx.is_weakly_connected
iter_func = itertools.permutations
def neighbors(v):
return itertools.chain(G.predecessors(v), G.successors(v))
else:
connected_func = nx.is_connected
iter_func = itertools.combinations
neighbors = G.neighbors
if not connected_func(G):
return 0
# Choose a node with minimum degree
v, minimum_degree = min(G.degree(), key=itemgetter(1))
# Node connectivity is bounded by minimum degree
K = minimum_degree
# compute local node connectivity with all non-neighbors nodes
# and store the minimum
for w in set(G) - set(neighbors(v)) - {v}:
K = min(K, local_node_connectivity(G, v, w, cutoff=K))
# Same for non adjacent pairs of neighbors of v
for x, y in iter_func(neighbors(v), 2):
if y not in G[x] and x != y:
K = min(K, local_node_connectivity(G, x, y, cutoff=K))
return K
def all_pairs_node_connectivity(G, nbunch=None, cutoff=None):
""" Compute node connectivity between all pairs of nodes.
Pairwise or local node connectivity between two distinct and nonadjacent
nodes is the minimum number of nodes that must be removed (minimum
separating cutset) to disconnect them. By Menger's theorem, this is equal
to the number of node independent paths (paths that share no nodes other
than source and target). Which is what we compute in this function.
This algorithm is a fast approximation that gives an strict lower
bound on the actual number of node independent paths between two nodes [1]_.
It works for both directed and undirected graphs.
Parameters
----------
G : NetworkX graph
nbunch: container
Container of nodes. If provided node connectivity will be computed
only over pairs of nodes in nbunch.
cutoff : integer
Maximum node connectivity to consider. If None, the minimum degree
of source or target is used as a cutoff in each pair of nodes.
Default value None.
Returns
-------
K : dictionary
Dictionary, keyed by source and target, of pairwise node connectivity
See Also
--------
local_node_connectivity
node_connectivity
References
----------
.. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for
Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035
http://eclectic.ss.uci.edu/~drwhite/working.pdf
"""
if nbunch is None:
nbunch = G
else:
nbunch = set(nbunch)
directed = G.is_directed()
if directed:
iter_func = itertools.permutations
else:
iter_func = itertools.combinations
all_pairs = {n: {} for n in nbunch}
for u, v in iter_func(nbunch, 2):
k = local_node_connectivity(G, u, v, cutoff=cutoff)
all_pairs[u][v] = k
if not directed:
all_pairs[v][u] = k
return all_pairs
def _bidirectional_shortest_path(G, source, target, exclude):
"""Returns shortest path between source and target ignoring nodes in the
container 'exclude'.
Parameters
----------
G : NetworkX graph
source : node
Starting node for path
target : node
Ending node for path
exclude: container
Container for nodes to exclude from the search for shortest paths
Returns
-------
path: list
Shortest path between source and target ignoring nodes in 'exclude'
Raises
------
NetworkXNoPath
If there is no path or if nodes are adjacent and have only one path
between them
Notes
-----
This function and its helper are originally from
networkx.algorithms.shortest_paths.unweighted and are modified to
accept the extra parameter 'exclude', which is a container for nodes
already used in other paths that should be ignored.
References
----------
.. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for
Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035
http://eclectic.ss.uci.edu/~drwhite/working.pdf
"""
# call helper to do the real work
results = _bidirectional_pred_succ(G, source, target, exclude)
pred, succ, w = results
# build path from pred+w+succ
path = []
# from source to w
while w is not None:
path.append(w)
w = pred[w]
path.reverse()
# from w to target
w = succ[path[-1]]
while w is not None:
path.append(w)
w = succ[w]
return path
def _bidirectional_pred_succ(G, source, target, exclude):
# does BFS from both source and target and meets in the middle
# excludes nodes in the container "exclude" from the search
if source is None or target is None:
raise nx.NetworkXException(
"Bidirectional shortest path called without source or target"
)
if target == source:
return ({target: None}, {source: None}, source)
# handle either directed or undirected
if G.is_directed():
Gpred = G.predecessors
Gsucc = G.successors
else:
Gpred = G.neighbors
Gsucc = G.neighbors
# predecesssor and successors in search
pred = {source: None}
succ = {target: None}
# initialize fringes, start with forward
forward_fringe = [source]
reverse_fringe = [target]
level = 0
while forward_fringe and reverse_fringe:
# Make sure that we iterate one step forward and one step backwards
# thus source and target will only trigger "found path" when they are
# adjacent and then they can be safely included in the container 'exclude'
level += 1
if not level % 2 == 0:
this_level = forward_fringe
forward_fringe = []
for v in this_level:
for w in Gsucc(v):
if w in exclude:
continue
if w not in pred:
forward_fringe.append(w)
pred[w] = v
if w in succ:
return pred, succ, w # found path
else:
this_level = reverse_fringe
reverse_fringe = []
for v in this_level:
for w in Gpred(v):
if w in exclude:
continue
if w not in succ:
succ[w] = v
reverse_fringe.append(w)
if w in pred:
return pred, succ, w # found path
raise nx.NetworkXNoPath(f"No path between {source} and {target}.")

View file

@ -0,0 +1,123 @@
"""Functions for finding node and edge dominating sets.
A `dominating set`_ for an undirected graph *G* with vertex set *V*
and edge set *E* is a subset *D* of *V* such that every vertex not in
*D* is adjacent to at least one member of *D*. An `edge dominating set`_
is a subset *F* of *E* such that every edge not in *F* is
incident to an endpoint of at least one edge in *F*.
.. _dominating set: https://en.wikipedia.org/wiki/Dominating_set
.. _edge dominating set: https://en.wikipedia.org/wiki/Edge_dominating_set
"""
from ..matching import maximal_matching
from ...utils import not_implemented_for
__all__ = ["min_weighted_dominating_set", "min_edge_dominating_set"]
# TODO Why doesn't this algorithm work for directed graphs?
@not_implemented_for("directed")
def min_weighted_dominating_set(G, weight=None):
r"""Returns a dominating set that approximates the minimum weight node
dominating set.
Parameters
----------
G : NetworkX graph
Undirected graph.
weight : string
The node attribute storing the weight of an node. If provided,
the node attribute with this key must be a number for each
node. If not provided, each node is assumed to have weight one.
Returns
-------
min_weight_dominating_set : set
A set of nodes, the sum of whose weights is no more than `(\log
w(V)) w(V^*)`, where `w(V)` denotes the sum of the weights of
each node in the graph and `w(V^*)` denotes the sum of the
weights of each node in the minimum weight dominating set.
Notes
-----
This algorithm computes an approximate minimum weighted dominating
set for the graph `G`. The returned solution has weight `(\log
w(V)) w(V^*)`, where `w(V)` denotes the sum of the weights of each
node in the graph and `w(V^*)` denotes the sum of the weights of
each node in the minimum weight dominating set for the graph.
This implementation of the algorithm runs in $O(m)$ time, where $m$
is the number of edges in the graph.
References
----------
.. [1] Vazirani, Vijay V.
*Approximation Algorithms*.
Springer Science & Business Media, 2001.
"""
# The unique dominating set for the null graph is the empty set.
if len(G) == 0:
return set()
# This is the dominating set that will eventually be returned.
dom_set = set()
def _cost(node_and_neighborhood):
"""Returns the cost-effectiveness of greedily choosing the given
node.
`node_and_neighborhood` is a two-tuple comprising a node and its
closed neighborhood.
"""
v, neighborhood = node_and_neighborhood
return G.nodes[v].get(weight, 1) / len(neighborhood - dom_set)
# This is a set of all vertices not already covered by the
# dominating set.
vertices = set(G)
# This is a dictionary mapping each node to the closed neighborhood
# of that node.
neighborhoods = {v: {v} | set(G[v]) for v in G}
# Continue until all vertices are adjacent to some node in the
# dominating set.
while vertices:
# Find the most cost-effective node to add, along with its
# closed neighborhood.
dom_node, min_set = min(neighborhoods.items(), key=_cost)
# Add the node to the dominating set and reduce the remaining
# set of nodes to cover.
dom_set.add(dom_node)
del neighborhoods[dom_node]
vertices -= min_set
return dom_set
def min_edge_dominating_set(G):
r"""Returns minimum cardinality edge dominating set.
Parameters
----------
G : NetworkX graph
Undirected graph
Returns
-------
min_edge_dominating_set : set
Returns a set of dominating edges whose size is no more than 2 * OPT.
Notes
-----
The algorithm computes an approximate solution to the edge dominating set
problem. The result is no more than 2 * OPT in terms of size of the set.
Runtime of the algorithm is $O(|E|)$.
"""
if not G:
raise ValueError("Expected non-empty NetworkX graph!")
return maximal_matching(G)

View file

@ -0,0 +1,58 @@
r"""
Independent Set
Independent set or stable set is a set of vertices in a graph, no two of
which are adjacent. That is, it is a set I of vertices such that for every
two vertices in I, there is no edge connecting the two. Equivalently, each
edge in the graph has at most one endpoint in I. The size of an independent
set is the number of vertices it contains.
A maximum independent set is a largest independent set for a given graph G
and its size is denoted $\alpha(G)$. The problem of finding such a set is called
the maximum independent set problem and is an NP-hard optimization problem.
As such, it is unlikely that there exists an efficient algorithm for finding
a maximum independent set of a graph.
`Wikipedia: Independent set <https://en.wikipedia.org/wiki/Independent_set_(graph_theory)>`_
Independent set algorithm is based on the following paper:
$O(|V|/(log|V|)^2)$ apx of maximum clique/independent set.
Boppana, R., & Halldórsson, M. M. (1992).
Approximating maximum independent sets by excluding subgraphs.
BIT Numerical Mathematics, 32(2), 180196. Springer.
doi:10.1007/BF01994876
"""
from networkx.algorithms.approximation import clique_removal
__all__ = ["maximum_independent_set"]
def maximum_independent_set(G):
"""Returns an approximate maximum independent set.
Parameters
----------
G : NetworkX graph
Undirected graph
Returns
-------
iset : Set
The apx-maximum independent set
Notes
-----
Finds the $O(|V|/(log|V|)^2)$ apx of independent set in the worst case.
References
----------
.. [1] Boppana, R., & Halldórsson, M. M. (1992).
Approximating maximum independent sets by excluding subgraphs.
BIT Numerical Mathematics, 32(2), 180196. Springer.
"""
iset, _ = clique_removal(G)
return iset

View file

@ -0,0 +1,368 @@
""" Fast approximation for k-component structure
"""
import itertools
from collections import defaultdict
from collections.abc import Mapping
import networkx as nx
from networkx.exception import NetworkXError
from networkx.utils import not_implemented_for
from networkx.algorithms.approximation import local_node_connectivity
__all__ = ["k_components"]
not_implemented_for("directed")
def k_components(G, min_density=0.95):
r"""Returns the approximate k-component structure of a graph G.
A `k`-component is a maximal subgraph of a graph G that has, at least,
node connectivity `k`: we need to remove at least `k` nodes to break it
into more components. `k`-components have an inherent hierarchical
structure because they are nested in terms of connectivity: a connected
graph can contain several 2-components, each of which can contain
one or more 3-components, and so forth.
This implementation is based on the fast heuristics to approximate
the `k`-component structure of a graph [1]_. Which, in turn, it is based on
a fast approximation algorithm for finding good lower bounds of the number
of node independent paths between two nodes [2]_.
Parameters
----------
G : NetworkX graph
Undirected graph
min_density : Float
Density relaxation threshold. Default value 0.95
Returns
-------
k_components : dict
Dictionary with connectivity level `k` as key and a list of
sets of nodes that form a k-component of level `k` as values.
Examples
--------
>>> # Petersen graph has 10 nodes and it is triconnected, thus all
>>> # nodes are in a single component on all three connectivity levels
>>> from networkx.algorithms import approximation as apxa
>>> G = nx.petersen_graph()
>>> k_components = apxa.k_components(G)
Notes
-----
The logic of the approximation algorithm for computing the `k`-component
structure [1]_ is based on repeatedly applying simple and fast algorithms
for `k`-cores and biconnected components in order to narrow down the
number of pairs of nodes over which we have to compute White and Newman's
approximation algorithm for finding node independent paths [2]_. More
formally, this algorithm is based on Whitney's theorem, which states
an inclusion relation among node connectivity, edge connectivity, and
minimum degree for any graph G. This theorem implies that every
`k`-component is nested inside a `k`-edge-component, which in turn,
is contained in a `k`-core. Thus, this algorithm computes node independent
paths among pairs of nodes in each biconnected part of each `k`-core,
and repeats this procedure for each `k` from 3 to the maximal core number
of a node in the input graph.
Because, in practice, many nodes of the core of level `k` inside a
bicomponent actually are part of a component of level k, the auxiliary
graph needed for the algorithm is likely to be very dense. Thus, we use
a complement graph data structure (see `AntiGraph`) to save memory.
AntiGraph only stores information of the edges that are *not* present
in the actual auxiliary graph. When applying algorithms to this
complement graph data structure, it behaves as if it were the dense
version.
See also
--------
k_components
References
----------
.. [1] Torrents, J. and F. Ferraro (2015) Structural Cohesion:
Visualization and Heuristics for Fast Computation.
https://arxiv.org/pdf/1503.04476v1
.. [2] White, Douglas R., and Mark Newman (2001) A Fast Algorithm for
Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035
http://eclectic.ss.uci.edu/~drwhite/working.pdf
.. [3] Moody, J. and D. White (2003). Social cohesion and embeddedness:
A hierarchical conception of social groups.
American Sociological Review 68(1), 103--28.
http://www2.asanet.org/journals/ASRFeb03MoodyWhite.pdf
"""
# Dictionary with connectivity level (k) as keys and a list of
# sets of nodes that form a k-component as values
k_components = defaultdict(list)
# make a few functions local for speed
node_connectivity = local_node_connectivity
k_core = nx.k_core
core_number = nx.core_number
biconnected_components = nx.biconnected_components
density = nx.density
combinations = itertools.combinations
# Exact solution for k = {1,2}
# There is a linear time algorithm for triconnectivity, if we had an
# implementation available we could start from k = 4.
for component in nx.connected_components(G):
# isolated nodes have connectivity 0
comp = set(component)
if len(comp) > 1:
k_components[1].append(comp)
for bicomponent in nx.biconnected_components(G):
# avoid considering dyads as bicomponents
bicomp = set(bicomponent)
if len(bicomp) > 2:
k_components[2].append(bicomp)
# There is no k-component of k > maximum core number
# \kappa(G) <= \lambda(G) <= \delta(G)
g_cnumber = core_number(G)
max_core = max(g_cnumber.values())
for k in range(3, max_core + 1):
C = k_core(G, k, core_number=g_cnumber)
for nodes in biconnected_components(C):
# Build a subgraph SG induced by the nodes that are part of
# each biconnected component of the k-core subgraph C.
if len(nodes) < k:
continue
SG = G.subgraph(nodes)
# Build auxiliary graph
H = _AntiGraph()
H.add_nodes_from(SG.nodes())
for u, v in combinations(SG, 2):
K = node_connectivity(SG, u, v, cutoff=k)
if k > K:
H.add_edge(u, v)
for h_nodes in biconnected_components(H):
if len(h_nodes) <= k:
continue
SH = H.subgraph(h_nodes)
for Gc in _cliques_heuristic(SG, SH, k, min_density):
for k_nodes in biconnected_components(Gc):
Gk = nx.k_core(SG.subgraph(k_nodes), k)
if len(Gk) <= k:
continue
k_components[k].append(set(Gk))
return k_components
def _cliques_heuristic(G, H, k, min_density):
h_cnumber = nx.core_number(H)
for i, c_value in enumerate(sorted(set(h_cnumber.values()), reverse=True)):
cands = {n for n, c in h_cnumber.items() if c == c_value}
# Skip checking for overlap for the highest core value
if i == 0:
overlap = False
else:
overlap = set.intersection(
*[{x for x in H[n] if x not in cands} for n in cands]
)
if overlap and len(overlap) < k:
SH = H.subgraph(cands | overlap)
else:
SH = H.subgraph(cands)
sh_cnumber = nx.core_number(SH)
SG = nx.k_core(G.subgraph(SH), k)
while not (_same(sh_cnumber) and nx.density(SH) >= min_density):
# This subgraph must be writable => .copy()
SH = H.subgraph(SG).copy()
if len(SH) <= k:
break
sh_cnumber = nx.core_number(SH)
sh_deg = dict(SH.degree())
min_deg = min(sh_deg.values())
SH.remove_nodes_from(n for n, d in sh_deg.items() if d == min_deg)
SG = nx.k_core(G.subgraph(SH), k)
else:
yield SG
def _same(measure, tol=0):
vals = set(measure.values())
if (max(vals) - min(vals)) <= tol:
return True
return False
class _AntiGraph(nx.Graph):
"""
Class for complement graphs.
The main goal is to be able to work with big and dense graphs with
a low memory foodprint.
In this class you add the edges that *do not exist* in the dense graph,
the report methods of the class return the neighbors, the edges and
the degree as if it was the dense graph. Thus it's possible to use
an instance of this class with some of NetworkX functions. In this
case we only use k-core, connected_components, and biconnected_components.
"""
all_edge_dict = {"weight": 1}
def single_edge_dict(self):
return self.all_edge_dict
edge_attr_dict_factory = single_edge_dict
def __getitem__(self, n):
"""Returns a dict of neighbors of node n in the dense graph.
Parameters
----------
n : node
A node in the graph.
Returns
-------
adj_dict : dictionary
The adjacency dictionary for nodes connected to n.
"""
all_edge_dict = self.all_edge_dict
return {
node: all_edge_dict for node in set(self._adj) - set(self._adj[n]) - {n}
}
def neighbors(self, n):
"""Returns an iterator over all neighbors of node n in the
dense graph.
"""
try:
return iter(set(self._adj) - set(self._adj[n]) - {n})
except KeyError as e:
raise NetworkXError(f"The node {n} is not in the graph.") from e
class AntiAtlasView(Mapping):
"""An adjacency inner dict for AntiGraph"""
def __init__(self, graph, node):
self._graph = graph
self._atlas = graph._adj[node]
self._node = node
def __len__(self):
return len(self._graph) - len(self._atlas) - 1
def __iter__(self):
return (n for n in self._graph if n not in self._atlas and n != self._node)
def __getitem__(self, nbr):
nbrs = set(self._graph._adj) - set(self._atlas) - {self._node}
if nbr in nbrs:
return self._graph.all_edge_dict
raise KeyError(nbr)
class AntiAdjacencyView(AntiAtlasView):
"""An adjacency outer dict for AntiGraph"""
def __init__(self, graph):
self._graph = graph
self._atlas = graph._adj
def __len__(self):
return len(self._atlas)
def __iter__(self):
return iter(self._graph)
def __getitem__(self, node):
if node not in self._graph:
raise KeyError(node)
return self._graph.AntiAtlasView(self._graph, node)
@property
def adj(self):
return self.AntiAdjacencyView(self)
def subgraph(self, nodes):
"""This subgraph method returns a full AntiGraph. Not a View"""
nodes = set(nodes)
G = _AntiGraph()
G.add_nodes_from(nodes)
for n in G:
Gnbrs = G.adjlist_inner_dict_factory()
G._adj[n] = Gnbrs
for nbr, d in self._adj[n].items():
if nbr in G._adj:
Gnbrs[nbr] = d
G._adj[nbr][n] = d
G.graph = self.graph
return G
class AntiDegreeView(nx.reportviews.DegreeView):
def __iter__(self):
all_nodes = set(self._succ)
for n in self._nodes:
nbrs = all_nodes - set(self._succ[n]) - {n}
yield (n, len(nbrs))
def __getitem__(self, n):
nbrs = set(self._succ) - set(self._succ[n]) - {n}
# AntiGraph is a ThinGraph so all edges have weight 1
return len(nbrs) + (n in nbrs)
@property
def degree(self):
"""Returns an iterator for (node, degree) and degree for single node.
The node degree is the number of edges adjacent to the node.
Parameters
----------
nbunch : iterable container, optional (default=all nodes)
A container of nodes. The container will be iterated
through once.
weight : string or None, optional (default=None)
The edge attribute that holds the numerical value used
as a weight. If None, then each edge has weight 1.
The degree is the sum of the edge weights adjacent to the node.
Returns
-------
deg:
Degree of the node, if a single node is passed as argument.
nd_iter : an iterator
The iterator returns two-tuples of (node, degree).
See Also
--------
degree
Examples
--------
>>> G = nx.path_graph(4)
>>> G.degree(0) # node 0 with degree 1
1
>>> list(G.degree([0, 1]))
[(0, 1), (1, 2)]
"""
return self.AntiDegreeView(self)
def adjacency(self):
"""Returns an iterator of (node, adjacency set) tuples for all nodes
in the dense graph.
This is the fastest way to look at every edge.
For directed graphs, only outgoing adjacencies are included.
Returns
-------
adj_iter : iterator
An iterator of (node, adjacency set) for all nodes in
the graph.
"""
for n in self._adj:
yield (n, set(self._adj) - set(self._adj[n]) - {n})

View file

@ -0,0 +1,42 @@
"""
**************
Graph Matching
**************
Given a graph G = (V,E), a matching M in G is a set of pairwise non-adjacent
edges; that is, no two edges share a common vertex.
`Wikipedia: Matching <https://en.wikipedia.org/wiki/Matching_(graph_theory)>`_
"""
import networkx as nx
__all__ = ["min_maximal_matching"]
def min_maximal_matching(G):
r"""Returns the minimum maximal matching of G. That is, out of all maximal
matchings of the graph G, the smallest is returned.
Parameters
----------
G : NetworkX graph
Undirected graph
Returns
-------
min_maximal_matching : set
Returns a set of edges such that no two edges share a common endpoint
and every edge not in the set shares some common endpoint in the set.
Cardinality will be 2*OPT in the worst case.
Notes
-----
The algorithm computes an approximate solution fo the minimum maximal
cardinality matching problem. The solution is no more than 2 * OPT in size.
Runtime is $O(|E|)$.
References
----------
.. [1] Vazirani, Vijay Approximation Algorithms (2001)
"""
return nx.maximal_matching(G)

View file

@ -0,0 +1,42 @@
"""
Ramsey numbers.
"""
import networkx as nx
from ...utils import arbitrary_element
__all__ = ["ramsey_R2"]
def ramsey_R2(G):
r"""Compute the largest clique and largest independent set in `G`.
This can be used to estimate bounds for the 2-color
Ramsey number `R(2;s,t)` for `G`.
This is a recursive implementation which could run into trouble
for large recursions. Note that self-loop edges are ignored.
Parameters
----------
G : NetworkX graph
Undirected graph
Returns
-------
max_pair : (set, set) tuple
Maximum clique, Maximum independent set.
"""
if not G:
return set(), set()
node = arbitrary_element(G)
nbrs = (nbr for nbr in nx.all_neighbors(G, node) if nbr != node)
nnbrs = nx.non_neighbors(G, node)
c_1, i_1 = ramsey_R2(G.subgraph(nbrs).copy())
c_2, i_2 = ramsey_R2(G.subgraph(nnbrs).copy())
c_1.add(node)
i_2.add(node)
# Choose the larger of the two cliques and the larger of the two
# independent sets, according to cardinality.
return max(c_1, c_2, key=len), max(i_1, i_2, key=len)

View file

@ -0,0 +1,104 @@
from itertools import chain
from networkx.utils import pairwise, not_implemented_for
import networkx as nx
__all__ = ["metric_closure", "steiner_tree"]
@not_implemented_for("directed")
def metric_closure(G, weight="weight"):
""" Return the metric closure of a graph.
The metric closure of a graph *G* is the complete graph in which each edge
is weighted by the shortest path distance between the nodes in *G* .
Parameters
----------
G : NetworkX graph
Returns
-------
NetworkX graph
Metric closure of the graph `G`.
"""
M = nx.Graph()
Gnodes = set(G)
# check for connected graph while processing first node
all_paths_iter = nx.all_pairs_dijkstra(G, weight=weight)
u, (distance, path) = next(all_paths_iter)
if Gnodes - set(distance):
msg = "G is not a connected graph. metric_closure is not defined."
raise nx.NetworkXError(msg)
Gnodes.remove(u)
for v in Gnodes:
M.add_edge(u, v, distance=distance[v], path=path[v])
# first node done -- now process the rest
for u, (distance, path) in all_paths_iter:
Gnodes.remove(u)
for v in Gnodes:
M.add_edge(u, v, distance=distance[v], path=path[v])
return M
@not_implemented_for("directed")
def steiner_tree(G, terminal_nodes, weight="weight"):
""" Return an approximation to the minimum Steiner tree of a graph.
The minimum Steiner tree of `G` w.r.t a set of `terminal_nodes`
is a tree within `G` that spans those nodes and has minimum size
(sum of edge weights) among all such trees.
The minimum Steiner tree can be approximated by computing the minimum
spanning tree of the subgraph of the metric closure of *G* induced by the
terminal nodes, where the metric closure of *G* is the complete graph in
which each edge is weighted by the shortest path distance between the
nodes in *G* .
This algorithm produces a tree whose weight is within a (2 - (2 / t))
factor of the weight of the optimal Steiner tree where *t* is number of
terminal nodes.
Parameters
----------
G : NetworkX graph
terminal_nodes : list
A list of terminal nodes for which minimum steiner tree is
to be found.
Returns
-------
NetworkX graph
Approximation to the minimum steiner tree of `G` induced by
`terminal_nodes` .
Notes
-----
For multigraphs, the edge between two nodes with minimum weight is the
edge put into the Steiner tree.
References
----------
.. [1] Steiner_tree_problem on Wikipedia.
https://en.wikipedia.org/wiki/Steiner_tree_problem
"""
# H is the subgraph induced by terminal_nodes in the metric closure M of G.
M = metric_closure(G, weight=weight)
H = M.subgraph(terminal_nodes)
# Use the 'distance' attribute of each edge provided by M.
mst_edges = nx.minimum_spanning_edges(H, weight="distance", data=True)
# Create an iterator over each edge in each shortest path; repeats are okay
edges = chain.from_iterable(pairwise(d["path"]) for u, v, d in mst_edges)
# For multigraph we should add the minimal weight edge keys
if G.is_multigraph():
edges = (
(u, v, min(G[u][v], key=lambda k: G[u][v][k][weight])) for u, v in edges
)
T = G.edge_subgraph(edges)
return T

View file

@ -0,0 +1,43 @@
import networkx as nx
from networkx.algorithms.approximation import average_clustering
# This approximation has to be be exact in regular graphs
# with no triangles or with all possible triangles.
def test_petersen():
# Actual coefficient is 0
G = nx.petersen_graph()
assert average_clustering(G, trials=int(len(G) / 2)) == nx.average_clustering(G)
def test_petersen_seed():
# Actual coefficient is 0
G = nx.petersen_graph()
assert average_clustering(
G, trials=int(len(G) / 2), seed=1
) == nx.average_clustering(G)
def test_tetrahedral():
# Actual coefficient is 1
G = nx.tetrahedral_graph()
assert average_clustering(G, trials=int(len(G) / 2)) == nx.average_clustering(G)
def test_dodecahedral():
# Actual coefficient is 0
G = nx.dodecahedral_graph()
assert average_clustering(G, trials=int(len(G) / 2)) == nx.average_clustering(G)
def test_empty():
G = nx.empty_graph(5)
assert average_clustering(G, trials=int(len(G) / 2)) == 0
def test_complete():
G = nx.complete_graph(5)
assert average_clustering(G, trials=int(len(G) / 2)) == 1
G = nx.complete_graph(7)
assert average_clustering(G, trials=int(len(G) / 2)) == 1

View file

@ -0,0 +1,107 @@
"""Unit tests for the :mod:`networkx.algorithms.approximation.clique`
module.
"""
import networkx as nx
from networkx.algorithms.approximation import max_clique
from networkx.algorithms.approximation import clique_removal
from networkx.algorithms.approximation import large_clique_size
def is_independent_set(G, nodes):
"""Returns True if and only if `nodes` is a clique in `G`.
`G` is a NetworkX graph. `nodes` is an iterable of nodes in
`G`.
"""
return G.subgraph(nodes).number_of_edges() == 0
def is_clique(G, nodes):
"""Returns True if and only if `nodes` is an independent set
in `G`.
`G` is an undirected simple graph. `nodes` is an iterable of
nodes in `G`.
"""
H = G.subgraph(nodes)
n = len(H)
return H.number_of_edges() == n * (n - 1) // 2
class TestCliqueRemoval:
"""Unit tests for the
:func:`~networkx.algorithms.approximation.clique_removal` function.
"""
def test_trivial_graph(self):
G = nx.trivial_graph()
independent_set, cliques = clique_removal(G)
assert is_independent_set(G, independent_set)
assert all(is_clique(G, clique) for clique in cliques)
# In fact, we should only have 1-cliques, that is, singleton nodes.
assert all(len(clique) == 1 for clique in cliques)
def test_complete_graph(self):
G = nx.complete_graph(10)
independent_set, cliques = clique_removal(G)
assert is_independent_set(G, independent_set)
assert all(is_clique(G, clique) for clique in cliques)
def test_barbell_graph(self):
G = nx.barbell_graph(10, 5)
independent_set, cliques = clique_removal(G)
assert is_independent_set(G, independent_set)
assert all(is_clique(G, clique) for clique in cliques)
class TestMaxClique:
"""Unit tests for the :func:`networkx.algorithms.approximation.max_clique`
function.
"""
def test_null_graph(self):
G = nx.null_graph()
assert len(max_clique(G)) == 0
def test_complete_graph(self):
graph = nx.complete_graph(30)
# this should return the entire graph
mc = max_clique(graph)
assert 30 == len(mc)
def test_maximal_by_cardinality(self):
"""Tests that the maximal clique is computed according to maximum
cardinality of the sets.
For more information, see pull request #1531.
"""
G = nx.complete_graph(5)
G.add_edge(4, 5)
clique = max_clique(G)
assert len(clique) > 1
G = nx.lollipop_graph(30, 2)
clique = max_clique(G)
assert len(clique) > 2
def test_large_clique_size():
G = nx.complete_graph(9)
nx.add_cycle(G, [9, 10, 11])
G.add_edge(8, 9)
G.add_edge(1, 12)
G.add_node(13)
assert large_clique_size(G) == 9
G.remove_node(5)
assert large_clique_size(G) == 8
G.remove_edge(2, 3)
assert large_clique_size(G) == 7

View file

@ -0,0 +1,199 @@
import pytest
import networkx as nx
from networkx.algorithms import approximation as approx
def test_global_node_connectivity():
# Figure 1 chapter on Connectivity
G = nx.Graph()
G.add_edges_from(
[
(1, 2),
(1, 3),
(1, 4),
(1, 5),
(2, 3),
(2, 6),
(3, 4),
(3, 6),
(4, 6),
(4, 7),
(5, 7),
(6, 8),
(6, 9),
(7, 8),
(7, 10),
(8, 11),
(9, 10),
(9, 11),
(10, 11),
]
)
assert 2 == approx.local_node_connectivity(G, 1, 11)
assert 2 == approx.node_connectivity(G)
assert 2 == approx.node_connectivity(G, 1, 11)
def test_white_harary1():
# Figure 1b white and harary (2001)
# A graph with high adhesion (edge connectivity) and low cohesion
# (node connectivity)
G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4))
G.remove_node(7)
for i in range(4, 7):
G.add_edge(0, i)
G = nx.disjoint_union(G, nx.complete_graph(4))
G.remove_node(G.order() - 1)
for i in range(7, 10):
G.add_edge(0, i)
assert 1 == approx.node_connectivity(G)
def test_complete_graphs():
for n in range(5, 25, 5):
G = nx.complete_graph(n)
assert n - 1 == approx.node_connectivity(G)
assert n - 1 == approx.node_connectivity(G, 0, 3)
def test_empty_graphs():
for k in range(5, 25, 5):
G = nx.empty_graph(k)
assert 0 == approx.node_connectivity(G)
assert 0 == approx.node_connectivity(G, 0, 3)
def test_petersen():
G = nx.petersen_graph()
assert 3 == approx.node_connectivity(G)
assert 3 == approx.node_connectivity(G, 0, 5)
# Approximation fails with tutte graph
# def test_tutte():
# G = nx.tutte_graph()
# assert_equal(3, approx.node_connectivity(G))
def test_dodecahedral():
G = nx.dodecahedral_graph()
assert 3 == approx.node_connectivity(G)
assert 3 == approx.node_connectivity(G, 0, 5)
def test_octahedral():
G = nx.octahedral_graph()
assert 4 == approx.node_connectivity(G)
assert 4 == approx.node_connectivity(G, 0, 5)
# Approximation can fail with icosahedral graph depending
# on iteration order.
# def test_icosahedral():
# G=nx.icosahedral_graph()
# assert_equal(5, approx.node_connectivity(G))
# assert_equal(5, approx.node_connectivity(G, 0, 5))
def test_only_source():
G = nx.complete_graph(5)
pytest.raises(nx.NetworkXError, approx.node_connectivity, G, s=0)
def test_only_target():
G = nx.complete_graph(5)
pytest.raises(nx.NetworkXError, approx.node_connectivity, G, t=0)
def test_missing_source():
G = nx.path_graph(4)
pytest.raises(nx.NetworkXError, approx.node_connectivity, G, 10, 1)
def test_missing_target():
G = nx.path_graph(4)
pytest.raises(nx.NetworkXError, approx.node_connectivity, G, 1, 10)
def test_source_equals_target():
G = nx.complete_graph(5)
pytest.raises(nx.NetworkXError, approx.local_node_connectivity, G, 0, 0)
def test_directed_node_connectivity():
G = nx.cycle_graph(10, create_using=nx.DiGraph()) # only one direction
D = nx.cycle_graph(10).to_directed() # 2 reciprocal edges
assert 1 == approx.node_connectivity(G)
assert 1 == approx.node_connectivity(G, 1, 4)
assert 2 == approx.node_connectivity(D)
assert 2 == approx.node_connectivity(D, 1, 4)
class TestAllPairsNodeConnectivityApprox:
@classmethod
def setup_class(cls):
cls.path = nx.path_graph(7)
cls.directed_path = nx.path_graph(7, create_using=nx.DiGraph())
cls.cycle = nx.cycle_graph(7)
cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph())
cls.gnp = nx.gnp_random_graph(30, 0.1)
cls.directed_gnp = nx.gnp_random_graph(30, 0.1, directed=True)
cls.K20 = nx.complete_graph(20)
cls.K10 = nx.complete_graph(10)
cls.K5 = nx.complete_graph(5)
cls.G_list = [
cls.path,
cls.directed_path,
cls.cycle,
cls.directed_cycle,
cls.gnp,
cls.directed_gnp,
cls.K10,
cls.K5,
cls.K20,
]
def test_cycles(self):
K_undir = approx.all_pairs_node_connectivity(self.cycle)
for source in K_undir:
for target, k in K_undir[source].items():
assert k == 2
K_dir = approx.all_pairs_node_connectivity(self.directed_cycle)
for source in K_dir:
for target, k in K_dir[source].items():
assert k == 1
def test_complete(self):
for G in [self.K10, self.K5, self.K20]:
K = approx.all_pairs_node_connectivity(G)
for source in K:
for target, k in K[source].items():
assert k == len(G) - 1
def test_paths(self):
K_undir = approx.all_pairs_node_connectivity(self.path)
for source in K_undir:
for target, k in K_undir[source].items():
assert k == 1
K_dir = approx.all_pairs_node_connectivity(self.directed_path)
for source in K_dir:
for target, k in K_dir[source].items():
if source < target:
assert k == 1
else:
assert k == 0
def test_cutoff(self):
for G in [self.K10, self.K5, self.K20]:
for mp in [2, 3, 4]:
paths = approx.all_pairs_node_connectivity(G, cutoff=mp)
for source in paths:
for target, K in paths[source].items():
assert K == mp
def test_all_pairs_connectivity_nbunch(self):
G = nx.complete_graph(5)
nbunch = [0, 2, 3]
C = approx.all_pairs_node_connectivity(G, nbunch=nbunch)
assert len(C) == len(nbunch)

View file

@ -0,0 +1,65 @@
import networkx as nx
from networkx.algorithms.approximation import min_weighted_dominating_set
from networkx.algorithms.approximation import min_edge_dominating_set
class TestMinWeightDominatingSet:
def test_min_weighted_dominating_set(self):
graph = nx.Graph()
graph.add_edge(1, 2)
graph.add_edge(1, 5)
graph.add_edge(2, 3)
graph.add_edge(2, 5)
graph.add_edge(3, 4)
graph.add_edge(3, 6)
graph.add_edge(5, 6)
vertices = {1, 2, 3, 4, 5, 6}
# due to ties, this might be hard to test tight bounds
dom_set = min_weighted_dominating_set(graph)
for vertex in vertices - dom_set:
neighbors = set(graph.neighbors(vertex))
assert len(neighbors & dom_set) > 0, "Non dominating set found!"
def test_star_graph(self):
"""Tests that an approximate dominating set for the star graph,
even when the center node does not have the smallest integer
label, gives just the center node.
For more information, see #1527.
"""
# Create a star graph in which the center node has the highest
# label instead of the lowest.
G = nx.star_graph(10)
G = nx.relabel_nodes(G, {0: 9, 9: 0})
assert min_weighted_dominating_set(G) == {9}
def test_min_edge_dominating_set(self):
graph = nx.path_graph(5)
dom_set = min_edge_dominating_set(graph)
# this is a crappy way to test, but good enough for now.
for edge in graph.edges():
if edge in dom_set:
continue
else:
u, v = edge
found = False
for dom_edge in dom_set:
found |= u == dom_edge[0] or u == dom_edge[1]
assert found, "Non adjacent edge found!"
graph = nx.complete_graph(10)
dom_set = min_edge_dominating_set(graph)
# this is a crappy way to test, but good enough for now.
for edge in graph.edges():
if edge in dom_set:
continue
else:
u, v = edge
found = False
for dom_edge in dom_set:
found |= u == dom_edge[0] or u == dom_edge[1]
assert found, "Non adjacent edge found!"

Some files were not shown because too many files have changed in this diff Show more