utils.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. """
  2. Utilities for connectivity package
  3. """
  4. import networkx as nx
  5. __all__ = ["build_auxiliary_node_connectivity", "build_auxiliary_edge_connectivity"]
  6. @nx._dispatchable(returns_graph=True)
  7. def build_auxiliary_node_connectivity(G):
  8. r"""Creates a directed graph D from an undirected graph G to compute flow
  9. based node connectivity.
  10. For an undirected graph G having `n` nodes and `m` edges we derive a
  11. directed graph D with `2n` nodes and `2m+n` arcs by replacing each
  12. original node `v` with two nodes `vA`, `vB` linked by an (internal)
  13. arc in D. Then for each edge (`u`, `v`) in G we add two arcs (`uB`, `vA`)
  14. and (`vB`, `uA`) in D. Finally we set the attribute capacity = 1 for each
  15. arc in D [1]_.
  16. For a directed graph having `n` nodes and `m` arcs we derive a
  17. directed graph D with `2n` nodes and `m+n` arcs by replacing each
  18. original node `v` with two nodes `vA`, `vB` linked by an (internal)
  19. arc (`vA`, `vB`) in D. Then for each arc (`u`, `v`) in G we add one
  20. arc (`uB`, `vA`) in D. Finally we set the attribute capacity = 1 for
  21. each arc in D.
  22. A dictionary with a mapping between nodes in the original graph and the
  23. auxiliary digraph is stored as a graph attribute: D.graph['mapping'].
  24. References
  25. ----------
  26. .. [1] Kammer, Frank and Hanjo Taubig. Graph Connectivity. in Brandes and
  27. Erlebach, 'Network Analysis: Methodological Foundations', Lecture
  28. Notes in Computer Science, Volume 3418, Springer-Verlag, 2005.
  29. https://doi.org/10.1007/978-3-540-31955-9_7
  30. """
  31. directed = G.is_directed()
  32. mapping = {}
  33. H = nx.DiGraph()
  34. for i, node in enumerate(G):
  35. mapping[node] = i
  36. H.add_node(f"{i}A", id=node)
  37. H.add_node(f"{i}B", id=node)
  38. H.add_edge(f"{i}A", f"{i}B", capacity=1)
  39. edges = []
  40. for source, target in G.edges():
  41. edges.append((f"{mapping[source]}B", f"{mapping[target]}A"))
  42. if not directed:
  43. edges.append((f"{mapping[target]}B", f"{mapping[source]}A"))
  44. H.add_edges_from(edges, capacity=1)
  45. # Store mapping as graph attribute
  46. H.graph["mapping"] = mapping
  47. return H
  48. @nx._dispatchable(returns_graph=True)
  49. def build_auxiliary_edge_connectivity(G):
  50. """Auxiliary digraph for computing flow based edge connectivity
  51. If the input graph is undirected, we replace each edge (`u`,`v`) with
  52. two reciprocal arcs (`u`, `v`) and (`v`, `u`) and then we set the attribute
  53. 'capacity' for each arc to 1. If the input graph is directed we simply
  54. add the 'capacity' attribute. Part of algorithm 1 in [1]_ .
  55. References
  56. ----------
  57. .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. (this is a
  58. chapter, look for the reference of the book).
  59. http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
  60. """
  61. if G.is_directed():
  62. H = nx.DiGraph()
  63. H.add_nodes_from(G.nodes())
  64. H.add_edges_from(G.edges(), capacity=1)
  65. return H
  66. else:
  67. H = nx.DiGraph()
  68. H.add_nodes_from(G.nodes())
  69. for source, target in G.edges():
  70. H.add_edges_from([(source, target), (target, source)], capacity=1)
  71. return H