okstra 0.108.0 → 0.110.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (648) hide show
  1. package/README.kr.md +1 -1
  2. package/README.md +1 -1
  3. package/docs/kr/architecture.md +3 -3
  4. package/docs/kr/cli.md +2 -2
  5. package/docs/project-structure-overview.md +3 -3
  6. package/package.json +1 -1
  7. package/runtime/BUILD.json +2 -2
  8. package/runtime/prompts/profiles/_common-contract.md +1 -1
  9. package/runtime/python/okstra_ctl/graphify_cmd.py +225 -0
  10. package/runtime/python/okstra_ctl/resolve_task_key.py +15 -9
  11. package/runtime/python/okstra_ctl/worktree.py +14 -13
  12. package/runtime/python/okstra_project/__init__.py +2 -0
  13. package/runtime/python/okstra_project/state.py +36 -0
  14. package/runtime/python/okstra_vendor/__init__.py +41 -0
  15. package/runtime/python/okstra_vendor/graphify/.vendored-version +1 -0
  16. package/runtime/python/okstra_vendor/graphify/__init__.py +28 -0
  17. package/runtime/python/okstra_vendor/graphify/__main__.py +1371 -0
  18. package/runtime/python/okstra_vendor/graphify/analyze.py +540 -0
  19. package/runtime/python/okstra_vendor/graphify/benchmark.py +129 -0
  20. package/runtime/python/okstra_vendor/graphify/build.py +107 -0
  21. package/runtime/python/okstra_vendor/graphify/cache.py +169 -0
  22. package/runtime/python/okstra_vendor/graphify/cluster.py +137 -0
  23. package/runtime/python/okstra_vendor/graphify/detect.py +510 -0
  24. package/runtime/python/okstra_vendor/graphify/export.py +1014 -0
  25. package/runtime/python/okstra_vendor/graphify/extract.py +3277 -0
  26. package/runtime/python/okstra_vendor/graphify/hooks.py +220 -0
  27. package/runtime/python/okstra_vendor/graphify/ingest.py +297 -0
  28. package/runtime/python/okstra_vendor/graphify/manifest.py +4 -0
  29. package/runtime/python/okstra_vendor/graphify/report.py +175 -0
  30. package/runtime/python/okstra_vendor/graphify/security.py +203 -0
  31. package/runtime/python/okstra_vendor/graphify/serve.py +373 -0
  32. package/runtime/python/okstra_vendor/graphify/skill-aider.md +1184 -0
  33. package/runtime/python/okstra_vendor/graphify/skill-claw.md +1184 -0
  34. package/runtime/python/okstra_vendor/graphify/skill-codex.md +1242 -0
  35. package/runtime/python/okstra_vendor/graphify/skill-copilot.md +1268 -0
  36. package/runtime/python/okstra_vendor/graphify/skill-droid.md +1239 -0
  37. package/runtime/python/okstra_vendor/graphify/skill-kiro.md +1183 -0
  38. package/runtime/python/okstra_vendor/graphify/skill-opencode.md +1238 -0
  39. package/runtime/python/okstra_vendor/graphify/skill-trae.md +1208 -0
  40. package/runtime/python/okstra_vendor/graphify/skill-vscode.md +253 -0
  41. package/runtime/python/okstra_vendor/graphify/skill-windows.md +1245 -0
  42. package/runtime/python/okstra_vendor/graphify/skill.md +1319 -0
  43. package/runtime/python/okstra_vendor/graphify/transcribe.py +182 -0
  44. package/runtime/python/okstra_vendor/graphify/validate.py +72 -0
  45. package/runtime/python/okstra_vendor/graphify/watch.py +188 -0
  46. package/runtime/python/okstra_vendor/graphify/wiki.py +214 -0
  47. package/runtime/python/okstra_vendor/networkx/__init__.py +62 -0
  48. package/runtime/python/okstra_vendor/networkx/algorithms/__init__.py +134 -0
  49. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/__init__.py +26 -0
  50. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clique.py +259 -0
  51. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clustering_coefficient.py +71 -0
  52. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/connectivity.py +412 -0
  53. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/density.py +396 -0
  54. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/distance_measures.py +150 -0
  55. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/dominating_set.py +149 -0
  56. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/kcomponents.py +369 -0
  57. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/matching.py +44 -0
  58. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/maxcut.py +143 -0
  59. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/ramsey.py +53 -0
  60. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/steinertree.py +265 -0
  61. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
  62. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +41 -0
  63. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +112 -0
  64. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +199 -0
  65. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +146 -0
  66. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +59 -0
  67. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +78 -0
  68. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +303 -0
  69. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +8 -0
  70. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +94 -0
  71. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +31 -0
  72. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +306 -0
  73. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +1014 -0
  74. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +274 -0
  75. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +68 -0
  76. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/traveling_salesman.py +1508 -0
  77. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/treewidth.py +255 -0
  78. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/vertex_cover.py +83 -0
  79. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/__init__.py +5 -0
  80. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/connectivity.py +122 -0
  81. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/correlation.py +302 -0
  82. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/mixing.py +255 -0
  83. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/neighbor_degree.py +160 -0
  84. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/pairs.py +127 -0
  85. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
  86. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +81 -0
  87. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +143 -0
  88. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +122 -0
  89. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +174 -0
  90. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +107 -0
  91. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +87 -0
  92. package/runtime/python/okstra_vendor/networkx/algorithms/asteroidal.py +164 -0
  93. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/__init__.py +88 -0
  94. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/basic.py +322 -0
  95. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/centrality.py +290 -0
  96. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/cluster.py +289 -0
  97. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/covering.py +57 -0
  98. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/edgelist.py +360 -0
  99. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/extendability.py +105 -0
  100. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/generators.py +603 -0
  101. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/link_analysis.py +316 -0
  102. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matching.py +590 -0
  103. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matrix.py +232 -0
  104. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/projection.py +526 -0
  105. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/redundancy.py +112 -0
  106. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/spectral.py +69 -0
  107. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
  108. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +125 -0
  109. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +192 -0
  110. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +84 -0
  111. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +33 -0
  112. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +240 -0
  113. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +334 -0
  114. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +407 -0
  115. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +218 -0
  116. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +327 -0
  117. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +138 -0
  118. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +409 -0
  119. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +35 -0
  120. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +80 -0
  121. package/runtime/python/okstra_vendor/networkx/algorithms/boundary.py +168 -0
  122. package/runtime/python/okstra_vendor/networkx/algorithms/bridges.py +205 -0
  123. package/runtime/python/okstra_vendor/networkx/algorithms/broadcasting.py +164 -0
  124. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/__init__.py +20 -0
  125. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness.py +591 -0
  126. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness_subset.py +236 -0
  127. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/closeness.py +282 -0
  128. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness.py +364 -0
  129. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness_subset.py +227 -0
  130. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_closeness.py +96 -0
  131. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/degree_alg.py +150 -0
  132. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/dispersion.py +107 -0
  133. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/eigenvector.py +357 -0
  134. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/flow_matrix.py +130 -0
  135. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/group.py +787 -0
  136. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/harmonic.py +88 -0
  137. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/katz.py +331 -0
  138. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/laplacian.py +150 -0
  139. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/load.py +200 -0
  140. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/percolation.py +128 -0
  141. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/reaching.py +209 -0
  142. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/second_order.py +141 -0
  143. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/subgraph_alg.py +361 -0
  144. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
  145. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +923 -0
  146. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +354 -0
  147. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +274 -0
  148. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +259 -0
  149. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +147 -0
  150. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +43 -0
  151. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +144 -0
  152. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +73 -0
  153. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +186 -0
  154. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +277 -0
  155. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +122 -0
  156. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +345 -0
  157. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +220 -0
  158. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +344 -0
  159. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +87 -0
  160. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +140 -0
  161. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +82 -0
  162. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +110 -0
  163. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +302 -0
  164. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +64 -0
  165. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/trophic.py +181 -0
  166. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/voterank_alg.py +95 -0
  167. package/runtime/python/okstra_vendor/networkx/algorithms/chains.py +172 -0
  168. package/runtime/python/okstra_vendor/networkx/algorithms/chordal.py +443 -0
  169. package/runtime/python/okstra_vendor/networkx/algorithms/clique.py +818 -0
  170. package/runtime/python/okstra_vendor/networkx/algorithms/cluster.py +732 -0
  171. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/__init__.py +4 -0
  172. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/equitable_coloring.py +505 -0
  173. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/greedy_coloring.py +565 -0
  174. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
  175. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +863 -0
  176. package/runtime/python/okstra_vendor/networkx/algorithms/communicability_alg.py +163 -0
  177. package/runtime/python/okstra_vendor/networkx/algorithms/community/__init__.py +28 -0
  178. package/runtime/python/okstra_vendor/networkx/algorithms/community/asyn_fluid.py +153 -0
  179. package/runtime/python/okstra_vendor/networkx/algorithms/community/bipartitions.py +354 -0
  180. package/runtime/python/okstra_vendor/networkx/algorithms/community/centrality.py +171 -0
  181. package/runtime/python/okstra_vendor/networkx/algorithms/community/community_utils.py +30 -0
  182. package/runtime/python/okstra_vendor/networkx/algorithms/community/divisive.py +216 -0
  183. package/runtime/python/okstra_vendor/networkx/algorithms/community/kclique.py +79 -0
  184. package/runtime/python/okstra_vendor/networkx/algorithms/community/label_propagation.py +338 -0
  185. package/runtime/python/okstra_vendor/networkx/algorithms/community/leiden.py +162 -0
  186. package/runtime/python/okstra_vendor/networkx/algorithms/community/local.py +220 -0
  187. package/runtime/python/okstra_vendor/networkx/algorithms/community/louvain.py +384 -0
  188. package/runtime/python/okstra_vendor/networkx/algorithms/community/lukes.py +227 -0
  189. package/runtime/python/okstra_vendor/networkx/algorithms/community/modularity_max.py +452 -0
  190. package/runtime/python/okstra_vendor/networkx/algorithms/community/quality.py +347 -0
  191. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
  192. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +147 -0
  193. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +157 -0
  194. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +85 -0
  195. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +106 -0
  196. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +91 -0
  197. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +241 -0
  198. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +138 -0
  199. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +76 -0
  200. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +264 -0
  201. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +152 -0
  202. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +340 -0
  203. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +139 -0
  204. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +26 -0
  205. package/runtime/python/okstra_vendor/networkx/algorithms/components/__init__.py +6 -0
  206. package/runtime/python/okstra_vendor/networkx/algorithms/components/attracting.py +115 -0
  207. package/runtime/python/okstra_vendor/networkx/algorithms/components/biconnected.py +394 -0
  208. package/runtime/python/okstra_vendor/networkx/algorithms/components/connected.py +282 -0
  209. package/runtime/python/okstra_vendor/networkx/algorithms/components/semiconnected.py +71 -0
  210. package/runtime/python/okstra_vendor/networkx/algorithms/components/strongly_connected.py +359 -0
  211. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
  212. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +70 -0
  213. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +248 -0
  214. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +138 -0
  215. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +55 -0
  216. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +193 -0
  217. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +96 -0
  218. package/runtime/python/okstra_vendor/networkx/algorithms/components/weakly_connected.py +196 -0
  219. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/__init__.py +11 -0
  220. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/connectivity.py +811 -0
  221. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/cuts.py +616 -0
  222. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/disjoint_paths.py +408 -0
  223. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_augmentation.py +1270 -0
  224. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_kcomponents.py +592 -0
  225. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcomponents.py +220 -0
  226. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcutsets.py +235 -0
  227. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/stoerwagner.py +152 -0
  228. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
  229. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +421 -0
  230. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +309 -0
  231. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +249 -0
  232. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +502 -0
  233. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +488 -0
  234. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +323 -0
  235. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +280 -0
  236. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +102 -0
  237. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/utils.py +88 -0
  238. package/runtime/python/okstra_vendor/networkx/algorithms/core.py +588 -0
  239. package/runtime/python/okstra_vendor/networkx/algorithms/covering.py +142 -0
  240. package/runtime/python/okstra_vendor/networkx/algorithms/cuts.py +416 -0
  241. package/runtime/python/okstra_vendor/networkx/algorithms/cycles.py +1234 -0
  242. package/runtime/python/okstra_vendor/networkx/algorithms/d_separation.py +677 -0
  243. package/runtime/python/okstra_vendor/networkx/algorithms/dag.py +1392 -0
  244. package/runtime/python/okstra_vendor/networkx/algorithms/distance_measures.py +1095 -0
  245. package/runtime/python/okstra_vendor/networkx/algorithms/distance_regular.py +272 -0
  246. package/runtime/python/okstra_vendor/networkx/algorithms/dominance.py +142 -0
  247. package/runtime/python/okstra_vendor/networkx/algorithms/dominating.py +268 -0
  248. package/runtime/python/okstra_vendor/networkx/algorithms/efficiency_measures.py +167 -0
  249. package/runtime/python/okstra_vendor/networkx/algorithms/euler.py +470 -0
  250. package/runtime/python/okstra_vendor/networkx/algorithms/flow/__init__.py +11 -0
  251. package/runtime/python/okstra_vendor/networkx/algorithms/flow/boykovkolmogorov.py +370 -0
  252. package/runtime/python/okstra_vendor/networkx/algorithms/flow/capacityscaling.py +407 -0
  253. package/runtime/python/okstra_vendor/networkx/algorithms/flow/dinitz_alg.py +238 -0
  254. package/runtime/python/okstra_vendor/networkx/algorithms/flow/edmondskarp.py +241 -0
  255. package/runtime/python/okstra_vendor/networkx/algorithms/flow/gomory_hu.py +178 -0
  256. package/runtime/python/okstra_vendor/networkx/algorithms/flow/maxflow.py +611 -0
  257. package/runtime/python/okstra_vendor/networkx/algorithms/flow/mincost.py +356 -0
  258. package/runtime/python/okstra_vendor/networkx/algorithms/flow/networksimplex.py +662 -0
  259. package/runtime/python/okstra_vendor/networkx/algorithms/flow/preflowpush.py +425 -0
  260. package/runtime/python/okstra_vendor/networkx/algorithms/flow/shortestaugmentingpath.py +300 -0
  261. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
  262. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
  263. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
  264. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
  265. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +128 -0
  266. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +573 -0
  267. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +155 -0
  268. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +475 -0
  269. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +481 -0
  270. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
  271. package/runtime/python/okstra_vendor/networkx/algorithms/flow/utils.py +194 -0
  272. package/runtime/python/okstra_vendor/networkx/algorithms/graph_hashing.py +435 -0
  273. package/runtime/python/okstra_vendor/networkx/algorithms/graphical.py +483 -0
  274. package/runtime/python/okstra_vendor/networkx/algorithms/hierarchy.py +57 -0
  275. package/runtime/python/okstra_vendor/networkx/algorithms/hybrid.py +196 -0
  276. package/runtime/python/okstra_vendor/networkx/algorithms/isolate.py +107 -0
  277. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/__init__.py +7 -0
  278. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/ismags.py +1306 -0
  279. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorph.py +336 -0
  280. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorphvf2.py +1262 -0
  281. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/matchhelpers.py +352 -0
  282. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/temporalisomorphvf2.py +308 -0
  283. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
  284. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
  285. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
  286. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
  287. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
  288. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +719 -0
  289. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +103 -0
  290. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +490 -0
  291. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +64 -0
  292. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +212 -0
  293. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +202 -0
  294. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +1655 -0
  295. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +3118 -0
  296. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +196 -0
  297. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tree_isomorphism.py +264 -0
  298. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2pp.py +1102 -0
  299. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2userfunc.py +192 -0
  300. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/__init__.py +2 -0
  301. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/hits_alg.py +337 -0
  302. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/pagerank_alg.py +498 -0
  303. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
  304. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +77 -0
  305. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +213 -0
  306. package/runtime/python/okstra_vendor/networkx/algorithms/link_prediction.py +687 -0
  307. package/runtime/python/okstra_vendor/networkx/algorithms/lowest_common_ancestors.py +280 -0
  308. package/runtime/python/okstra_vendor/networkx/algorithms/matching.py +1148 -0
  309. package/runtime/python/okstra_vendor/networkx/algorithms/minors/__init__.py +27 -0
  310. package/runtime/python/okstra_vendor/networkx/algorithms/minors/contraction.py +738 -0
  311. package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +544 -0
  312. package/runtime/python/okstra_vendor/networkx/algorithms/mis.py +78 -0
  313. package/runtime/python/okstra_vendor/networkx/algorithms/moral.py +59 -0
  314. package/runtime/python/okstra_vendor/networkx/algorithms/node_classification.py +219 -0
  315. package/runtime/python/okstra_vendor/networkx/algorithms/non_randomness.py +155 -0
  316. package/runtime/python/okstra_vendor/networkx/algorithms/operators/__init__.py +4 -0
  317. package/runtime/python/okstra_vendor/networkx/algorithms/operators/all.py +324 -0
  318. package/runtime/python/okstra_vendor/networkx/algorithms/operators/binary.py +468 -0
  319. package/runtime/python/okstra_vendor/networkx/algorithms/operators/product.py +633 -0
  320. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
  321. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +328 -0
  322. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +451 -0
  323. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +491 -0
  324. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +55 -0
  325. package/runtime/python/okstra_vendor/networkx/algorithms/operators/unary.py +77 -0
  326. package/runtime/python/okstra_vendor/networkx/algorithms/perfect_graph.py +73 -0
  327. package/runtime/python/okstra_vendor/networkx/algorithms/planar_drawing.py +464 -0
  328. package/runtime/python/okstra_vendor/networkx/algorithms/planarity.py +1463 -0
  329. package/runtime/python/okstra_vendor/networkx/algorithms/polynomials.py +306 -0
  330. package/runtime/python/okstra_vendor/networkx/algorithms/reciprocity.py +98 -0
  331. package/runtime/python/okstra_vendor/networkx/algorithms/regular.py +167 -0
  332. package/runtime/python/okstra_vendor/networkx/algorithms/richclub.py +138 -0
  333. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/__init__.py +5 -0
  334. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/astar.py +239 -0
  335. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/dense.py +264 -0
  336. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/generic.py +716 -0
  337. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
  338. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +254 -0
  339. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +212 -0
  340. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +88 -0
  341. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +511 -0
  342. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +149 -0
  343. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +983 -0
  344. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/unweighted.py +625 -0
  345. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/weighted.py +2542 -0
  346. package/runtime/python/okstra_vendor/networkx/algorithms/similarity.py +2107 -0
  347. package/runtime/python/okstra_vendor/networkx/algorithms/simple_paths.py +966 -0
  348. package/runtime/python/okstra_vendor/networkx/algorithms/smallworld.py +404 -0
  349. package/runtime/python/okstra_vendor/networkx/algorithms/smetric.py +30 -0
  350. package/runtime/python/okstra_vendor/networkx/algorithms/sparsifiers.py +296 -0
  351. package/runtime/python/okstra_vendor/networkx/algorithms/structuralholes.py +374 -0
  352. package/runtime/python/okstra_vendor/networkx/algorithms/summarization.py +564 -0
  353. package/runtime/python/okstra_vendor/networkx/algorithms/swap.py +406 -0
  354. package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
  355. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +23 -0
  356. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +154 -0
  357. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +144 -0
  358. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +109 -0
  359. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +136 -0
  360. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +129 -0
  361. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +300 -0
  362. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +678 -0
  363. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +80 -0
  364. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +266 -0
  365. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +85 -0
  366. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +171 -0
  367. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +984 -0
  368. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +340 -0
  369. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +835 -0
  370. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +831 -0
  371. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +85 -0
  372. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +299 -0
  373. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +115 -0
  374. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +58 -0
  375. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +314 -0
  376. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +872 -0
  377. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +163 -0
  378. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +46 -0
  379. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +24 -0
  380. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +26 -0
  381. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +615 -0
  382. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +459 -0
  383. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +556 -0
  384. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +179 -0
  385. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +62 -0
  386. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +15 -0
  387. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +140 -0
  388. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +60 -0
  389. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +27 -0
  390. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +274 -0
  391. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +556 -0
  392. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +57 -0
  393. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +37 -0
  394. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +88 -0
  395. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +149 -0
  396. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +1158 -0
  397. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +803 -0
  398. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +76 -0
  399. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +8 -0
  400. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +138 -0
  401. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +191 -0
  402. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +642 -0
  403. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +179 -0
  404. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +270 -0
  405. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +431 -0
  406. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +161 -0
  407. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +248 -0
  408. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +41 -0
  409. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +103 -0
  410. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +54 -0
  411. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +157 -0
  412. package/runtime/python/okstra_vendor/networkx/algorithms/threshold.py +981 -0
  413. package/runtime/python/okstra_vendor/networkx/algorithms/time_dependent.py +142 -0
  414. package/runtime/python/okstra_vendor/networkx/algorithms/tournament.py +406 -0
  415. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/__init__.py +5 -0
  416. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/beamsearch.py +90 -0
  417. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/breadth_first_search.py +576 -0
  418. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/depth_first_search.py +529 -0
  419. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgebfs.py +185 -0
  420. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgedfs.py +182 -0
  421. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
  422. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +25 -0
  423. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +203 -0
  424. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +307 -0
  425. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +147 -0
  426. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +131 -0
  427. package/runtime/python/okstra_vendor/networkx/algorithms/tree/__init__.py +7 -0
  428. package/runtime/python/okstra_vendor/networkx/algorithms/tree/branchings.py +1042 -0
  429. package/runtime/python/okstra_vendor/networkx/algorithms/tree/coding.py +413 -0
  430. package/runtime/python/okstra_vendor/networkx/algorithms/tree/decomposition.py +88 -0
  431. package/runtime/python/okstra_vendor/networkx/algorithms/tree/distance_measures.py +219 -0
  432. package/runtime/python/okstra_vendor/networkx/algorithms/tree/mst.py +1281 -0
  433. package/runtime/python/okstra_vendor/networkx/algorithms/tree/operations.py +106 -0
  434. package/runtime/python/okstra_vendor/networkx/algorithms/tree/recognition.py +273 -0
  435. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
  436. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +624 -0
  437. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +114 -0
  438. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +79 -0
  439. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +99 -0
  440. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +934 -0
  441. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +53 -0
  442. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +174 -0
  443. package/runtime/python/okstra_vendor/networkx/algorithms/triads.py +500 -0
  444. package/runtime/python/okstra_vendor/networkx/algorithms/vitality.py +76 -0
  445. package/runtime/python/okstra_vendor/networkx/algorithms/voronoi.py +86 -0
  446. package/runtime/python/okstra_vendor/networkx/algorithms/walks.py +77 -0
  447. package/runtime/python/okstra_vendor/networkx/algorithms/wiener.py +278 -0
  448. package/runtime/python/okstra_vendor/networkx/classes/__init__.py +13 -0
  449. package/runtime/python/okstra_vendor/networkx/classes/coreviews.py +435 -0
  450. package/runtime/python/okstra_vendor/networkx/classes/digraph.py +1363 -0
  451. package/runtime/python/okstra_vendor/networkx/classes/filters.py +95 -0
  452. package/runtime/python/okstra_vendor/networkx/classes/function.py +1549 -0
  453. package/runtime/python/okstra_vendor/networkx/classes/graph.py +2082 -0
  454. package/runtime/python/okstra_vendor/networkx/classes/graphviews.py +269 -0
  455. package/runtime/python/okstra_vendor/networkx/classes/multidigraph.py +977 -0
  456. package/runtime/python/okstra_vendor/networkx/classes/multigraph.py +1294 -0
  457. package/runtime/python/okstra_vendor/networkx/classes/reportviews.py +1447 -0
  458. package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
  459. package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +192 -0
  460. package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +476 -0
  461. package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +362 -0
  462. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +331 -0
  463. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +110 -0
  464. package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +177 -0
  465. package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +1045 -0
  466. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +950 -0
  467. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +12 -0
  468. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +349 -0
  469. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +459 -0
  470. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +528 -0
  471. package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +1421 -0
  472. package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +131 -0
  473. package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +371 -0
  474. package/runtime/python/okstra_vendor/networkx/conftest.py +261 -0
  475. package/runtime/python/okstra_vendor/networkx/convert.py +502 -0
  476. package/runtime/python/okstra_vendor/networkx/convert_matrix.py +1314 -0
  477. package/runtime/python/okstra_vendor/networkx/drawing/__init__.py +7 -0
  478. package/runtime/python/okstra_vendor/networkx/drawing/layout.py +2036 -0
  479. package/runtime/python/okstra_vendor/networkx/drawing/nx_agraph.py +470 -0
  480. package/runtime/python/okstra_vendor/networkx/drawing/nx_latex.py +570 -0
  481. package/runtime/python/okstra_vendor/networkx/drawing/nx_pydot.py +361 -0
  482. package/runtime/python/okstra_vendor/networkx/drawing/nx_pylab.py +2978 -0
  483. package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
  484. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
  485. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
  486. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
  487. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
  488. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
  489. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
  490. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +237 -0
  491. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +229 -0
  492. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +285 -0
  493. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +631 -0
  494. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +146 -0
  495. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +1582 -0
  496. package/runtime/python/okstra_vendor/networkx/exception.py +131 -0
  497. package/runtime/python/okstra_vendor/networkx/generators/__init__.py +34 -0
  498. package/runtime/python/okstra_vendor/networkx/generators/atlas.dat.gz +0 -0
  499. package/runtime/python/okstra_vendor/networkx/generators/atlas.py +227 -0
  500. package/runtime/python/okstra_vendor/networkx/generators/classic.py +1091 -0
  501. package/runtime/python/okstra_vendor/networkx/generators/cographs.py +68 -0
  502. package/runtime/python/okstra_vendor/networkx/generators/community.py +1070 -0
  503. package/runtime/python/okstra_vendor/networkx/generators/degree_seq.py +886 -0
  504. package/runtime/python/okstra_vendor/networkx/generators/directed.py +572 -0
  505. package/runtime/python/okstra_vendor/networkx/generators/duplication.py +174 -0
  506. package/runtime/python/okstra_vendor/networkx/generators/ego.py +66 -0
  507. package/runtime/python/okstra_vendor/networkx/generators/expanders.py +499 -0
  508. package/runtime/python/okstra_vendor/networkx/generators/geometric.py +1037 -0
  509. package/runtime/python/okstra_vendor/networkx/generators/harary_graph.py +163 -0
  510. package/runtime/python/okstra_vendor/networkx/generators/internet_as_graphs.py +443 -0
  511. package/runtime/python/okstra_vendor/networkx/generators/intersection.py +125 -0
  512. package/runtime/python/okstra_vendor/networkx/generators/interval_graph.py +70 -0
  513. package/runtime/python/okstra_vendor/networkx/generators/joint_degree_seq.py +664 -0
  514. package/runtime/python/okstra_vendor/networkx/generators/lattice.py +405 -0
  515. package/runtime/python/okstra_vendor/networkx/generators/line.py +501 -0
  516. package/runtime/python/okstra_vendor/networkx/generators/mycielski.py +110 -0
  517. package/runtime/python/okstra_vendor/networkx/generators/nonisomorphic_trees.py +259 -0
  518. package/runtime/python/okstra_vendor/networkx/generators/random_clustered.py +117 -0
  519. package/runtime/python/okstra_vendor/networkx/generators/random_graphs.py +1416 -0
  520. package/runtime/python/okstra_vendor/networkx/generators/small.py +1070 -0
  521. package/runtime/python/okstra_vendor/networkx/generators/social.py +554 -0
  522. package/runtime/python/okstra_vendor/networkx/generators/spectral_graph_forge.py +120 -0
  523. package/runtime/python/okstra_vendor/networkx/generators/stochastic.py +54 -0
  524. package/runtime/python/okstra_vendor/networkx/generators/sudoku.py +131 -0
  525. package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
  526. package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +75 -0
  527. package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +642 -0
  528. package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +20 -0
  529. package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +362 -0
  530. package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +224 -0
  531. package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +189 -0
  532. package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +103 -0
  533. package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +39 -0
  534. package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +182 -0
  535. package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +488 -0
  536. package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +133 -0
  537. package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +221 -0
  538. package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +28 -0
  539. package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +144 -0
  540. package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +125 -0
  541. package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +264 -0
  542. package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +316 -0
  543. package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +30 -0
  544. package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +82 -0
  545. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +33 -0
  546. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +495 -0
  547. package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +220 -0
  548. package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +49 -0
  549. package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +72 -0
  550. package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +92 -0
  551. package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +64 -0
  552. package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +195 -0
  553. package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +15 -0
  554. package/runtime/python/okstra_vendor/networkx/generators/time_series.py +74 -0
  555. package/runtime/python/okstra_vendor/networkx/generators/trees.py +1070 -0
  556. package/runtime/python/okstra_vendor/networkx/generators/triads.py +94 -0
  557. package/runtime/python/okstra_vendor/networkx/lazy_imports.py +188 -0
  558. package/runtime/python/okstra_vendor/networkx/linalg/__init__.py +13 -0
  559. package/runtime/python/okstra_vendor/networkx/linalg/algebraicconnectivity.py +650 -0
  560. package/runtime/python/okstra_vendor/networkx/linalg/attrmatrix.py +466 -0
  561. package/runtime/python/okstra_vendor/networkx/linalg/bethehessianmatrix.py +77 -0
  562. package/runtime/python/okstra_vendor/networkx/linalg/graphmatrix.py +168 -0
  563. package/runtime/python/okstra_vendor/networkx/linalg/laplacianmatrix.py +512 -0
  564. package/runtime/python/okstra_vendor/networkx/linalg/modularitymatrix.py +166 -0
  565. package/runtime/python/okstra_vendor/networkx/linalg/spectrum.py +186 -0
  566. package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
  567. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +400 -0
  568. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +108 -0
  569. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +40 -0
  570. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +275 -0
  571. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +334 -0
  572. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +86 -0
  573. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +70 -0
  574. package/runtime/python/okstra_vendor/networkx/readwrite/__init__.py +17 -0
  575. package/runtime/python/okstra_vendor/networkx/readwrite/adjlist.py +330 -0
  576. package/runtime/python/okstra_vendor/networkx/readwrite/edgelist.py +489 -0
  577. package/runtime/python/okstra_vendor/networkx/readwrite/gexf.py +1084 -0
  578. package/runtime/python/okstra_vendor/networkx/readwrite/gml.py +879 -0
  579. package/runtime/python/okstra_vendor/networkx/readwrite/graph6.py +427 -0
  580. package/runtime/python/okstra_vendor/networkx/readwrite/graphml.py +1053 -0
  581. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/__init__.py +19 -0
  582. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/adjacency.py +156 -0
  583. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/cytoscape.py +190 -0
  584. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/node_link.py +261 -0
  585. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
  586. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +78 -0
  587. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +78 -0
  588. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +109 -0
  589. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +48 -0
  590. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tree.py +137 -0
  591. package/runtime/python/okstra_vendor/networkx/readwrite/leda.py +108 -0
  592. package/runtime/python/okstra_vendor/networkx/readwrite/multiline_adjlist.py +393 -0
  593. package/runtime/python/okstra_vendor/networkx/readwrite/p2g.py +113 -0
  594. package/runtime/python/okstra_vendor/networkx/readwrite/pajek.py +286 -0
  595. package/runtime/python/okstra_vendor/networkx/readwrite/sparse6.py +379 -0
  596. package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
  597. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +354 -0
  598. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +318 -0
  599. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +612 -0
  600. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +744 -0
  601. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +181 -0
  602. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +1531 -0
  603. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +30 -0
  604. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +63 -0
  605. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +128 -0
  606. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +166 -0
  607. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +1742 -0
  608. package/runtime/python/okstra_vendor/networkx/readwrite/text.py +851 -0
  609. package/runtime/python/okstra_vendor/networkx/relabel.py +285 -0
  610. package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
  611. package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +248 -0
  612. package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +321 -0
  613. package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +531 -0
  614. package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +349 -0
  615. package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +281 -0
  616. package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +40 -0
  617. package/runtime/python/okstra_vendor/networkx/tests/test_import.py +11 -0
  618. package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +96 -0
  619. package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +349 -0
  620. package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +8 -0
  621. package/runtime/python/okstra_vendor/networkx/utils/__init__.py +8 -0
  622. package/runtime/python/okstra_vendor/networkx/utils/backends.py +2171 -0
  623. package/runtime/python/okstra_vendor/networkx/utils/configs.py +396 -0
  624. package/runtime/python/okstra_vendor/networkx/utils/decorators.py +1233 -0
  625. package/runtime/python/okstra_vendor/networkx/utils/heaps.py +338 -0
  626. package/runtime/python/okstra_vendor/networkx/utils/mapped_queue.py +297 -0
  627. package/runtime/python/okstra_vendor/networkx/utils/misc.py +703 -0
  628. package/runtime/python/okstra_vendor/networkx/utils/random_sequence.py +198 -0
  629. package/runtime/python/okstra_vendor/networkx/utils/rcm.py +159 -0
  630. package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
  631. package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +11 -0
  632. package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +225 -0
  633. package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +263 -0
  634. package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +510 -0
  635. package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +131 -0
  636. package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +268 -0
  637. package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +393 -0
  638. package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +53 -0
  639. package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +63 -0
  640. package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +55 -0
  641. package/runtime/python/okstra_vendor/networkx/utils/union_find.py +106 -0
  642. package/runtime/skills/okstra-graphify/SKILL.md +161 -0
  643. package/runtime/skills/okstra-inspect/SKILL.md +17 -9
  644. package/runtime/templates/reports/settings.template.json +4 -0
  645. package/src/cli-registry.mjs +7 -0
  646. package/src/commands/graphify.mjs +32 -0
  647. package/src/commands/lifecycle/doctor.mjs +9 -0
  648. package/src/lib/skill-catalog.mjs +1 -0
