harary_graph.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. """Generators for Harary graphs
  2. This module gives two generators for the Harary graph, which was
  3. introduced by the famous mathematician Frank Harary in his 1962 work [H]_.
  4. The first generator gives the Harary graph that maximizes the node
  5. connectivity with given number of nodes and given number of edges.
  6. The second generator gives the Harary graph that minimizes
  7. the number of edges in the graph with given node connectivity and
  8. number of nodes.
  9. References
  10. ----------
  11. .. [H] Harary, F. "The Maximum Connectivity of a Graph."
  12. Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962.
  13. """
  14. import networkx as nx
  15. from networkx.exception import NetworkXError
  16. __all__ = ["hnm_harary_graph", "hkn_harary_graph"]
  17. def hnm_harary_graph(n, m, create_using=None):
  18. """Returns the Harary graph with given numbers of nodes and edges.
  19. The Harary graph $H_{n,m}$ is the graph that maximizes node connectivity
  20. with $n$ nodes and $m$ edges.
  21. This maximum node connectivity is known to be floor($2m/n$). [1]_
  22. Parameters
  23. ----------
  24. n: integer
  25. The number of nodes the generated graph is to contain
  26. m: integer
  27. The number of edges the generated graph is to contain
  28. create_using : NetworkX graph constructor, optional Graph type
  29. to create (default=nx.Graph). If graph instance, then cleared
  30. before populated.
  31. Returns
  32. -------
  33. NetworkX graph
  34. The Harary graph $H_{n,m}$.
  35. See Also
  36. --------
  37. hkn_harary_graph
  38. Notes
  39. -----
  40. This algorithm runs in $O(m)$ time.
  41. It is implemented by following the Reference [2]_.
  42. References
  43. ----------
  44. .. [1] F. T. Boesch, A. Satyanarayana, and C. L. Suffel,
  45. "A Survey of Some Network Reliability Analysis and Synthesis Results,"
  46. Networks, pp. 99-107, 2009.
  47. .. [2] Harary, F. "The Maximum Connectivity of a Graph."
  48. Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962.
  49. """
  50. if n < 1:
  51. raise NetworkXError("The number of nodes must be >= 1!")
  52. if m < n - 1:
  53. raise NetworkXError("The number of edges must be >= n - 1 !")
  54. if m > n * (n - 1) // 2:
  55. raise NetworkXError("The number of edges must be <= n(n-1)/2")
  56. # Construct an empty graph with n nodes first
  57. H = nx.empty_graph(n, create_using)
  58. # Get the floor of average node degree
  59. d = 2 * m // n
  60. # Test the parity of n and d
  61. if (n % 2 == 0) or (d % 2 == 0):
  62. # Start with a regular graph of d degrees
  63. offset = d // 2
  64. for i in range(n):
  65. for j in range(1, offset + 1):
  66. H.add_edge(i, (i - j) % n)
  67. H.add_edge(i, (i + j) % n)
  68. if d & 1:
  69. # in case d is odd; n must be even in this case
  70. half = n // 2
  71. for i in range(0, half):
  72. # add edges diagonally
  73. H.add_edge(i, i + half)
  74. # Get the remainder of 2*m modulo n
  75. r = 2 * m % n
  76. if r > 0:
  77. # add remaining edges at offset+1
  78. for i in range(0, r // 2):
  79. H.add_edge(i, i + offset + 1)
  80. else:
  81. # Start with a regular graph of (d - 1) degrees
  82. offset = (d - 1) // 2
  83. for i in range(n):
  84. for j in range(1, offset + 1):
  85. H.add_edge(i, (i - j) % n)
  86. H.add_edge(i, (i + j) % n)
  87. half = n // 2
  88. for i in range(0, m - n * offset):
  89. # add the remaining m - n*offset edges between i and i+half
  90. H.add_edge(i, (i + half) % n)
  91. return H
  92. def hkn_harary_graph(k, n, create_using=None):
  93. """Returns the Harary graph with given node connectivity and node number.
  94. The Harary graph $H_{k,n}$ is the graph that minimizes the number of
  95. edges needed with given node connectivity $k$ and node number $n$.
  96. This smallest number of edges is known to be ceil($kn/2$) [1]_.
  97. Parameters
  98. ----------
  99. k: integer
  100. The node connectivity of the generated graph
  101. n: integer
  102. The number of nodes the generated graph is to contain
  103. create_using : NetworkX graph constructor, optional Graph type
  104. to create (default=nx.Graph). If graph instance, then cleared
  105. before populated.
  106. Returns
  107. -------
  108. NetworkX graph
  109. The Harary graph $H_{k,n}$.
  110. See Also
  111. --------
  112. hnm_harary_graph
  113. Notes
  114. -----
  115. This algorithm runs in $O(kn)$ time.
  116. It is implemented by following the Reference [2]_.
  117. References
  118. ----------
  119. .. [1] Weisstein, Eric W. "Harary Graph." From MathWorld--A Wolfram Web
  120. Resource. http://mathworld.wolfram.com/HararyGraph.html.
  121. .. [2] Harary, F. "The Maximum Connectivity of a Graph."
  122. Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962.
  123. """
  124. if k < 1:
  125. raise NetworkXError("The node connectivity must be >= 1!")
  126. if n < k + 1:
  127. raise NetworkXError("The number of nodes must be >= k+1 !")
  128. # in case of connectivity 1, simply return the path graph
  129. if k == 1:
  130. H = nx.path_graph(n, create_using)
  131. return H
  132. # Construct an empty graph with n nodes first
  133. H = nx.empty_graph(n, create_using)
  134. # Test the parity of k and n
  135. if (k % 2 == 0) or (n % 2 == 0):
  136. # Construct a regular graph with k degrees
  137. offset = k // 2
  138. for i in range(n):
  139. for j in range(1, offset + 1):
  140. H.add_edge(i, (i - j) % n)
  141. H.add_edge(i, (i + j) % n)
  142. if k & 1:
  143. # odd degree; n must be even in this case
  144. half = n // 2
  145. for i in range(0, half):
  146. # add edges diagonally
  147. H.add_edge(i, i + half)
  148. else:
  149. # Construct a regular graph with (k - 1) degrees
  150. offset = (k - 1) // 2
  151. for i in range(n):
  152. for j in range(1, offset + 1):
  153. H.add_edge(i, (i - j) % n)
  154. H.add_edge(i, (i + j) % n)
  155. half = n // 2
  156. for i in range(0, half + 1):
  157. # add half+1 edges between i and i+half
  158. H.add_edge(i, (i + half) % n)
  159. return H