@@ -0,0 +1,1270 @@
1
+ """
2
+ Algorithms for finding k-edge-augmentations
3
+
4
+ A k-edge-augmentation is a set of edges, that once added to a graph, ensures
5
+ that the graph is k-edge-connected; i.e. the graph cannot be disconnected
6
+ unless k or more edges are removed. Typically, the goal is to find the
7
+ augmentation with minimum weight. In general, it is not guaranteed that a
8
+ k-edge-augmentation exists.
9
+
10
+ See Also
11
+ --------
12
+ :mod:`edge_kcomponents` : algorithms for finding k-edge-connected components
13
+ :mod:`connectivity` : algorithms for determining edge connectivity.
14
+ """
15
+
16
+ import itertools as it
17
+ import math
18
+ from collections import defaultdict, namedtuple
19
+
20
+ import networkx as nx
21
+ from networkx.utils import not_implemented_for, py_random_state
22
+
23
+ __all__ = ["k_edge_augmentation", "is_k_edge_connected", "is_locally_k_edge_connected"]
24
+
25
+
26
+ @not_implemented_for("directed")
27
+ @not_implemented_for("multigraph")
28
+ @nx._dispatchable
29
+ def is_k_edge_connected(G, k):
30
+ """Tests to see if a graph is k-edge-connected.
31
+
32
+ Is it impossible to disconnect the graph by removing fewer than k edges?
33
+ If so, then G is k-edge-connected.
34
+
35
+ Parameters
36
+ ----------
37
+ G : NetworkX graph
38
+ An undirected graph.
39
+
40
+ k : integer
41
+ edge connectivity to test for
42
+
43
+ Returns
44
+ -------
45
+ boolean
46
+ True if G is k-edge-connected.
47
+
48
+ See Also
49
+ --------
50
+ :func:`is_locally_k_edge_connected`
51
+
52
+ Examples
53
+ --------
54
+ >>> G = nx.barbell_graph(10, 0)
55
+ >>> nx.is_k_edge_connected(G, k=1)
56
+ True
57
+ >>> nx.is_k_edge_connected(G, k=2)
58
+ False
59
+ """
60
+ if k < 1:
61
+ raise ValueError(f"k must be positive, not {k}")
62
+ # First try to quickly determine if G is not k-edge-connected
63
+ if G.number_of_nodes() < k + 1:
64
+ return False
65
+ elif any(d < k for n, d in G.degree()):
66
+ return False
67
+ else:
68
+ # Otherwise perform the full check
69
+ if k == 1:
70
+ return nx.is_connected(G)
71
+ elif k == 2:
72
+ return nx.is_connected(G) and not nx.has_bridges(G)
73
+ else:
74
+ return nx.edge_connectivity(G, cutoff=k) >= k
75
+
76
+
77
+ @not_implemented_for("directed")
78
+ @not_implemented_for("multigraph")
79
+ @nx._dispatchable
80
+ def is_locally_k_edge_connected(G, s, t, k):
81
+ """Tests to see if an edge in a graph is locally k-edge-connected.
82
+
83
+ Is it impossible to disconnect s and t by removing fewer than k edges?
84
+ If so, then s and t are locally k-edge-connected in G.
85
+
86
+ Parameters
87
+ ----------
88
+ G : NetworkX graph
89
+ An undirected graph.
90
+
91
+ s : node
92
+ Source node
93
+
94
+ t : node
95
+ Target node
96
+
97
+ k : integer
98
+ local edge connectivity for nodes s and t
99
+
100
+ Returns
101
+ -------
102
+ boolean
103
+ True if s and t are locally k-edge-connected in G.
104
+
105
+ See Also
106
+ --------
107
+ :func:`is_k_edge_connected`
108
+
109
+ Examples
110
+ --------
111
+ >>> from networkx.algorithms.connectivity import is_locally_k_edge_connected
112
+ >>> G = nx.barbell_graph(10, 0)
113
+ >>> is_locally_k_edge_connected(G, 5, 15, k=1)
114
+ True
115
+ >>> is_locally_k_edge_connected(G, 5, 15, k=2)
116
+ False
117
+ >>> is_locally_k_edge_connected(G, 1, 5, k=2)
118
+ True
119
+ """
120
+ if k < 1:
121
+ raise ValueError(f"k must be positive, not {k}")
122
+
123
+ # First try to quickly determine s, t is not k-locally-edge-connected in G
124
+ if G.degree(s) < k or G.degree(t) < k:
125
+ return False
126
+ else:
127
+ # Otherwise perform the full check
128
+ if k == 1:
129
+ return nx.has_path(G, s, t)
130
+ else:
131
+ localk = nx.connectivity.local_edge_connectivity(G, s, t, cutoff=k)
132
+ return localk >= k
133
+
134
+
135
+ @not_implemented_for("directed")
136
+ @not_implemented_for("multigraph")
137
+ @nx._dispatchable
138
+ def k_edge_augmentation(G, k, avail=None, weight=None, partial=False):
139
+ """Finds set of edges to k-edge-connect G.
140
+
141
+ Adding edges from the augmentation to G make it impossible to disconnect G
142
+ unless k or more edges are removed. This function uses the most efficient
143
+ function available (depending on the value of k and if the problem is
144
+ weighted or unweighted) to search for a minimum weight subset of available
145
+ edges that k-edge-connects G. In general, finding a k-edge-augmentation is
146
+ NP-hard, so solutions are not guaranteed to be minimal. Furthermore, a
147
+ k-edge-augmentation may not exist.
148
+
149
+ Parameters
150
+ ----------
151
+ G : NetworkX graph
152
+ An undirected graph.
153
+
154
+ k : integer
155
+ Desired edge connectivity
156
+
157
+ avail : dict or a set of 2 or 3 tuples
158
+ The available edges that can be used in the augmentation.
159
+
160
+ If unspecified, then all edges in the complement of G are available.
161
+ Otherwise, each item is an available edge (with an optional weight).
162
+
163
+ In the unweighted case, each item is an edge ``(u, v)``.
164
+
165
+ In the weighted case, each item is a 3-tuple ``(u, v, d)`` or a dict
166
+ with items ``(u, v): d``. The third item, ``d``, can be a dictionary
167
+ or a real number. If ``d`` is a dictionary ``d[weight]``
168
+ correspondings to the weight.
169
+
170
+ weight : string
171
+ key to use to find weights if ``avail`` is a set of 3-tuples where the
172
+ third item in each tuple is a dictionary.
173
+
174
+ partial : boolean
175
+ If partial is True and no feasible k-edge-augmentation exists, then all
176
+ a partial k-edge-augmentation is generated. Adding the edges in a
177
+ partial augmentation to G, minimizes the number of k-edge-connected
178
+ components and maximizes the edge connectivity between those
179
+ components. For details, see :func:`partial_k_edge_augmentation`.
180
+
181
+ Yields
182
+ ------
183
+ edge : tuple
184
+ Edges that, once added to G, would cause G to become k-edge-connected.
185
+ If partial is False, an error is raised if this is not possible.
186
+ Otherwise, generated edges form a partial augmentation, which
187
+ k-edge-connects any part of G where it is possible, and maximally
188
+ connects the remaining parts.
189
+
190
+ Raises
191
+ ------
192
+ NetworkXUnfeasible
193
+ If partial is False and no k-edge-augmentation exists.
194
+
195
+ NetworkXNotImplemented
196
+ If the input graph is directed or a multigraph.
197
+
198
+ ValueError:
199
+ If k is less than 1
200
+
201
+ Notes
202
+ -----
203
+ When k=1 this returns an optimal solution.
204
+
205
+ When k=2 and ``avail`` is None, this returns an optimal solution.
206
+ Otherwise when k=2, this returns a 2-approximation of the optimal solution.
207
+
208
+ For k>3, this problem is NP-hard and this uses a randomized algorithm that
209
+ produces a feasible solution, but provides no guarantees on the
210
+ solution weight.
211
+
212
+ Examples
213
+ --------
214
+ >>> # Unweighted cases
215
+ >>> G = nx.path_graph((1, 2, 3, 4))
216
+ >>> G.add_node(5)
217
+ >>> sorted(nx.k_edge_augmentation(G, k=1))
218
+ [(1, 5)]
219
+ >>> sorted(nx.k_edge_augmentation(G, k=2))
220
+ [(1, 5), (5, 4)]
221
+ >>> sorted(nx.k_edge_augmentation(G, k=3))
222
+ [(1, 4), (1, 5), (2, 5), (3, 5), (4, 5)]
223
+ >>> complement = list(nx.k_edge_augmentation(G, k=5, partial=True))
224
+ >>> G.add_edges_from(complement)
225
+ >>> nx.edge_connectivity(G)
226
+ 4
227
+
228
+ >>> # Weighted cases
229
+ >>> G = nx.path_graph((1, 2, 3, 4))
230
+ >>> G.add_node(5)
231
+ >>> # avail can be a tuple with a dict
232
+ >>> avail = [(1, 5, {"weight": 11}), (2, 5, {"weight": 10})]
233
+ >>> sorted(nx.k_edge_augmentation(G, k=1, avail=avail, weight="weight"))
234
+ [(2, 5)]
235
+ >>> # or avail can be a 3-tuple with a real number
236
+ >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)]
237
+ >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail))
238
+ [(1, 5), (2, 5), (4, 5)]
239
+ >>> # or avail can be a dict
240
+ >>> avail = {(1, 5): 11, (2, 5): 10, (4, 3): 1, (4, 5): 51}
241
+ >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail))
242
+ [(1, 5), (2, 5), (4, 5)]
243
+ >>> # If augmentation is infeasible, then a partial solution can be found
244
+ >>> avail = {(1, 5): 11}
245
+ >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail, partial=True))
246
+ [(1, 5)]
247
+ """
248
+ try:
249
+ if k <= 0:
250
+ raise ValueError(f"k must be a positive integer, not {k}")
251
+ elif G.number_of_nodes() < k + 1:
252
+ msg = f"impossible to {k} connect in graph with less than {k + 1} nodes"
253
+ raise nx.NetworkXUnfeasible(msg)
254
+ elif avail is not None and len(avail) == 0:
255
+ if not nx.is_k_edge_connected(G, k):
256
+ raise nx.NetworkXUnfeasible("no available edges")
257
+ aug_edges = []
258
+ elif k == 1:
259
+ aug_edges = one_edge_augmentation(
260
+ G, avail=avail, weight=weight, partial=partial
261
+ )
262
+ elif k == 2:
263
+ aug_edges = bridge_augmentation(G, avail=avail, weight=weight)
264
+ else:
265
+ # raise NotImplementedError(f'not implemented for k>2. k={k}')
266
+ aug_edges = greedy_k_edge_augmentation(
267
+ G, k=k, avail=avail, weight=weight, seed=0
268
+ )
269
+ # Do eager evaluation so we can catch any exceptions
270
+ # Before executing partial code.
271
+ yield from list(aug_edges)
272
+ except nx.NetworkXUnfeasible:
273
+ if partial:
274
+ # Return all available edges
275
+ if avail is None:
276
+ aug_edges = complement_edges(G)
277
+ else:
278
+ # If we can't k-edge-connect the entire graph, try to
279
+ # k-edge-connect as much as possible
280
+ aug_edges = partial_k_edge_augmentation(
281
+ G, k=k, avail=avail, weight=weight
282
+ )
283
+ yield from aug_edges
284
+ else:
285
+ raise
286
+
287
+
288
+ @nx._dispatchable
289
+ def partial_k_edge_augmentation(G, k, avail, weight=None):
290
+ """Finds augmentation that k-edge-connects as much of the graph as possible.
291
+
292
+ When a k-edge-augmentation is not possible, we can still try to find a
293
+ small set of edges that partially k-edge-connects as much of the graph as
294
+ possible. All possible edges are generated between remaining parts.
295
+ This minimizes the number of k-edge-connected subgraphs in the resulting
296
+ graph and maximizes the edge connectivity between those subgraphs.
297
+
298
+ Parameters
299
+ ----------
300
+ G : NetworkX graph
301
+ An undirected graph.
302
+
303
+ k : integer
304
+ Desired edge connectivity
305
+
306
+ avail : dict or a set of 2 or 3 tuples
307
+ For more details, see :func:`k_edge_augmentation`.
308
+
309
+ weight : string
310
+ key to use to find weights if ``avail`` is a set of 3-tuples.
311
+ For more details, see :func:`k_edge_augmentation`.
312
+
313
+ Yields
314
+ ------
315
+ edge : tuple
316
+ Edges in the partial augmentation of G. These edges k-edge-connect any
317
+ part of G where it is possible, and maximally connects the remaining
318
+ parts. In other words, all edges from avail are generated except for
319
+ those within subgraphs that have already become k-edge-connected.
320
+
321
+ Notes
322
+ -----
323
+ Construct H that augments G with all edges in avail.
324
+ Find the k-edge-subgraphs of H.
325
+ For each k-edge-subgraph, if the number of nodes is more than k, then find
326
+ the k-edge-augmentation of that graph and add it to the solution. Then add
327
+ all edges in avail between k-edge subgraphs to the solution.
328
+
329
+ See Also
330
+ --------
331
+ :func:`k_edge_augmentation`
332
+
333
+ Examples
334
+ --------
335
+ >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7))
336
+ >>> G.add_node(8)
337
+ >>> avail = [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5), (1, 8)]
338
+ >>> sorted(partial_k_edge_augmentation(G, k=2, avail=avail))
339
+ [(1, 5), (1, 8)]
340
+ """
341
+
342
+ def _edges_between_disjoint(H, only1, only2):
343
+ """finds edges between disjoint nodes"""
344
+ only1_adj = {u: set(H.adj[u]) for u in only1}
345
+ for u, neighbs in only1_adj.items():
346
+ # Find the neighbors of u in only1 that are also in only2
347
+ neighbs12 = neighbs.intersection(only2)
348
+ for v in neighbs12:
349
+ yield (u, v)
350
+
351
+ avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G)
352
+
353
+ # Find which parts of the graph can be k-edge-connected
354
+ H = G.copy()
355
+ H.add_edges_from(
356
+ (
357
+ (u, v, {"weight": w, "generator": (u, v)})
358
+ for (u, v), w in zip(avail, avail_w)
359
+ )
360
+ )
361
+ k_edge_subgraphs = list(nx.k_edge_subgraphs(H, k=k))
362
+
363
+ # Generate edges to k-edge-connect internal subgraphs
364
+ for nodes in k_edge_subgraphs:
365
+ if len(nodes) > 1:
366
+ # Get the k-edge-connected subgraph
367
+ C = H.subgraph(nodes).copy()
368
+ # Find the internal edges that were available
369
+ sub_avail = {
370
+ d["generator"]: d["weight"]
371
+ for (u, v, d) in C.edges(data=True)
372
+ if "generator" in d
373
+ }
374
+ # Remove potential augmenting edges
375
+ C.remove_edges_from(sub_avail.keys())
376
+ # Find a subset of these edges that makes the component
377
+ # k-edge-connected and ignore the rest
378
+ yield from nx.k_edge_augmentation(C, k=k, avail=sub_avail)
379
+
380
+ # Generate all edges between CCs that could not be k-edge-connected
381
+ for cc1, cc2 in it.combinations(k_edge_subgraphs, 2):
382
+ for u, v in _edges_between_disjoint(H, cc1, cc2):
383
+ d = H.get_edge_data(u, v)
384
+ edge = d.get("generator", None)
385
+ if edge is not None:
386
+ yield edge
387
+
388
+
389
+ @not_implemented_for("multigraph")
390
+ @not_implemented_for("directed")
391
+ @nx._dispatchable
392
+ def one_edge_augmentation(G, avail=None, weight=None, partial=False):
393
+ """Finds minimum weight set of edges to connect G.
394
+
395
+ Equivalent to :func:`k_edge_augmentation` when k=1. Adding the resulting
396
+ edges to G will make it 1-edge-connected. The solution is optimal for both
397
+ weighted and non-weighted variants.
398
+
399
+ Parameters
400
+ ----------
401
+ G : NetworkX graph
402
+ An undirected graph.
403
+
404
+ avail : dict or a set of 2 or 3 tuples
405
+ For more details, see :func:`k_edge_augmentation`.
406
+
407
+ weight : string
408
+ key to use to find weights if ``avail`` is a set of 3-tuples.
409
+ For more details, see :func:`k_edge_augmentation`.
410
+
411
+ partial : boolean
412
+ If partial is True and no feasible k-edge-augmentation exists, then the
413
+ augmenting edges minimize the number of connected components.
414
+
415
+ Yields
416
+ ------
417
+ edge : tuple
418
+ Edges in the one-augmentation of G
419
+
420
+ Raises
421
+ ------
422
+ NetworkXUnfeasible
423
+ If partial is False and no one-edge-augmentation exists.
424
+
425
+ Notes
426
+ -----
427
+ Uses either :func:`unconstrained_one_edge_augmentation` or
428
+ :func:`weighted_one_edge_augmentation` depending on whether ``avail`` is
429
+ specified. Both algorithms are based on finding a minimum spanning tree.
430
+ As such both algorithms find optimal solutions and run in linear time.
431
+
432
+ See Also
433
+ --------
434
+ :func:`k_edge_augmentation`
435
+ """
436
+ if avail is None:
437
+ return unconstrained_one_edge_augmentation(G)
438
+ else:
439
+ return weighted_one_edge_augmentation(
440
+ G, avail=avail, weight=weight, partial=partial
441
+ )
442
+
443
+
444
+ @not_implemented_for("multigraph")
445
+ @not_implemented_for("directed")
446
+ @nx._dispatchable
447
+ def bridge_augmentation(G, avail=None, weight=None):
448
+ """Finds the a set of edges that bridge connects G.
449
+
450
+ Equivalent to :func:`k_edge_augmentation` when k=2, and partial=False.
451
+ Adding the resulting edges to G will make it 2-edge-connected. If no
452
+ constraints are specified the returned set of edges is minimum an optimal,
453
+ otherwise the solution is approximated.
454
+
455
+ Parameters
456
+ ----------
457
+ G : NetworkX graph
458
+ An undirected graph.
459
+
460
+ avail : dict or a set of 2 or 3 tuples
461
+ For more details, see :func:`k_edge_augmentation`.
462
+
463
+ weight : string
464
+ key to use to find weights if ``avail`` is a set of 3-tuples.
465
+ For more details, see :func:`k_edge_augmentation`.
466
+
467
+ Yields
468
+ ------
469
+ edge : tuple
470
+ Edges in the bridge-augmentation of G
471
+
472
+ Raises
473
+ ------
474
+ NetworkXUnfeasible
475
+ If no bridge-augmentation exists.
476
+
477
+ Notes
478
+ -----
479
+ If there are no constraints the solution can be computed in linear time
480
+ using :func:`unconstrained_bridge_augmentation`. Otherwise, the problem
481
+ becomes NP-hard and is the solution is approximated by
482
+ :func:`weighted_bridge_augmentation`.
483
+
484
+ See Also
485
+ --------
486
+ :func:`k_edge_augmentation`
487
+ """
488
+ if G.number_of_nodes() < 3:
489
+ raise nx.NetworkXUnfeasible("impossible to bridge connect less than 3 nodes")
490
+ if avail is None:
491
+ return unconstrained_bridge_augmentation(G)
492
+ else:
493
+ return weighted_bridge_augmentation(G, avail, weight=weight)
494
+
495
+
496
+ # --- Algorithms and Helpers ---
497
+
498
+
499
+ def _ordered(u, v):
500
+ """Returns the nodes in an undirected edge in lower-triangular order"""
501
+ return (u, v) if u < v else (v, u)
502
+
503
+
504
+ def _unpack_available_edges(avail, weight=None, G=None):
505
+ """Helper to separate avail into edges and corresponding weights"""
506
+ if weight is None:
507
+ weight = "weight"
508
+ if isinstance(avail, dict):
509
+ avail_uv = list(avail.keys())
510
+ avail_w = list(avail.values())
511
+ else:
512
+
513
+ def _try_getitem(d):
514
+ try:
515
+ return d[weight]
516
+ except TypeError:
517
+ return d
518
+
519
+ avail_uv = [tup[0:2] for tup in avail]
520
+ avail_w = [1 if len(tup) == 2 else _try_getitem(tup[-1]) for tup in avail]
521
+
522
+ if G is not None:
523
+ # Edges already in the graph are filtered
524
+ flags = [not G.has_edge(u, v) for u, v in avail_uv]
525
+ avail_uv = list(it.compress(avail_uv, flags))
526
+ avail_w = list(it.compress(avail_w, flags))
527
+ return avail_uv, avail_w
528
+
529
+
530
+ MetaEdge = namedtuple("MetaEdge", ("meta_uv", "uv", "w"))
531
+
532
+
533
+ def _lightest_meta_edges(mapping, avail_uv, avail_w):
534
+ """Maps available edges in the original graph to edges in the metagraph.
535
+
536
+ Parameters
537
+ ----------
538
+ mapping : dict
539
+ mapping produced by :func:`collapse`, that maps each node in the
540
+ original graph to a node in the meta graph
541
+
542
+ avail_uv : list
543
+ list of edges
544
+
545
+ avail_w : list
546
+ list of edge weights
547
+
548
+ Notes
549
+ -----
550
+ Each node in the metagraph is a k-edge-connected component in the original
551
+ graph. We don't care about any edge within the same k-edge-connected
552
+ component, so we ignore self edges. We also are only interested in the
553
+ minimum weight edge bridging each k-edge-connected component so, we group
554
+ the edges by meta-edge and take the lightest in each group.
555
+
556
+ Examples
557
+ --------
558
+ >>> # Each group represents a meta-node
559
+ >>> groups = ([1, 2, 3], [4, 5], [6])
560
+ >>> mapping = {n: meta_n for meta_n, ns in enumerate(groups) for n in ns}
561
+ >>> avail_uv = [(1, 2), (3, 6), (1, 4), (5, 2), (6, 1), (2, 6), (3, 1)]
562
+ >>> avail_w = [20, 99, 20, 15, 50, 99, 20]
563
+ >>> sorted(_lightest_meta_edges(mapping, avail_uv, avail_w))
564
+ [MetaEdge(meta_uv=(0, 1), uv=(5, 2), w=15), MetaEdge(meta_uv=(0, 2), uv=(6, 1), w=50)]
565
+ """
566
+ grouped_wuv = defaultdict(list)
567
+ for w, (u, v) in zip(avail_w, avail_uv):
568
+ # Order the meta-edge so it can be used as a dict key
569
+ meta_uv = _ordered(mapping[u], mapping[v])
570
+ # Group each available edge using the meta-edge as a key
571
+ grouped_wuv[meta_uv].append((w, u, v))
572
+
573
+ # Now that all available edges are grouped, choose one per group
574
+ for (mu, mv), choices_wuv in grouped_wuv.items():
575
+ # Ignore available edges within the same meta-node
576
+ if mu != mv:
577
+ # Choose the lightest available edge belonging to each meta-edge
578
+ w, u, v = min(choices_wuv)
579
+ yield MetaEdge((mu, mv), (u, v), w)
580
+
581
+
582
+ @nx._dispatchable
583
+ def unconstrained_one_edge_augmentation(G):
584
+ """Finds the smallest set of edges to connect G.
585
+
586
+ This is a variant of the unweighted MST problem.
587
+ If G is not empty, a feasible solution always exists.
588
+
589
+ Parameters
590
+ ----------
591
+ G : NetworkX graph
592
+ An undirected graph.
593
+
594
+ Yields
595
+ ------
596
+ edge : tuple
597
+ Edges in the one-edge-augmentation of G
598
+
599
+ See Also
600
+ --------
601
+ :func:`one_edge_augmentation`
602
+ :func:`k_edge_augmentation`
603
+
604
+ Examples
605
+ --------
606
+ >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)])
607
+ >>> G.add_nodes_from([6, 7, 8])
608
+ >>> sorted(unconstrained_one_edge_augmentation(G))
609
+ [(1, 4), (4, 6), (6, 7), (7, 8)]
610
+ """
611
+ ccs1 = list(nx.connected_components(G))
612
+ C = collapse(G, ccs1)
613
+ # When we are not constrained, we can just make a meta graph tree.
614
+ meta_nodes = list(C.nodes())
615
+ # build a path in the metagraph
616
+ meta_aug = list(zip(meta_nodes, meta_nodes[1:]))
617
+ # map that path to the original graph
618
+ inverse = defaultdict(list)
619
+ for k, v in C.graph["mapping"].items():
620
+ inverse[v].append(k)
621
+ for mu, mv in meta_aug:
622
+ yield (inverse[mu][0], inverse[mv][0])
623
+
624
+
625
+ @nx._dispatchable
626
+ def weighted_one_edge_augmentation(G, avail, weight=None, partial=False):
627
+ """Finds the minimum weight set of edges to connect G if one exists.
628
+
629
+ This is a variant of the weighted MST problem.
630
+
631
+ Parameters
632
+ ----------
633
+ G : NetworkX graph
634
+ An undirected graph.
635
+
636
+ avail : dict or a set of 2 or 3 tuples
637
+ For more details, see :func:`k_edge_augmentation`.
638
+
639
+ weight : string
640
+ key to use to find weights if ``avail`` is a set of 3-tuples.
641
+ For more details, see :func:`k_edge_augmentation`.
642
+
643
+ partial : boolean
644
+ If partial is True and no feasible k-edge-augmentation exists, then the
645
+ augmenting edges minimize the number of connected components.
646
+
647
+ Yields
648
+ ------
649
+ edge : tuple
650
+ Edges in the subset of avail chosen to connect G.
651
+
652
+ See Also
653
+ --------
654
+ :func:`one_edge_augmentation`
655
+ :func:`k_edge_augmentation`
656
+
657
+ Examples
658
+ --------
659
+ >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)])
660
+ >>> G.add_nodes_from([6, 7, 8])
661
+ >>> # any edge not in avail has an implicit weight of infinity
662
+ >>> avail = [(1, 3), (1, 5), (4, 7), (4, 8), (6, 1), (8, 1), (8, 2)]
663
+ >>> sorted(weighted_one_edge_augmentation(G, avail))
664
+ [(1, 5), (4, 7), (6, 1), (8, 1)]
665
+ >>> # find another solution by giving large weights to edges in the
666
+ >>> # previous solution (note some of the old edges must be used)
667
+ >>> avail = [(1, 3), (1, 5, 99), (4, 7, 9), (6, 1, 99), (8, 1, 99), (8, 2)]
668
+ >>> sorted(weighted_one_edge_augmentation(G, avail))
669
+ [(1, 5), (4, 7), (6, 1), (8, 2)]
670
+ """
671
+ avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G)
672
+ # Collapse CCs in the original graph into nodes in a metagraph
673
+ # Then find an MST of the metagraph instead of the original graph
674
+ C = collapse(G, nx.connected_components(G))
675
+ mapping = C.graph["mapping"]
676
+ # Assign each available edge to an edge in the metagraph
677
+ candidate_mapping = _lightest_meta_edges(mapping, avail_uv, avail_w)
678
+ # nx.set_edge_attributes(C, name='weight', values=0)
679
+ C.add_edges_from(
680
+ (mu, mv, {"weight": w, "generator": uv})
681
+ for (mu, mv), uv, w in candidate_mapping
682
+ )
683
+ # Find MST of the meta graph
684
+ meta_mst = nx.minimum_spanning_tree(C)
685
+ if not partial and not nx.is_connected(meta_mst):
686
+ raise nx.NetworkXUnfeasible("Not possible to connect G with available edges")
687
+ # Yield the edge that generated the meta-edge
688
+ for mu, mv, d in meta_mst.edges(data=True):
689
+ if "generator" in d:
690
+ edge = d["generator"]
691
+ yield edge
692
+
693
+
694
+ @nx._dispatchable
695
+ def unconstrained_bridge_augmentation(G):
696
+ """Finds an optimal 2-edge-augmentation of G using the fewest edges.
697
+
698
+ This is an implementation of the algorithm detailed in [1]_.
699
+ The basic idea is to construct a meta-graph of bridge-ccs, connect leaf
700
+ nodes of the trees to connect the entire graph, and finally connect the
701
+ leafs of the tree in dfs-preorder to bridge connect the entire graph.
702
+
703
+ Parameters
704
+ ----------
705
+ G : NetworkX graph
706
+ An undirected graph.
707
+
708
+ Yields
709
+ ------
710
+ edge : tuple
711
+ Edges in the bridge augmentation of G
712
+
713
+ Notes
714
+ -----
715
+ Input: a graph G.
716
+ First find the bridge components of G and collapse each bridge-cc into a
717
+ node of a metagraph graph C, which is guaranteed to be a forest of trees.
718
+
719
+ C contains p "leafs" --- nodes with exactly one incident edge.
720
+ C contains q "isolated nodes" --- nodes with no incident edges.
721
+
722
+ Theorem: If p + q > 1, then at least :math:`ceil(p / 2) + q` edges are
723
+ needed to bridge connect C. This algorithm achieves this min number.
724
+
725
+ The method first adds enough edges to make G into a tree and then pairs
726
+ leafs in a simple fashion.
727
+
728
+ Let n be the number of trees in C. Let v(i) be an isolated vertex in the
729
+ i-th tree if one exists, otherwise it is a pair of distinct leafs nodes
730
+ in the i-th tree. Alternating edges from these sets (i.e. adding edges
731
+ A1 = [(v(i)[0], v(i + 1)[1]), v(i + 1)[0], v(i + 2)[1])...]) connects C
732
+ into a tree T. This tree has p' = p + 2q - 2(n -1) leafs and no isolated
733
+ vertices. A1 has n - 1 edges. The next step finds ceil(p' / 2) edges to
734
+ biconnect any tree with p' leafs.
735
+
736
+ Convert T into an arborescence T' by picking an arbitrary root node with
737
+ degree >= 2 and directing all edges away from the root. Note the
738
+ implementation implicitly constructs T'.
739
+
740
+ The leafs of T are the nodes with no existing edges in T'.
741
+ Order the leafs of T' by DFS preorder. Then break this list in half
742
+ and add the zipped pairs to A2.
743
+
744
+ The set A = A1 + A2 is the minimum augmentation in the metagraph.
745
+
746
+ To convert this to edges in the original graph
747
+
748
+ References
749
+ ----------
750
+ .. [1] Eswaran, Kapali P., and R. Endre Tarjan. (1975) Augmentation problems.
751
+ http://epubs.siam.org/doi/abs/10.1137/0205044
752
+
753
+ See Also
754
+ --------
755
+ :func:`bridge_augmentation`
756
+ :func:`k_edge_augmentation`
757
+
758
+ Examples
759
+ --------
760
+ >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7))
761
+ >>> sorted(unconstrained_bridge_augmentation(G))
762
+ [(1, 7)]
763
+ >>> G = nx.path_graph((1, 2, 3, 2, 4, 5, 6, 7))
764
+ >>> sorted(unconstrained_bridge_augmentation(G))
765
+ [(1, 3), (3, 7)]
766
+ >>> G = nx.Graph([(0, 1), (0, 2), (1, 2)])
767
+ >>> G.add_node(4)
768
+ >>> sorted(unconstrained_bridge_augmentation(G))
769
+ [(1, 4), (4, 0)]
770
+ """
771
+ # -----
772
+ # Mapping of terms from (Eswaran and Tarjan):
773
+ # G = G_0 - the input graph
774
+ # C = G_0' - the bridge condensation of G. (This is a forest of trees)
775
+ # A1 = A_1 - the edges to connect the forest into a tree
776
+ # leaf = pendant - a node with degree of 1
777
+
778
+ # alpha(v) = maps the node v in G to its meta-node in C
779
+ # beta(x) = maps the meta-node x in C to any node in the bridge
780
+ # component of G corresponding to x.
781
+
782
+ # find the 2-edge-connected components of G
783
+ bridge_ccs = list(nx.connectivity.bridge_components(G))
784
+ # condense G into an forest C
785
+ C = collapse(G, bridge_ccs)
786
+
787
+ # Choose pairs of distinct leaf nodes in each tree. If this is not
788
+ # possible then make a pair using the single isolated node in the tree.
789
+ vset1 = [
790
+ tuple(cc) * 2 # case1: an isolated node
791
+ if len(cc) == 1
792
+ else sorted(cc, key=C.degree)[0:2] # case2: pair of leaf nodes
793
+ for cc in nx.connected_components(C)
794
+ ]
795
+ if len(vset1) > 1:
796
+ # Use this set to construct edges that connect C into a tree.
797
+ nodes1 = [vs[0] for vs in vset1]
798
+ nodes2 = [vs[1] for vs in vset1]
799
+ A1 = list(zip(nodes1[1:], nodes2))
800
+ else:
801
+ A1 = []
802
+ # Connect each tree in the forest to construct an arborescence
803
+ T = C.copy()
804
+ T.add_edges_from(A1)
805
+
806
+ # If there are only two leaf nodes, we simply connect them.
807
+ leafs = [n for n, d in T.degree() if d == 1]
808
+ if len(leafs) == 1:
809
+ A2 = []
810
+ if len(leafs) == 2:
811
+ A2 = [tuple(leafs)]
812
+ else:
813
+ # Choose an arbitrary non-leaf root
814
+ try:
815
+ root = next(n for n, d in T.degree() if d > 1)
816
+ except StopIteration: # no nodes found with degree > 1
817
+ return
818
+ # order the leaves of C by (induced directed) preorder
819
+ v2 = [n for n in nx.dfs_preorder_nodes(T, root) if T.degree(n) == 1]
820
+ # connecting first half of the leafs in pre-order to the second
821
+ # half will bridge connect the tree with the fewest edges.
822
+ half = math.ceil(len(v2) / 2)
823
+ A2 = list(zip(v2[:half], v2[-half:]))
824
+
825
+ # collect the edges used to augment the original forest
826
+ aug_tree_edges = A1 + A2
827
+
828
+ # Construct the mapping (beta) from meta-nodes to regular nodes
829
+ inverse = defaultdict(list)
830
+ for k, v in C.graph["mapping"].items():
831
+ inverse[v].append(k)
832
+ # sort so we choose minimum degree nodes first
833
+ inverse = {
834
+ mu: sorted(mapped, key=lambda u: (G.degree(u), u))
835
+ for mu, mapped in inverse.items()
836
+ }
837
+
838
+ # For each meta-edge, map back to an arbitrary pair in the original graph
839
+ G2 = G.copy()
840
+ for mu, mv in aug_tree_edges:
841
+ # Find the first available edge that doesn't exist and return it
842
+ for u, v in it.product(inverse[mu], inverse[mv]):
843
+ if not G2.has_edge(u, v):
844
+ G2.add_edge(u, v)
845
+ yield u, v
846
+ break
847
+
848
+
849
+ @nx._dispatchable
850
+ def weighted_bridge_augmentation(G, avail, weight=None):
851
+ """Finds an approximate min-weight 2-edge-augmentation of G.
852
+
853
+ This is an implementation of the approximation algorithm detailed in [1]_.
854
+ It chooses a set of edges from avail to add to G that renders it
855
+ 2-edge-connected if such a subset exists. This is done by finding a
856
+ minimum spanning arborescence of a specially constructed metagraph.
857
+
858
+ Parameters
859
+ ----------
860
+ G : NetworkX graph
861
+ An undirected graph.
862
+
863
+ avail : set of 2 or 3 tuples.
864
+ candidate edges (with optional weights) to choose from
865
+
866
+ weight : string
867
+ key to use to find weights if avail is a set of 3-tuples where the
868
+ third item in each tuple is a dictionary.
869
+
870
+ Yields
871
+ ------
872
+ edge : tuple
873
+ Edges in the subset of avail chosen to bridge augment G.
874
+
875
+ Notes
876
+ -----
877
+ Finding a weighted 2-edge-augmentation is NP-hard.
878
+ Any edge not in ``avail`` is considered to have a weight of infinity.
879
+ The approximation factor is 2 if ``G`` is connected and 3 if it is not.
880
+ Runs in :math:`O(m + n log(n))` time
881
+
882
+ References
883
+ ----------
884
+ .. [1] Khuller, Samir, and Ramakrishna Thurimella. (1993) Approximation
885
+ algorithms for graph augmentation.
886
+ http://www.sciencedirect.com/science/article/pii/S0196677483710102
887
+
888
+ See Also
889
+ --------
890
+ :func:`bridge_augmentation`
891
+ :func:`k_edge_augmentation`
892
+
893
+ Examples
894
+ --------
895
+ >>> G = nx.path_graph((1, 2, 3, 4))
896
+ >>> # When the weights are equal, (1, 4) is the best
897
+ >>> avail = [(1, 4, 1), (1, 3, 1), (2, 4, 1)]
898
+ >>> sorted(weighted_bridge_augmentation(G, avail))
899
+ [(1, 4)]
900
+ >>> # Giving (1, 4) a high weight makes the two edge solution the best.
901
+ >>> avail = [(1, 4, 1000), (1, 3, 1), (2, 4, 1)]
902
+ >>> sorted(weighted_bridge_augmentation(G, avail))
903
+ [(1, 3), (2, 4)]
904
+ >>> # ------
905
+ >>> G = nx.path_graph((1, 2, 3, 4))
906
+ >>> G.add_node(5)
907
+ >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 1)]
908
+ >>> sorted(weighted_bridge_augmentation(G, avail=avail))
909
+ [(1, 5), (4, 5)]
910
+ >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)]
911
+ >>> sorted(weighted_bridge_augmentation(G, avail=avail))
912
+ [(1, 5), (2, 5), (4, 5)]
913
+ """
914
+
915
+ if weight is None:
916
+ weight = "weight"
917
+
918
+ # If input G is not connected the approximation factor increases to 3
919
+ if not nx.is_connected(G):
920
+ H = G.copy()
921
+ connectors = list(one_edge_augmentation(H, avail=avail, weight=weight))
922
+ H.add_edges_from(connectors)
923
+
924
+ yield from connectors
925
+ else:
926
+ connectors = []
927
+ H = G
928
+
929
+ if len(avail) == 0:
930
+ if nx.has_bridges(H):
931
+ raise nx.NetworkXUnfeasible("no augmentation possible")
932
+
933
+ avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=H)
934
+
935
+ # Collapse input into a metagraph. Meta nodes are bridge-ccs
936
+ bridge_ccs = nx.connectivity.bridge_components(H)
937
+ C = collapse(H, bridge_ccs)
938
+
939
+ # Use the meta graph to shrink avail to a small feasible subset
940
+ mapping = C.graph["mapping"]
941
+ # Choose the minimum weight feasible edge in each group
942
+ meta_to_wuv = {
943
+ (mu, mv): (w, uv)
944
+ for (mu, mv), uv, w in _lightest_meta_edges(mapping, avail_uv, avail_w)
945
+ }
946
+
947
+ # Mapping of terms from (Khuller and Thurimella):
948
+ # C : G_0 = (V, E^0)
949
+ # This is the metagraph where each node is a 2-edge-cc in G.
950
+ # The edges in C represent bridges in the original graph.
951
+ # (mu, mv) : E - E^0 # they group both avail and given edges in E
952
+ # T : \Gamma
953
+ # D : G^D = (V, E_D)
954
+
955
+ # The paper uses ancestor because children point to parents, which is
956
+ # contrary to networkx standards. So, we actually need to run
957
+ # nx.least_common_ancestor on the reversed Tree.
958
+
959
+ # Pick an arbitrary leaf from C as the root
960
+ try:
961
+ root = next(n for n, d in C.degree() if d == 1)
962
+ except StopIteration: # no nodes found with degree == 1
963
+ return
964
+ # Root C into a tree TR by directing all edges away from the root
965
+ # Note in their paper T directs edges towards the root
966
+ TR = nx.dfs_tree(C, root)
967
+
968
+ # Add to D the directed edges of T and set their weight to zero
969
+ # This indicates that it costs nothing to use edges that were given.
970
+ D = nx.reverse(TR).copy()
971
+
972
+ nx.set_edge_attributes(D, name="weight", values=0)
973
+
974
+ # The LCA of mu and mv in T is the shared ancestor of mu and mv that is
975
+ # located farthest from the root.
976
+ lca_gen = nx.tree_all_pairs_lowest_common_ancestor(
977
+ TR, root=root, pairs=meta_to_wuv.keys()
978
+ )
979
+
980
+ for (mu, mv), lca in lca_gen:
981
+ w, uv = meta_to_wuv[(mu, mv)]
982
+ if lca == mu:
983
+ # If u is an ancestor of v in TR, then add edge u->v to D
984
+ D.add_edge(lca, mv, weight=w, generator=uv)
985
+ elif lca == mv:
986
+ # If v is an ancestor of u in TR, then add edge v->u to D
987
+ D.add_edge(lca, mu, weight=w, generator=uv)
988
+ else:
989
+ # If neither u nor v is a ancestor of the other in TR
990
+ # let t = lca(TR, u, v) and add edges t->u and t->v
991
+ # Track the original edge that GENERATED these edges.
992
+ D.add_edge(lca, mu, weight=w, generator=uv)
993
+ D.add_edge(lca, mv, weight=w, generator=uv)
994
+
995
+ # Then compute a minimum rooted branching
996
+ try:
997
+ # Note the original edges must be directed towards to root for the
998
+ # branching to give us a bridge-augmentation.
999
+ A = _minimum_rooted_branching(D, root)
1000
+ except nx.NetworkXException as err:
1001
+ # If there is no branching then augmentation is not possible
1002
+ raise nx.NetworkXUnfeasible("no 2-edge-augmentation possible") from err
1003
+
1004
+ # For each edge e, in the branching that did not belong to the directed
1005
+ # tree T, add the corresponding edge that **GENERATED** it (this is not
1006
+ # necessarily e itself!)
1007
+
1008
+ # ensure the third case does not generate edges twice
1009
+ bridge_connectors = set()
1010
+ for mu, mv in A.edges():
1011
+ data = D.get_edge_data(mu, mv)
1012
+ if "generator" in data:
1013
+ # Add the avail edge that generated the branching edge.
1014
+ edge = data["generator"]
1015
+ bridge_connectors.add(edge)
1016
+
1017
+ yield from bridge_connectors
1018
+
1019
+
1020
+ def _minimum_rooted_branching(D, root):
1021
+ """Helper function to compute a minimum rooted branching (aka rooted
1022
+ arborescence)
1023
+
1024
+ Before the branching can be computed, the directed graph must be rooted by
1025
+ removing the predecessors of root.
1026
+
1027
+ A branching / arborescence of rooted graph G is a subgraph that contains a
1028
+ directed path from the root to every other vertex. It is the directed
1029
+ analog of the minimum spanning tree problem.
1030
+
1031
+ References
1032
+ ----------
1033
+ [1] Khuller, Samir (2002) Advanced Algorithms Lecture 24 Notes.
1034
+ https://web.archive.org/web/20121030033722/https://www.cs.umd.edu/class/spring2011/cmsc651/lec07.pdf
1035
+ """
1036
+ rooted = D.copy()
1037
+ # root the graph by removing all predecessors to `root`.
1038
+ rooted.remove_edges_from([(u, root) for u in D.predecessors(root)])
1039
+ # Then compute the branching / arborescence.
1040
+ A = nx.minimum_spanning_arborescence(rooted)
1041
+ return A
1042
+
1043
+
1044
+ @nx._dispatchable(returns_graph=True)
1045
+ def collapse(G, grouped_nodes):
1046
+ """Collapses each group of nodes into a single node.
1047
+
1048
+ This is similar to condensation, but works on undirected graphs.
1049
+
1050
+ Parameters
1051
+ ----------
1052
+ G : NetworkX Graph
1053
+
1054
+ grouped_nodes: list or generator
1055
+ Grouping of nodes to collapse. The grouping must be disjoint.
1056
+ If grouped_nodes are strongly_connected_components then this is
1057
+ equivalent to :func:`condensation`.
1058
+
1059
+ Returns
1060
+ -------
1061
+ C : NetworkX Graph
1062
+ The collapsed graph C of G with respect to the node grouping. The node
1063
+ labels are integers corresponding to the index of the component in the
1064
+ list of grouped_nodes. C has a graph attribute named 'mapping' with a
1065
+ dictionary mapping the original nodes to the nodes in C to which they
1066
+ belong. Each node in C also has a node attribute 'members' with the set
1067
+ of original nodes in G that form the group that the node in C
1068
+ represents.
1069
+
1070
+ Examples
1071
+ --------
1072
+ >>> # Collapses a graph using disjoint groups, but not necessarily connected
1073
+ >>> G = nx.Graph([(1, 0), (2, 3), (3, 1), (3, 4), (4, 5), (5, 6), (5, 7)])
1074
+ >>> G.add_node("A")
1075
+ >>> grouped_nodes = [{0, 1, 2, 3}, {5, 6, 7}]
1076
+ >>> C = collapse(G, grouped_nodes)
1077
+ >>> members = nx.get_node_attributes(C, "members")
1078
+ >>> sorted(members.keys())
1079
+ [0, 1, 2, 3]
1080
+ >>> member_values = set(map(frozenset, members.values()))
1081
+ >>> assert {0, 1, 2, 3} in member_values
1082
+ >>> assert {4} in member_values
1083
+ >>> assert {5, 6, 7} in member_values
1084
+ >>> assert {"A"} in member_values
1085
+ """
1086
+ mapping = {}
1087
+ members = {}
1088
+ C = G.__class__()
1089
+ i = 0 # required if G is empty
1090
+ remaining = set(G.nodes())
1091
+ for i, group in enumerate(grouped_nodes):
1092
+ group = set(group)
1093
+ assert remaining.issuperset(group), (
1094
+ "grouped nodes must exist in G and be disjoint"
1095
+ )
1096
+ remaining.difference_update(group)
1097
+ members[i] = group
1098
+ mapping.update((n, i) for n in group)
1099
+ # remaining nodes are in their own group
1100
+ for i, node in enumerate(remaining, start=i + 1):
1101
+ group = {node}
1102
+ members[i] = group
1103
+ mapping.update((n, i) for n in group)
1104
+ number_of_groups = i + 1
1105
+ C.add_nodes_from(range(number_of_groups))
1106
+ C.add_edges_from(
1107
+ (mapping[u], mapping[v]) for u, v in G.edges() if mapping[u] != mapping[v]
1108
+ )
1109
+ # Add a list of members (ie original nodes) to each node (ie scc) in C.
1110
+ nx.set_node_attributes(C, name="members", values=members)
1111
+ # Add mapping dict as graph attribute
1112
+ C.graph["mapping"] = mapping
1113
+ return C
1114
+
1115
+
1116
+ @nx._dispatchable
1117
+ def complement_edges(G):
1118
+ """Returns only the edges in the complement of G
1119
+
1120
+ Parameters
1121
+ ----------
1122
+ G : NetworkX Graph
1123
+
1124
+ Yields
1125
+ ------
1126
+ edge : tuple
1127
+ Edges in the complement of G
1128
+
1129
+ Examples
1130
+ --------
1131
+ >>> G = nx.path_graph((1, 2, 3, 4))
1132
+ >>> sorted(complement_edges(G))
1133
+ [(1, 3), (1, 4), (2, 4)]
1134
+ >>> G = nx.path_graph((1, 2, 3, 4), nx.DiGraph())
1135
+ >>> sorted(complement_edges(G))
1136
+ [(1, 3), (1, 4), (2, 1), (2, 4), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3)]
1137
+ >>> G = nx.complete_graph(1000)
1138
+ >>> sorted(complement_edges(G))
1139
+ []
1140
+ """
1141
+ G_adj = G._adj # Store as a variable to eliminate attribute lookup
1142
+ if G.is_directed():
1143
+ for u, v in it.combinations(G.nodes(), 2):
1144
+ if v not in G_adj[u]:
1145
+ yield (u, v)
1146
+ if u not in G_adj[v]:
1147
+ yield (v, u)
1148
+ else:
1149
+ for u, v in it.combinations(G.nodes(), 2):
1150
+ if v not in G_adj[u]:
1151
+ yield (u, v)
1152
+
1153
+
1154
+ def _compat_shuffle(rng, input):
1155
+ """wrapper around rng.shuffle for python 2 compatibility reasons"""
1156
+ rng.shuffle(input)
1157
+
1158
+
1159
+ @not_implemented_for("multigraph")
1160
+ @not_implemented_for("directed")
1161
+ @py_random_state(4)
1162
+ @nx._dispatchable
1163
+ def greedy_k_edge_augmentation(G, k, avail=None, weight=None, seed=None):
1164
+ """Greedy algorithm for finding a k-edge-augmentation
1165
+
1166
+ Parameters
1167
+ ----------
1168
+ G : NetworkX graph
1169
+ An undirected graph.
1170
+
1171
+ k : integer
1172
+ Desired edge connectivity
1173
+
1174
+ avail : dict or a set of 2 or 3 tuples
1175
+ For more details, see :func:`k_edge_augmentation`.
1176
+
1177
+ weight : string
1178
+ key to use to find weights if ``avail`` is a set of 3-tuples.
1179
+ For more details, see :func:`k_edge_augmentation`.
1180
+
1181
+ seed : integer, random_state, or None (default)
1182
+ Indicator of random number generation state.
1183
+ See :ref:`Randomness<randomness>`.
1184
+
1185
+ Yields
1186
+ ------
1187
+ edge : tuple
1188
+ Edges in the greedy augmentation of G
1189
+
1190
+ Notes
1191
+ -----
1192
+ The algorithm is simple. Edges are incrementally added between parts of the
1193
+ graph that are not yet locally k-edge-connected. Then edges are from the
1194
+ augmenting set are pruned as long as local-edge-connectivity is not broken.
1195
+
1196
+ This algorithm is greedy and does not provide optimality guarantees. It
1197
+ exists only to provide :func:`k_edge_augmentation` with the ability to
1198
+ generate a feasible solution for arbitrary k.
1199
+
1200
+ See Also
1201
+ --------
1202
+ :func:`k_edge_augmentation`
1203
+
1204
+ Examples
1205
+ --------
1206
+ >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7))
1207
+ >>> sorted(greedy_k_edge_augmentation(G, k=2))
1208
+ [(1, 7)]
1209
+ >>> sorted(greedy_k_edge_augmentation(G, k=1, avail=[]))
1210
+ []
1211
+ >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7))
1212
+ >>> avail = {(u, v): 1 for (u, v) in complement_edges(G)}
1213
+ >>> # randomized pruning process can produce different solutions
1214
+ >>> sorted(greedy_k_edge_augmentation(G, k=4, avail=avail, seed=2))
1215
+ [(1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 4), (2, 6), (3, 7), (5, 7)]
1216
+ >>> sorted(greedy_k_edge_augmentation(G, k=4, avail=avail, seed=3))
1217
+ [(1, 3), (1, 5), (1, 6), (2, 4), (2, 6), (3, 7), (4, 7), (5, 7)]
1218
+ """
1219
+ # Result set
1220
+ aug_edges = []
1221
+
1222
+ done = is_k_edge_connected(G, k)
1223
+ if done:
1224
+ return
1225
+ if avail is None:
1226
+ # all edges are available
1227
+ avail_uv = list(complement_edges(G))
1228
+ avail_w = [1] * len(avail_uv)
1229
+ else:
1230
+ # Get the unique set of unweighted edges
1231
+ avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G)
1232
+
1233
+ # Greedy: order lightest edges. Use degree sum to tie-break
1234
+ tiebreaker = [sum(map(G.degree, uv)) for uv in avail_uv]
1235
+ avail_wduv = sorted(zip(avail_w, tiebreaker, avail_uv))
1236
+ avail_uv = [uv for w, d, uv in avail_wduv]
1237
+
1238
+ # Incrementally add edges in until we are k-connected
1239
+ H = G.copy()
1240
+ for u, v in avail_uv:
1241
+ done = False
1242
+ if not is_locally_k_edge_connected(H, u, v, k=k):
1243
+ # Only add edges in parts that are not yet locally k-edge-connected
1244
+ aug_edges.append((u, v))
1245
+ H.add_edge(u, v)
1246
+ # Did adding this edge help?
1247
+ if H.degree(u) >= k and H.degree(v) >= k:
1248
+ done = is_k_edge_connected(H, k)
1249
+ if done:
1250
+ break
1251
+
1252
+ # Check for feasibility
1253
+ if not done:
1254
+ raise nx.NetworkXUnfeasible("not able to k-edge-connect with available edges")
1255
+
1256
+ # Randomized attempt to reduce the size of the solution
1257
+ _compat_shuffle(seed, aug_edges)
1258
+ for u, v in list(aug_edges):
1259
+ # Don't remove if we know it would break connectivity
1260
+ if H.degree(u) <= k or H.degree(v) <= k:
1261
+ continue
1262
+ H.remove_edge(u, v)
1263
+ aug_edges.remove((u, v))
1264
+ if not is_k_edge_connected(H, k=k):
1265
+ # If removing this edge breaks feasibility, undo
1266
+ H.add_edge(u, v)
1267
+ aug_edges.append((u, v))
1268
+
1269
+ # Generate results
1270
+ yield from aug_edges