okstra 0.108.0 → 0.109.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 (642) hide show
  1. package/package.json +1 -1
  2. package/runtime/BUILD.json +2 -2
  3. package/runtime/prompts/profiles/_common-contract.md +1 -1
  4. package/runtime/python/okstra_ctl/graphify_cmd.py +225 -0
  5. package/runtime/python/okstra_ctl/resolve_task_key.py +15 -9
  6. package/runtime/python/okstra_project/__init__.py +2 -0
  7. package/runtime/python/okstra_project/state.py +36 -0
  8. package/runtime/python/okstra_vendor/__init__.py +41 -0
  9. package/runtime/python/okstra_vendor/graphify/.vendored-version +1 -0
  10. package/runtime/python/okstra_vendor/graphify/__init__.py +28 -0
  11. package/runtime/python/okstra_vendor/graphify/__main__.py +1371 -0
  12. package/runtime/python/okstra_vendor/graphify/analyze.py +540 -0
  13. package/runtime/python/okstra_vendor/graphify/benchmark.py +129 -0
  14. package/runtime/python/okstra_vendor/graphify/build.py +107 -0
  15. package/runtime/python/okstra_vendor/graphify/cache.py +169 -0
  16. package/runtime/python/okstra_vendor/graphify/cluster.py +137 -0
  17. package/runtime/python/okstra_vendor/graphify/detect.py +510 -0
  18. package/runtime/python/okstra_vendor/graphify/export.py +1014 -0
  19. package/runtime/python/okstra_vendor/graphify/extract.py +3277 -0
  20. package/runtime/python/okstra_vendor/graphify/hooks.py +220 -0
  21. package/runtime/python/okstra_vendor/graphify/ingest.py +297 -0
  22. package/runtime/python/okstra_vendor/graphify/manifest.py +4 -0
  23. package/runtime/python/okstra_vendor/graphify/report.py +175 -0
  24. package/runtime/python/okstra_vendor/graphify/security.py +203 -0
  25. package/runtime/python/okstra_vendor/graphify/serve.py +373 -0
  26. package/runtime/python/okstra_vendor/graphify/skill-aider.md +1184 -0
  27. package/runtime/python/okstra_vendor/graphify/skill-claw.md +1184 -0
  28. package/runtime/python/okstra_vendor/graphify/skill-codex.md +1242 -0
  29. package/runtime/python/okstra_vendor/graphify/skill-copilot.md +1268 -0
  30. package/runtime/python/okstra_vendor/graphify/skill-droid.md +1239 -0
  31. package/runtime/python/okstra_vendor/graphify/skill-kiro.md +1183 -0
  32. package/runtime/python/okstra_vendor/graphify/skill-opencode.md +1238 -0
  33. package/runtime/python/okstra_vendor/graphify/skill-trae.md +1208 -0
  34. package/runtime/python/okstra_vendor/graphify/skill-vscode.md +253 -0
  35. package/runtime/python/okstra_vendor/graphify/skill-windows.md +1245 -0
  36. package/runtime/python/okstra_vendor/graphify/skill.md +1319 -0
  37. package/runtime/python/okstra_vendor/graphify/transcribe.py +182 -0
  38. package/runtime/python/okstra_vendor/graphify/validate.py +72 -0
  39. package/runtime/python/okstra_vendor/graphify/watch.py +188 -0
  40. package/runtime/python/okstra_vendor/graphify/wiki.py +214 -0
  41. package/runtime/python/okstra_vendor/networkx/__init__.py +62 -0
  42. package/runtime/python/okstra_vendor/networkx/algorithms/__init__.py +134 -0
  43. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/__init__.py +26 -0
  44. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clique.py +259 -0
  45. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clustering_coefficient.py +71 -0
  46. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/connectivity.py +412 -0
  47. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/density.py +396 -0
  48. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/distance_measures.py +150 -0
  49. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/dominating_set.py +149 -0
  50. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/kcomponents.py +369 -0
  51. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/matching.py +44 -0
  52. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/maxcut.py +143 -0
  53. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/ramsey.py +53 -0
  54. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/steinertree.py +265 -0
  55. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
  56. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +41 -0
  57. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +112 -0
  58. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +199 -0
  59. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +146 -0
  60. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +59 -0
  61. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +78 -0
  62. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +303 -0
  63. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +8 -0
  64. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +94 -0
  65. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +31 -0
  66. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +306 -0
  67. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +1014 -0
  68. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +274 -0
  69. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +68 -0
  70. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/traveling_salesman.py +1508 -0
  71. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/treewidth.py +255 -0
  72. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/vertex_cover.py +83 -0
  73. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/__init__.py +5 -0
  74. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/connectivity.py +122 -0
  75. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/correlation.py +302 -0
  76. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/mixing.py +255 -0
  77. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/neighbor_degree.py +160 -0
  78. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/pairs.py +127 -0
  79. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
  80. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +81 -0
  81. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +143 -0
  82. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +122 -0
  83. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +174 -0
  84. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +107 -0
  85. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +87 -0
  86. package/runtime/python/okstra_vendor/networkx/algorithms/asteroidal.py +164 -0
  87. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/__init__.py +88 -0
  88. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/basic.py +322 -0
  89. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/centrality.py +290 -0
  90. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/cluster.py +289 -0
  91. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/covering.py +57 -0
  92. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/edgelist.py +360 -0
  93. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/extendability.py +105 -0
  94. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/generators.py +603 -0
  95. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/link_analysis.py +316 -0
  96. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matching.py +590 -0
  97. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matrix.py +232 -0
  98. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/projection.py +526 -0
  99. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/redundancy.py +112 -0
  100. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/spectral.py +69 -0
  101. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
  102. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +125 -0
  103. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +192 -0
  104. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +84 -0
  105. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +33 -0
  106. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +240 -0
  107. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +334 -0
  108. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +407 -0
  109. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +218 -0
  110. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +327 -0
  111. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +138 -0
  112. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +409 -0
  113. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +35 -0
  114. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +80 -0
  115. package/runtime/python/okstra_vendor/networkx/algorithms/boundary.py +168 -0
  116. package/runtime/python/okstra_vendor/networkx/algorithms/bridges.py +205 -0
  117. package/runtime/python/okstra_vendor/networkx/algorithms/broadcasting.py +164 -0
  118. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/__init__.py +20 -0
  119. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness.py +591 -0
  120. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness_subset.py +236 -0
  121. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/closeness.py +282 -0
  122. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness.py +364 -0
  123. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness_subset.py +227 -0
  124. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_closeness.py +96 -0
  125. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/degree_alg.py +150 -0
  126. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/dispersion.py +107 -0
  127. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/eigenvector.py +357 -0
  128. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/flow_matrix.py +130 -0
  129. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/group.py +787 -0
  130. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/harmonic.py +88 -0
  131. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/katz.py +331 -0
  132. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/laplacian.py +150 -0
  133. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/load.py +200 -0
  134. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/percolation.py +128 -0
  135. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/reaching.py +209 -0
  136. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/second_order.py +141 -0
  137. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/subgraph_alg.py +361 -0
  138. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
  139. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +923 -0
  140. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +354 -0
  141. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +274 -0
  142. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +259 -0
  143. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +147 -0
  144. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +43 -0
  145. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +144 -0
  146. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +73 -0
  147. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +186 -0
  148. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +277 -0
  149. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +122 -0
  150. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +345 -0
  151. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +220 -0
  152. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +344 -0
  153. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +87 -0
  154. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +140 -0
  155. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +82 -0
  156. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +110 -0
  157. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +302 -0
  158. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +64 -0
  159. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/trophic.py +181 -0
  160. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/voterank_alg.py +95 -0
  161. package/runtime/python/okstra_vendor/networkx/algorithms/chains.py +172 -0
  162. package/runtime/python/okstra_vendor/networkx/algorithms/chordal.py +443 -0
  163. package/runtime/python/okstra_vendor/networkx/algorithms/clique.py +818 -0
  164. package/runtime/python/okstra_vendor/networkx/algorithms/cluster.py +732 -0
  165. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/__init__.py +4 -0
  166. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/equitable_coloring.py +505 -0
  167. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/greedy_coloring.py +565 -0
  168. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
  169. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +863 -0
  170. package/runtime/python/okstra_vendor/networkx/algorithms/communicability_alg.py +163 -0
  171. package/runtime/python/okstra_vendor/networkx/algorithms/community/__init__.py +28 -0
  172. package/runtime/python/okstra_vendor/networkx/algorithms/community/asyn_fluid.py +153 -0
  173. package/runtime/python/okstra_vendor/networkx/algorithms/community/bipartitions.py +354 -0
  174. package/runtime/python/okstra_vendor/networkx/algorithms/community/centrality.py +171 -0
  175. package/runtime/python/okstra_vendor/networkx/algorithms/community/community_utils.py +30 -0
  176. package/runtime/python/okstra_vendor/networkx/algorithms/community/divisive.py +216 -0
  177. package/runtime/python/okstra_vendor/networkx/algorithms/community/kclique.py +79 -0
  178. package/runtime/python/okstra_vendor/networkx/algorithms/community/label_propagation.py +338 -0
  179. package/runtime/python/okstra_vendor/networkx/algorithms/community/leiden.py +162 -0
  180. package/runtime/python/okstra_vendor/networkx/algorithms/community/local.py +220 -0
  181. package/runtime/python/okstra_vendor/networkx/algorithms/community/louvain.py +384 -0
  182. package/runtime/python/okstra_vendor/networkx/algorithms/community/lukes.py +227 -0
  183. package/runtime/python/okstra_vendor/networkx/algorithms/community/modularity_max.py +452 -0
  184. package/runtime/python/okstra_vendor/networkx/algorithms/community/quality.py +347 -0
  185. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
  186. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +147 -0
  187. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +157 -0
  188. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +85 -0
  189. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +106 -0
  190. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +91 -0
  191. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +241 -0
  192. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +138 -0
  193. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +76 -0
  194. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +264 -0
  195. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +152 -0
  196. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +340 -0
  197. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +139 -0
  198. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +26 -0
  199. package/runtime/python/okstra_vendor/networkx/algorithms/components/__init__.py +6 -0
  200. package/runtime/python/okstra_vendor/networkx/algorithms/components/attracting.py +115 -0
  201. package/runtime/python/okstra_vendor/networkx/algorithms/components/biconnected.py +394 -0
  202. package/runtime/python/okstra_vendor/networkx/algorithms/components/connected.py +282 -0
  203. package/runtime/python/okstra_vendor/networkx/algorithms/components/semiconnected.py +71 -0
  204. package/runtime/python/okstra_vendor/networkx/algorithms/components/strongly_connected.py +359 -0
  205. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
  206. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +70 -0
  207. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +248 -0
  208. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +138 -0
  209. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +55 -0
  210. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +193 -0
  211. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +96 -0
  212. package/runtime/python/okstra_vendor/networkx/algorithms/components/weakly_connected.py +196 -0
  213. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/__init__.py +11 -0
  214. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/connectivity.py +811 -0
  215. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/cuts.py +616 -0
  216. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/disjoint_paths.py +408 -0
  217. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_augmentation.py +1270 -0
  218. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_kcomponents.py +592 -0
  219. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcomponents.py +220 -0
  220. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcutsets.py +235 -0
  221. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/stoerwagner.py +152 -0
  222. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
  223. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +421 -0
  224. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +309 -0
  225. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +249 -0
  226. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +502 -0
  227. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +488 -0
  228. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +323 -0
  229. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +280 -0
  230. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +102 -0
  231. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/utils.py +88 -0
  232. package/runtime/python/okstra_vendor/networkx/algorithms/core.py +588 -0
  233. package/runtime/python/okstra_vendor/networkx/algorithms/covering.py +142 -0
  234. package/runtime/python/okstra_vendor/networkx/algorithms/cuts.py +416 -0
  235. package/runtime/python/okstra_vendor/networkx/algorithms/cycles.py +1234 -0
  236. package/runtime/python/okstra_vendor/networkx/algorithms/d_separation.py +677 -0
  237. package/runtime/python/okstra_vendor/networkx/algorithms/dag.py +1392 -0
  238. package/runtime/python/okstra_vendor/networkx/algorithms/distance_measures.py +1095 -0
  239. package/runtime/python/okstra_vendor/networkx/algorithms/distance_regular.py +272 -0
  240. package/runtime/python/okstra_vendor/networkx/algorithms/dominance.py +142 -0
  241. package/runtime/python/okstra_vendor/networkx/algorithms/dominating.py +268 -0
  242. package/runtime/python/okstra_vendor/networkx/algorithms/efficiency_measures.py +167 -0
  243. package/runtime/python/okstra_vendor/networkx/algorithms/euler.py +470 -0
  244. package/runtime/python/okstra_vendor/networkx/algorithms/flow/__init__.py +11 -0
  245. package/runtime/python/okstra_vendor/networkx/algorithms/flow/boykovkolmogorov.py +370 -0
  246. package/runtime/python/okstra_vendor/networkx/algorithms/flow/capacityscaling.py +407 -0
  247. package/runtime/python/okstra_vendor/networkx/algorithms/flow/dinitz_alg.py +238 -0
  248. package/runtime/python/okstra_vendor/networkx/algorithms/flow/edmondskarp.py +241 -0
  249. package/runtime/python/okstra_vendor/networkx/algorithms/flow/gomory_hu.py +178 -0
  250. package/runtime/python/okstra_vendor/networkx/algorithms/flow/maxflow.py +611 -0
  251. package/runtime/python/okstra_vendor/networkx/algorithms/flow/mincost.py +356 -0
  252. package/runtime/python/okstra_vendor/networkx/algorithms/flow/networksimplex.py +662 -0
  253. package/runtime/python/okstra_vendor/networkx/algorithms/flow/preflowpush.py +425 -0
  254. package/runtime/python/okstra_vendor/networkx/algorithms/flow/shortestaugmentingpath.py +300 -0
  255. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
  256. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
  257. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
  258. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
  259. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +128 -0
  260. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +573 -0
  261. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +155 -0
  262. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +475 -0
  263. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +481 -0
  264. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
  265. package/runtime/python/okstra_vendor/networkx/algorithms/flow/utils.py +194 -0
  266. package/runtime/python/okstra_vendor/networkx/algorithms/graph_hashing.py +435 -0
  267. package/runtime/python/okstra_vendor/networkx/algorithms/graphical.py +483 -0
  268. package/runtime/python/okstra_vendor/networkx/algorithms/hierarchy.py +57 -0
  269. package/runtime/python/okstra_vendor/networkx/algorithms/hybrid.py +196 -0
  270. package/runtime/python/okstra_vendor/networkx/algorithms/isolate.py +107 -0
  271. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/__init__.py +7 -0
  272. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/ismags.py +1306 -0
  273. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorph.py +336 -0
  274. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorphvf2.py +1262 -0
  275. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/matchhelpers.py +352 -0
  276. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/temporalisomorphvf2.py +308 -0
  277. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
  278. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
  279. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
  280. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
  281. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
  282. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +719 -0
  283. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +103 -0
  284. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +490 -0
  285. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +64 -0
  286. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +212 -0
  287. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +202 -0
  288. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +1655 -0
  289. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +3118 -0
  290. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +196 -0
  291. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tree_isomorphism.py +264 -0
  292. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2pp.py +1102 -0
  293. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2userfunc.py +192 -0
  294. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/__init__.py +2 -0
  295. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/hits_alg.py +337 -0
  296. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/pagerank_alg.py +498 -0
  297. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
  298. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +77 -0
  299. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +213 -0
  300. package/runtime/python/okstra_vendor/networkx/algorithms/link_prediction.py +687 -0
  301. package/runtime/python/okstra_vendor/networkx/algorithms/lowest_common_ancestors.py +280 -0
  302. package/runtime/python/okstra_vendor/networkx/algorithms/matching.py +1148 -0
  303. package/runtime/python/okstra_vendor/networkx/algorithms/minors/__init__.py +27 -0
  304. package/runtime/python/okstra_vendor/networkx/algorithms/minors/contraction.py +738 -0
  305. package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +544 -0
  306. package/runtime/python/okstra_vendor/networkx/algorithms/mis.py +78 -0
  307. package/runtime/python/okstra_vendor/networkx/algorithms/moral.py +59 -0
  308. package/runtime/python/okstra_vendor/networkx/algorithms/node_classification.py +219 -0
  309. package/runtime/python/okstra_vendor/networkx/algorithms/non_randomness.py +155 -0
  310. package/runtime/python/okstra_vendor/networkx/algorithms/operators/__init__.py +4 -0
  311. package/runtime/python/okstra_vendor/networkx/algorithms/operators/all.py +324 -0
  312. package/runtime/python/okstra_vendor/networkx/algorithms/operators/binary.py +468 -0
  313. package/runtime/python/okstra_vendor/networkx/algorithms/operators/product.py +633 -0
  314. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
  315. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +328 -0
  316. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +451 -0
  317. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +491 -0
  318. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +55 -0
  319. package/runtime/python/okstra_vendor/networkx/algorithms/operators/unary.py +77 -0
  320. package/runtime/python/okstra_vendor/networkx/algorithms/perfect_graph.py +73 -0
  321. package/runtime/python/okstra_vendor/networkx/algorithms/planar_drawing.py +464 -0
  322. package/runtime/python/okstra_vendor/networkx/algorithms/planarity.py +1463 -0
  323. package/runtime/python/okstra_vendor/networkx/algorithms/polynomials.py +306 -0
  324. package/runtime/python/okstra_vendor/networkx/algorithms/reciprocity.py +98 -0
  325. package/runtime/python/okstra_vendor/networkx/algorithms/regular.py +167 -0
  326. package/runtime/python/okstra_vendor/networkx/algorithms/richclub.py +138 -0
  327. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/__init__.py +5 -0
  328. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/astar.py +239 -0
  329. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/dense.py +264 -0
  330. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/generic.py +716 -0
  331. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
  332. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +254 -0
  333. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +212 -0
  334. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +88 -0
  335. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +511 -0
  336. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +149 -0
  337. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +983 -0
  338. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/unweighted.py +625 -0
  339. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/weighted.py +2542 -0
  340. package/runtime/python/okstra_vendor/networkx/algorithms/similarity.py +2107 -0
  341. package/runtime/python/okstra_vendor/networkx/algorithms/simple_paths.py +966 -0
  342. package/runtime/python/okstra_vendor/networkx/algorithms/smallworld.py +404 -0
  343. package/runtime/python/okstra_vendor/networkx/algorithms/smetric.py +30 -0
  344. package/runtime/python/okstra_vendor/networkx/algorithms/sparsifiers.py +296 -0
  345. package/runtime/python/okstra_vendor/networkx/algorithms/structuralholes.py +374 -0
  346. package/runtime/python/okstra_vendor/networkx/algorithms/summarization.py +564 -0
  347. package/runtime/python/okstra_vendor/networkx/algorithms/swap.py +406 -0
  348. package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
  349. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +23 -0
  350. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +154 -0
  351. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +144 -0
  352. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +109 -0
  353. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +136 -0
  354. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +129 -0
  355. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +300 -0
  356. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +678 -0
  357. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +80 -0
  358. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +266 -0
  359. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +85 -0
  360. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +171 -0
  361. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +984 -0
  362. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +340 -0
  363. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +835 -0
  364. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +831 -0
  365. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +85 -0
  366. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +299 -0
  367. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +115 -0
  368. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +58 -0
  369. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +314 -0
  370. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +872 -0
  371. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +163 -0
  372. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +46 -0
  373. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +24 -0
  374. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +26 -0
  375. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +615 -0
  376. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +459 -0
  377. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +556 -0
  378. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +179 -0
  379. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +62 -0
  380. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +15 -0
  381. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +140 -0
  382. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +60 -0
  383. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +27 -0
  384. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +274 -0
  385. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +556 -0
  386. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +57 -0
  387. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +37 -0
  388. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +88 -0
  389. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +149 -0
  390. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +1158 -0
  391. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +803 -0
  392. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +76 -0
  393. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +8 -0
  394. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +138 -0
  395. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +191 -0
  396. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +642 -0
  397. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +179 -0
  398. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +270 -0
  399. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +431 -0
  400. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +161 -0
  401. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +248 -0
  402. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +41 -0
  403. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +103 -0
  404. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +54 -0
  405. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +157 -0
  406. package/runtime/python/okstra_vendor/networkx/algorithms/threshold.py +981 -0
  407. package/runtime/python/okstra_vendor/networkx/algorithms/time_dependent.py +142 -0
  408. package/runtime/python/okstra_vendor/networkx/algorithms/tournament.py +406 -0
  409. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/__init__.py +5 -0
  410. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/beamsearch.py +90 -0
  411. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/breadth_first_search.py +576 -0
  412. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/depth_first_search.py +529 -0
  413. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgebfs.py +185 -0
  414. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgedfs.py +182 -0
  415. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
  416. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +25 -0
  417. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +203 -0
  418. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +307 -0
  419. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +147 -0
  420. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +131 -0
  421. package/runtime/python/okstra_vendor/networkx/algorithms/tree/__init__.py +7 -0
  422. package/runtime/python/okstra_vendor/networkx/algorithms/tree/branchings.py +1042 -0
  423. package/runtime/python/okstra_vendor/networkx/algorithms/tree/coding.py +413 -0
  424. package/runtime/python/okstra_vendor/networkx/algorithms/tree/decomposition.py +88 -0
  425. package/runtime/python/okstra_vendor/networkx/algorithms/tree/distance_measures.py +219 -0
  426. package/runtime/python/okstra_vendor/networkx/algorithms/tree/mst.py +1281 -0
  427. package/runtime/python/okstra_vendor/networkx/algorithms/tree/operations.py +106 -0
  428. package/runtime/python/okstra_vendor/networkx/algorithms/tree/recognition.py +273 -0
  429. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
  430. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +624 -0
  431. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +114 -0
  432. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +79 -0
  433. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +99 -0
  434. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +934 -0
  435. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +53 -0
  436. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +174 -0
  437. package/runtime/python/okstra_vendor/networkx/algorithms/triads.py +500 -0
  438. package/runtime/python/okstra_vendor/networkx/algorithms/vitality.py +76 -0
  439. package/runtime/python/okstra_vendor/networkx/algorithms/voronoi.py +86 -0
  440. package/runtime/python/okstra_vendor/networkx/algorithms/walks.py +77 -0
  441. package/runtime/python/okstra_vendor/networkx/algorithms/wiener.py +278 -0
  442. package/runtime/python/okstra_vendor/networkx/classes/__init__.py +13 -0
  443. package/runtime/python/okstra_vendor/networkx/classes/coreviews.py +435 -0
  444. package/runtime/python/okstra_vendor/networkx/classes/digraph.py +1363 -0
  445. package/runtime/python/okstra_vendor/networkx/classes/filters.py +95 -0
  446. package/runtime/python/okstra_vendor/networkx/classes/function.py +1549 -0
  447. package/runtime/python/okstra_vendor/networkx/classes/graph.py +2082 -0
  448. package/runtime/python/okstra_vendor/networkx/classes/graphviews.py +269 -0
  449. package/runtime/python/okstra_vendor/networkx/classes/multidigraph.py +977 -0
  450. package/runtime/python/okstra_vendor/networkx/classes/multigraph.py +1294 -0
  451. package/runtime/python/okstra_vendor/networkx/classes/reportviews.py +1447 -0
  452. package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
  453. package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +192 -0
  454. package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +476 -0
  455. package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +362 -0
  456. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +331 -0
  457. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +110 -0
  458. package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +177 -0
  459. package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +1045 -0
  460. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +950 -0
  461. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +12 -0
  462. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +349 -0
  463. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +459 -0
  464. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +528 -0
  465. package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +1421 -0
  466. package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +131 -0
  467. package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +371 -0
  468. package/runtime/python/okstra_vendor/networkx/conftest.py +261 -0
  469. package/runtime/python/okstra_vendor/networkx/convert.py +502 -0
  470. package/runtime/python/okstra_vendor/networkx/convert_matrix.py +1314 -0
  471. package/runtime/python/okstra_vendor/networkx/drawing/__init__.py +7 -0
  472. package/runtime/python/okstra_vendor/networkx/drawing/layout.py +2036 -0
  473. package/runtime/python/okstra_vendor/networkx/drawing/nx_agraph.py +470 -0
  474. package/runtime/python/okstra_vendor/networkx/drawing/nx_latex.py +570 -0
  475. package/runtime/python/okstra_vendor/networkx/drawing/nx_pydot.py +361 -0
  476. package/runtime/python/okstra_vendor/networkx/drawing/nx_pylab.py +2978 -0
  477. package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
  478. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
  479. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
  480. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
  481. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
  482. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
  483. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
  484. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +237 -0
  485. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +229 -0
  486. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +285 -0
  487. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +631 -0
  488. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +146 -0
  489. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +1582 -0
  490. package/runtime/python/okstra_vendor/networkx/exception.py +131 -0
  491. package/runtime/python/okstra_vendor/networkx/generators/__init__.py +34 -0
  492. package/runtime/python/okstra_vendor/networkx/generators/atlas.dat.gz +0 -0
  493. package/runtime/python/okstra_vendor/networkx/generators/atlas.py +227 -0
  494. package/runtime/python/okstra_vendor/networkx/generators/classic.py +1091 -0
  495. package/runtime/python/okstra_vendor/networkx/generators/cographs.py +68 -0
  496. package/runtime/python/okstra_vendor/networkx/generators/community.py +1070 -0
  497. package/runtime/python/okstra_vendor/networkx/generators/degree_seq.py +886 -0
  498. package/runtime/python/okstra_vendor/networkx/generators/directed.py +572 -0
  499. package/runtime/python/okstra_vendor/networkx/generators/duplication.py +174 -0
  500. package/runtime/python/okstra_vendor/networkx/generators/ego.py +66 -0
  501. package/runtime/python/okstra_vendor/networkx/generators/expanders.py +499 -0
  502. package/runtime/python/okstra_vendor/networkx/generators/geometric.py +1037 -0
  503. package/runtime/python/okstra_vendor/networkx/generators/harary_graph.py +163 -0
  504. package/runtime/python/okstra_vendor/networkx/generators/internet_as_graphs.py +443 -0
  505. package/runtime/python/okstra_vendor/networkx/generators/intersection.py +125 -0
  506. package/runtime/python/okstra_vendor/networkx/generators/interval_graph.py +70 -0
  507. package/runtime/python/okstra_vendor/networkx/generators/joint_degree_seq.py +664 -0
  508. package/runtime/python/okstra_vendor/networkx/generators/lattice.py +405 -0
  509. package/runtime/python/okstra_vendor/networkx/generators/line.py +501 -0
  510. package/runtime/python/okstra_vendor/networkx/generators/mycielski.py +110 -0
  511. package/runtime/python/okstra_vendor/networkx/generators/nonisomorphic_trees.py +259 -0
  512. package/runtime/python/okstra_vendor/networkx/generators/random_clustered.py +117 -0
  513. package/runtime/python/okstra_vendor/networkx/generators/random_graphs.py +1416 -0
  514. package/runtime/python/okstra_vendor/networkx/generators/small.py +1070 -0
  515. package/runtime/python/okstra_vendor/networkx/generators/social.py +554 -0
  516. package/runtime/python/okstra_vendor/networkx/generators/spectral_graph_forge.py +120 -0
  517. package/runtime/python/okstra_vendor/networkx/generators/stochastic.py +54 -0
  518. package/runtime/python/okstra_vendor/networkx/generators/sudoku.py +131 -0
  519. package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
  520. package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +75 -0
  521. package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +642 -0
  522. package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +20 -0
  523. package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +362 -0
  524. package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +224 -0
  525. package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +189 -0
  526. package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +103 -0
  527. package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +39 -0
  528. package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +182 -0
  529. package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +488 -0
  530. package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +133 -0
  531. package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +221 -0
  532. package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +28 -0
  533. package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +144 -0
  534. package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +125 -0
  535. package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +264 -0
  536. package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +316 -0
  537. package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +30 -0
  538. package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +82 -0
  539. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +33 -0
  540. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +495 -0
  541. package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +220 -0
  542. package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +49 -0
  543. package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +72 -0
  544. package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +92 -0
  545. package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +64 -0
  546. package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +195 -0
  547. package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +15 -0
  548. package/runtime/python/okstra_vendor/networkx/generators/time_series.py +74 -0
  549. package/runtime/python/okstra_vendor/networkx/generators/trees.py +1070 -0
  550. package/runtime/python/okstra_vendor/networkx/generators/triads.py +94 -0
  551. package/runtime/python/okstra_vendor/networkx/lazy_imports.py +188 -0
  552. package/runtime/python/okstra_vendor/networkx/linalg/__init__.py +13 -0
  553. package/runtime/python/okstra_vendor/networkx/linalg/algebraicconnectivity.py +650 -0
  554. package/runtime/python/okstra_vendor/networkx/linalg/attrmatrix.py +466 -0
  555. package/runtime/python/okstra_vendor/networkx/linalg/bethehessianmatrix.py +77 -0
  556. package/runtime/python/okstra_vendor/networkx/linalg/graphmatrix.py +168 -0
  557. package/runtime/python/okstra_vendor/networkx/linalg/laplacianmatrix.py +512 -0
  558. package/runtime/python/okstra_vendor/networkx/linalg/modularitymatrix.py +166 -0
  559. package/runtime/python/okstra_vendor/networkx/linalg/spectrum.py +186 -0
  560. package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
  561. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +400 -0
  562. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +108 -0
  563. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +40 -0
  564. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +275 -0
  565. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +334 -0
  566. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +86 -0
  567. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +70 -0
  568. package/runtime/python/okstra_vendor/networkx/readwrite/__init__.py +17 -0
  569. package/runtime/python/okstra_vendor/networkx/readwrite/adjlist.py +330 -0
  570. package/runtime/python/okstra_vendor/networkx/readwrite/edgelist.py +489 -0
  571. package/runtime/python/okstra_vendor/networkx/readwrite/gexf.py +1084 -0
  572. package/runtime/python/okstra_vendor/networkx/readwrite/gml.py +879 -0
  573. package/runtime/python/okstra_vendor/networkx/readwrite/graph6.py +427 -0
  574. package/runtime/python/okstra_vendor/networkx/readwrite/graphml.py +1053 -0
  575. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/__init__.py +19 -0
  576. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/adjacency.py +156 -0
  577. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/cytoscape.py +190 -0
  578. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/node_link.py +261 -0
  579. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
  580. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +78 -0
  581. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +78 -0
  582. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +109 -0
  583. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +48 -0
  584. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tree.py +137 -0
  585. package/runtime/python/okstra_vendor/networkx/readwrite/leda.py +108 -0
  586. package/runtime/python/okstra_vendor/networkx/readwrite/multiline_adjlist.py +393 -0
  587. package/runtime/python/okstra_vendor/networkx/readwrite/p2g.py +113 -0
  588. package/runtime/python/okstra_vendor/networkx/readwrite/pajek.py +286 -0
  589. package/runtime/python/okstra_vendor/networkx/readwrite/sparse6.py +379 -0
  590. package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
  591. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +354 -0
  592. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +318 -0
  593. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +612 -0
  594. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +744 -0
  595. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +181 -0
  596. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +1531 -0
  597. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +30 -0
  598. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +63 -0
  599. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +128 -0
  600. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +166 -0
  601. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +1742 -0
  602. package/runtime/python/okstra_vendor/networkx/readwrite/text.py +851 -0
  603. package/runtime/python/okstra_vendor/networkx/relabel.py +285 -0
  604. package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
  605. package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +248 -0
  606. package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +321 -0
  607. package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +531 -0
  608. package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +349 -0
  609. package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +281 -0
  610. package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +40 -0
  611. package/runtime/python/okstra_vendor/networkx/tests/test_import.py +11 -0
  612. package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +96 -0
  613. package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +349 -0
  614. package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +8 -0
  615. package/runtime/python/okstra_vendor/networkx/utils/__init__.py +8 -0
  616. package/runtime/python/okstra_vendor/networkx/utils/backends.py +2171 -0
  617. package/runtime/python/okstra_vendor/networkx/utils/configs.py +396 -0
  618. package/runtime/python/okstra_vendor/networkx/utils/decorators.py +1233 -0
  619. package/runtime/python/okstra_vendor/networkx/utils/heaps.py +338 -0
  620. package/runtime/python/okstra_vendor/networkx/utils/mapped_queue.py +297 -0
  621. package/runtime/python/okstra_vendor/networkx/utils/misc.py +703 -0
  622. package/runtime/python/okstra_vendor/networkx/utils/random_sequence.py +198 -0
  623. package/runtime/python/okstra_vendor/networkx/utils/rcm.py +159 -0
  624. package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
  625. package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +11 -0
  626. package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +225 -0
  627. package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +263 -0
  628. package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +510 -0
  629. package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +131 -0
  630. package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +268 -0
  631. package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +393 -0
  632. package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +53 -0
  633. package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +63 -0
  634. package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +55 -0
  635. package/runtime/python/okstra_vendor/networkx/utils/union_find.py +106 -0
  636. package/runtime/skills/okstra-graphify/SKILL.md +161 -0
  637. package/runtime/skills/okstra-inspect/SKILL.md +17 -9
  638. package/runtime/templates/reports/settings.template.json +4 -0
  639. package/src/cli-registry.mjs +7 -0
  640. package/src/commands/graphify.mjs +32 -0
  641. package/src/commands/lifecycle/doctor.mjs +9 -0
  642. package/src/lib/skill-catalog.mjs +1 -0
@@ -0,0 +1,2542 @@
1
+ """
2
+ Shortest path algorithms for weighted graphs.
3
+ """
4
+
5
+ from collections import deque
6
+ from heapq import heappop, heappush
7
+ from itertools import count, islice
8
+
9
+ import networkx as nx
10
+ from networkx.algorithms.shortest_paths.generic import _build_paths_from_predecessors
11
+
12
+ __all__ = [
13
+ "dijkstra_path",
14
+ "dijkstra_path_length",
15
+ "bidirectional_dijkstra",
16
+ "single_source_dijkstra",
17
+ "single_source_dijkstra_path",
18
+ "single_source_dijkstra_path_length",
19
+ "multi_source_dijkstra",
20
+ "multi_source_dijkstra_path",
21
+ "multi_source_dijkstra_path_length",
22
+ "all_pairs_dijkstra",
23
+ "all_pairs_dijkstra_path",
24
+ "all_pairs_dijkstra_path_length",
25
+ "dijkstra_predecessor_and_distance",
26
+ "bellman_ford_path",
27
+ "bellman_ford_path_length",
28
+ "single_source_bellman_ford",
29
+ "single_source_bellman_ford_path",
30
+ "single_source_bellman_ford_path_length",
31
+ "all_pairs_bellman_ford_path",
32
+ "all_pairs_bellman_ford_path_length",
33
+ "bellman_ford_predecessor_and_distance",
34
+ "negative_edge_cycle",
35
+ "find_negative_cycle",
36
+ "goldberg_radzik",
37
+ "johnson",
38
+ ]
39
+
40
+
41
+ def _weight_function(G, weight):
42
+ """Returns a function that returns the weight of an edge.
43
+
44
+ The returned function is specifically suitable for input to
45
+ functions :func:`_dijkstra` and :func:`_bellman_ford_relaxation`.
46
+
47
+ Parameters
48
+ ----------
49
+ G : NetworkX graph.
50
+
51
+ weight : string or function
52
+ If it is callable, `weight` itself is returned. If it is a string,
53
+ it is assumed to be the name of the edge attribute that represents
54
+ the weight of an edge. In that case, a function is returned that
55
+ gets the edge weight according to the specified edge attribute.
56
+
57
+ Returns
58
+ -------
59
+ function
60
+ This function returns a callable that accepts exactly three inputs:
61
+ a node, an node adjacent to the first one, and the edge attribute
62
+ dictionary for the eedge joining those nodes. That function returns
63
+ a number representing the weight of an edge.
64
+
65
+ If `G` is a multigraph, and `weight` is not callable, the
66
+ minimum edge weight over all parallel edges is returned. If any edge
67
+ does not have an attribute with key `weight`, it is assumed to
68
+ have weight one.
69
+
70
+ """
71
+ if callable(weight):
72
+ return weight
73
+ # If the weight keyword argument is not callable, we assume it is a
74
+ # string representing the edge attribute containing the weight of
75
+ # the edge.
76
+ if G.is_multigraph():
77
+ return lambda u, v, d: min(attr.get(weight, 1) for attr in d.values())
78
+ return lambda u, v, data: data.get(weight, 1)
79
+
80
+
81
+ @nx._dispatchable(edge_attrs="weight")
82
+ def dijkstra_path(G, source, target, weight="weight"):
83
+ """Returns the shortest weighted path from source to target in G.
84
+
85
+ Uses Dijkstra's Method to compute the shortest weighted path
86
+ between two nodes in a graph.
87
+
88
+ Parameters
89
+ ----------
90
+ G : NetworkX graph
91
+
92
+ source : node
93
+ Starting node
94
+
95
+ target : node
96
+ Ending node
97
+
98
+ weight : string or function
99
+ If this is a string, then edge weights will be accessed via the
100
+ edge attribute with this key (that is, the weight of the edge
101
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
102
+ such edge attribute exists, the weight of the edge is assumed to
103
+ be one.
104
+
105
+ If this is a function, the weight of an edge is the value
106
+ returned by the function. The function must accept exactly three
107
+ positional arguments: the two endpoints of an edge and the
108
+ dictionary of edge attributes for that edge. The function must
109
+ return a number or None to indicate a hidden edge.
110
+
111
+ Returns
112
+ -------
113
+ path : list
114
+ List of nodes in a shortest path.
115
+
116
+ Raises
117
+ ------
118
+ NodeNotFound
119
+ If `source` is not in `G`.
120
+
121
+ NetworkXNoPath
122
+ If no path exists between source and target.
123
+
124
+ Examples
125
+ --------
126
+ >>> G = nx.path_graph(5)
127
+ >>> print(nx.dijkstra_path(G, 0, 4))
128
+ [0, 1, 2, 3, 4]
129
+
130
+ Find edges of shortest path in Multigraph
131
+
132
+ >>> G = nx.MultiDiGraph()
133
+ >>> G.add_weighted_edges_from([(1, 2, 0.75), (1, 2, 0.5), (2, 3, 0.5), (1, 3, 1.5)])
134
+ >>> nodes = nx.dijkstra_path(G, 1, 3)
135
+ >>> edges = nx.utils.pairwise(nodes)
136
+ >>> list(
137
+ ... (u, v, min(G[u][v], key=lambda k: G[u][v][k].get("weight", 1)))
138
+ ... for u, v in edges
139
+ ... )
140
+ [(1, 2, 1), (2, 3, 0)]
141
+
142
+ Notes
143
+ -----
144
+ Edge weight attributes must be numerical.
145
+ Distances are calculated as sums of weighted edges traversed.
146
+
147
+ The weight function can be used to hide edges by returning None.
148
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
149
+ will find the shortest red path.
150
+
151
+ The weight function can be used to include node weights.
152
+
153
+ >>> def func(u, v, d):
154
+ ... node_u_wt = G.nodes[u].get("node_weight", 1)
155
+ ... node_v_wt = G.nodes[v].get("node_weight", 1)
156
+ ... edge_wt = d.get("weight", 1)
157
+ ... return node_u_wt / 2 + node_v_wt / 2 + edge_wt
158
+
159
+ In this example we take the average of start and end node
160
+ weights of an edge and add it to the weight of the edge.
161
+
162
+ The function :func:`single_source_dijkstra` computes both
163
+ path and length-of-path if you need both, use that.
164
+
165
+ See Also
166
+ --------
167
+ bidirectional_dijkstra
168
+ bellman_ford_path
169
+ single_source_dijkstra
170
+ """
171
+ (length, path) = single_source_dijkstra(G, source, target=target, weight=weight)
172
+ return path
173
+
174
+
175
+ @nx._dispatchable(edge_attrs="weight")
176
+ def dijkstra_path_length(G, source, target, weight="weight"):
177
+ """Returns the shortest weighted path length in G from source to target.
178
+
179
+ Uses Dijkstra's Method to compute the shortest weighted path length
180
+ between two nodes in a graph.
181
+
182
+ Parameters
183
+ ----------
184
+ G : NetworkX graph
185
+
186
+ source : node label
187
+ starting node for path
188
+
189
+ target : node label
190
+ ending node for path
191
+
192
+ weight : string or function
193
+ If this is a string, then edge weights will be accessed via the
194
+ edge attribute with this key (that is, the weight of the edge
195
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
196
+ such edge attribute exists, the weight of the edge is assumed to
197
+ be one.
198
+
199
+ If this is a function, the weight of an edge is the value
200
+ returned by the function. The function must accept exactly three
201
+ positional arguments: the two endpoints of an edge and the
202
+ dictionary of edge attributes for that edge. The function must
203
+ return a number or None to indicate a hidden edge.
204
+
205
+ Returns
206
+ -------
207
+ length : number
208
+ Shortest path length.
209
+
210
+ Raises
211
+ ------
212
+ NodeNotFound
213
+ If `source` is not in `G`.
214
+
215
+ NetworkXNoPath
216
+ If no path exists between source and target.
217
+
218
+ Examples
219
+ --------
220
+ >>> G = nx.path_graph(5)
221
+ >>> nx.dijkstra_path_length(G, 0, 4)
222
+ 4
223
+
224
+ Notes
225
+ -----
226
+ Edge weight attributes must be numerical.
227
+ Distances are calculated as sums of weighted edges traversed.
228
+
229
+ The weight function can be used to hide edges by returning None.
230
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
231
+ will find the shortest red path.
232
+
233
+ The function :func:`single_source_dijkstra` computes both
234
+ path and length-of-path if you need both, use that.
235
+
236
+ See Also
237
+ --------
238
+ bidirectional_dijkstra
239
+ bellman_ford_path_length
240
+ single_source_dijkstra
241
+
242
+ """
243
+ if source not in G:
244
+ raise nx.NodeNotFound(f"Node {source} not found in graph")
245
+ if source == target:
246
+ return 0
247
+ weight = _weight_function(G, weight)
248
+ length = _dijkstra(G, source, weight, target=target)
249
+ try:
250
+ return length[target]
251
+ except KeyError as err:
252
+ raise nx.NetworkXNoPath(f"Node {target} not reachable from {source}") from err
253
+
254
+
255
+ @nx._dispatchable(edge_attrs="weight")
256
+ def single_source_dijkstra_path(G, source, cutoff=None, weight="weight"):
257
+ """Find shortest weighted paths in G from a source node.
258
+
259
+ Compute shortest path between source and all other reachable
260
+ nodes for a weighted graph.
261
+
262
+ Parameters
263
+ ----------
264
+ G : NetworkX graph
265
+
266
+ source : node
267
+ Starting node for path.
268
+
269
+ cutoff : integer or float, optional
270
+ Length (sum of edge weights) at which the search is stopped.
271
+ If cutoff is provided, only return paths with summed weight <= cutoff.
272
+
273
+ weight : string or function
274
+ If this is a string, then edge weights will be accessed via the
275
+ edge attribute with this key (that is, the weight of the edge
276
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
277
+ such edge attribute exists, the weight of the edge is assumed to
278
+ be one.
279
+
280
+ If this is a function, the weight of an edge is the value
281
+ returned by the function. The function must accept exactly three
282
+ positional arguments: the two endpoints of an edge and the
283
+ dictionary of edge attributes for that edge. The function must
284
+ return a number or None to indicate a hidden edge.
285
+
286
+ Returns
287
+ -------
288
+ paths : dictionary
289
+ Dictionary of shortest path lengths keyed by target.
290
+
291
+ Raises
292
+ ------
293
+ NodeNotFound
294
+ If `source` is not in `G`.
295
+
296
+ Examples
297
+ --------
298
+ >>> G = nx.path_graph(5)
299
+ >>> path = nx.single_source_dijkstra_path(G, 0)
300
+ >>> path[4]
301
+ [0, 1, 2, 3, 4]
302
+
303
+ Notes
304
+ -----
305
+ Edge weight attributes must be numerical.
306
+ Distances are calculated as sums of weighted edges traversed.
307
+
308
+ The weight function can be used to hide edges by returning None.
309
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
310
+ will find the shortest red path.
311
+
312
+ See Also
313
+ --------
314
+ single_source_dijkstra, single_source_bellman_ford
315
+
316
+ """
317
+ return multi_source_dijkstra_path(G, {source}, cutoff=cutoff, weight=weight)
318
+
319
+
320
+ @nx._dispatchable(edge_attrs="weight")
321
+ def single_source_dijkstra_path_length(G, source, cutoff=None, weight="weight"):
322
+ """Find shortest weighted path lengths in G from a source node.
323
+
324
+ Compute the shortest path length between source and all other
325
+ reachable nodes for a weighted graph.
326
+
327
+ Parameters
328
+ ----------
329
+ G : NetworkX graph
330
+
331
+ source : node label
332
+ Starting node for path
333
+
334
+ cutoff : integer or float, optional
335
+ Length (sum of edge weights) at which the search is stopped.
336
+ If cutoff is provided, only return paths with summed weight <= cutoff.
337
+
338
+ weight : string or function
339
+ If this is a string, then edge weights will be accessed via the
340
+ edge attribute with this key (that is, the weight of the edge
341
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
342
+ such edge attribute exists, the weight of the edge is assumed to
343
+ be one.
344
+
345
+ If this is a function, the weight of an edge is the value
346
+ returned by the function. The function must accept exactly three
347
+ positional arguments: the two endpoints of an edge and the
348
+ dictionary of edge attributes for that edge. The function must
349
+ return a number or None to indicate a hidden edge.
350
+
351
+ Returns
352
+ -------
353
+ length : dict
354
+ Dict keyed by node to shortest path length from source.
355
+
356
+ Raises
357
+ ------
358
+ NodeNotFound
359
+ If `source` is not in `G`.
360
+
361
+ Examples
362
+ --------
363
+ >>> G = nx.path_graph(5)
364
+ >>> length = nx.single_source_dijkstra_path_length(G, 0)
365
+ >>> length[4]
366
+ 4
367
+ >>> for node in [0, 1, 2, 3, 4]:
368
+ ... print(f"{node}: {length[node]}")
369
+ 0: 0
370
+ 1: 1
371
+ 2: 2
372
+ 3: 3
373
+ 4: 4
374
+
375
+ Notes
376
+ -----
377
+ Edge weight attributes must be numerical.
378
+ Distances are calculated as sums of weighted edges traversed.
379
+
380
+ The weight function can be used to hide edges by returning None.
381
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
382
+ will find the shortest red path.
383
+
384
+ See Also
385
+ --------
386
+ single_source_dijkstra, single_source_bellman_ford_path_length
387
+
388
+ """
389
+ return multi_source_dijkstra_path_length(G, {source}, cutoff=cutoff, weight=weight)
390
+
391
+
392
+ @nx._dispatchable(edge_attrs="weight")
393
+ def single_source_dijkstra(G, source, target=None, cutoff=None, weight="weight"):
394
+ """Find shortest weighted paths and lengths from a source node.
395
+
396
+ Compute the shortest path length between source and all other
397
+ reachable nodes for a weighted graph.
398
+
399
+ Uses Dijkstra's algorithm to compute shortest paths and lengths
400
+ between a source and all other reachable nodes in a weighted graph.
401
+
402
+ Parameters
403
+ ----------
404
+ G : NetworkX graph
405
+
406
+ source : node label
407
+ Starting node for path
408
+
409
+ target : node label, optional
410
+ Ending node for path
411
+
412
+ cutoff : integer or float, optional
413
+ Length (sum of edge weights) at which the search is stopped.
414
+ If cutoff is provided, only return paths with summed weight <= cutoff.
415
+
416
+
417
+ weight : string or function
418
+ If this is a string, then edge weights will be accessed via the
419
+ edge attribute with this key (that is, the weight of the edge
420
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
421
+ such edge attribute exists, the weight of the edge is assumed to
422
+ be one.
423
+
424
+ If this is a function, the weight of an edge is the value
425
+ returned by the function. The function must accept exactly three
426
+ positional arguments: the two endpoints of an edge and the
427
+ dictionary of edge attributes for that edge. The function must
428
+ return a number or None to indicate a hidden edge.
429
+
430
+ Returns
431
+ -------
432
+ distance, path : pair of dictionaries, or numeric and list.
433
+ If target is None, paths and lengths to all nodes are computed.
434
+ The return value is a tuple of two dictionaries keyed by target nodes.
435
+ The first dictionary stores distance to each target node.
436
+ The second stores the path to each target node.
437
+ If target is not None, returns a tuple (distance, path), where
438
+ distance is the distance from source to target and path is a list
439
+ representing the path from source to target.
440
+
441
+ Raises
442
+ ------
443
+ NodeNotFound
444
+ If `source` is not in `G`.
445
+
446
+ Examples
447
+ --------
448
+ >>> G = nx.path_graph(5)
449
+ >>> length, path = nx.single_source_dijkstra(G, 0)
450
+ >>> length[4]
451
+ 4
452
+ >>> for node in [0, 1, 2, 3, 4]:
453
+ ... print(f"{node}: {length[node]}")
454
+ 0: 0
455
+ 1: 1
456
+ 2: 2
457
+ 3: 3
458
+ 4: 4
459
+ >>> path[4]
460
+ [0, 1, 2, 3, 4]
461
+ >>> length, path = nx.single_source_dijkstra(G, 0, 1)
462
+ >>> length
463
+ 1
464
+ >>> path
465
+ [0, 1]
466
+
467
+ Notes
468
+ -----
469
+ Edge weight attributes must be numerical.
470
+ Distances are calculated as sums of weighted edges traversed.
471
+
472
+ The weight function can be used to hide edges by returning None.
473
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
474
+ will find the shortest red path.
475
+
476
+ Based on the Python cookbook recipe (119466) at
477
+ https://code.activestate.com/recipes/119466/
478
+
479
+ This algorithm is not guaranteed to work if edge weights
480
+ are negative or are floating point numbers
481
+ (overflows and roundoff errors can cause problems).
482
+
483
+ See Also
484
+ --------
485
+ single_source_dijkstra_path
486
+ single_source_dijkstra_path_length
487
+ single_source_bellman_ford
488
+ """
489
+ return multi_source_dijkstra(
490
+ G, {source}, cutoff=cutoff, target=target, weight=weight
491
+ )
492
+
493
+
494
+ @nx._dispatchable(edge_attrs="weight")
495
+ def multi_source_dijkstra_path(G, sources, cutoff=None, weight="weight"):
496
+ """Find shortest weighted paths in G from a given set of source
497
+ nodes.
498
+
499
+ Compute shortest path between any of the source nodes and all other
500
+ reachable nodes for a weighted graph.
501
+
502
+ Parameters
503
+ ----------
504
+ G : NetworkX graph
505
+
506
+ sources : non-empty set of nodes
507
+ Starting nodes for paths. If this is just a set containing a
508
+ single node, then all paths computed by this function will start
509
+ from that node. If there are two or more nodes in the set, the
510
+ computed paths may begin from any one of the start nodes.
511
+
512
+ cutoff : integer or float, optional
513
+ Length (sum of edge weights) at which the search is stopped.
514
+ If cutoff is provided, only return paths with summed weight <= cutoff.
515
+
516
+ weight : string or function
517
+ If this is a string, then edge weights will be accessed via the
518
+ edge attribute with this key (that is, the weight of the edge
519
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
520
+ such edge attribute exists, the weight of the edge is assumed to
521
+ be one.
522
+
523
+ If this is a function, the weight of an edge is the value
524
+ returned by the function. The function must accept exactly three
525
+ positional arguments: the two endpoints of an edge and the
526
+ dictionary of edge attributes for that edge. The function must
527
+ return a number or None to indicate a hidden edge.
528
+
529
+ Returns
530
+ -------
531
+ paths : dictionary
532
+ Dictionary of shortest paths keyed by target.
533
+
534
+ Examples
535
+ --------
536
+ >>> G = nx.path_graph(5)
537
+ >>> path = nx.multi_source_dijkstra_path(G, {0, 4})
538
+ >>> path[1]
539
+ [0, 1]
540
+ >>> path[3]
541
+ [4, 3]
542
+
543
+ Notes
544
+ -----
545
+ Edge weight attributes must be numerical.
546
+ Distances are calculated as sums of weighted edges traversed.
547
+
548
+ The weight function can be used to hide edges by returning None.
549
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
550
+ will find the shortest red path.
551
+
552
+ Raises
553
+ ------
554
+ ValueError
555
+ If `sources` is empty.
556
+ NodeNotFound
557
+ If any of `sources` is not in `G`.
558
+
559
+ See Also
560
+ --------
561
+ multi_source_dijkstra, multi_source_bellman_ford
562
+
563
+ """
564
+ length, path = multi_source_dijkstra(G, sources, cutoff=cutoff, weight=weight)
565
+ return path
566
+
567
+
568
+ @nx._dispatchable(edge_attrs="weight")
569
+ def multi_source_dijkstra_path_length(G, sources, cutoff=None, weight="weight"):
570
+ """Find shortest weighted path lengths in G from a given set of
571
+ source nodes.
572
+
573
+ Compute the shortest path length between any of the source nodes and
574
+ all other reachable nodes for a weighted graph.
575
+
576
+ Parameters
577
+ ----------
578
+ G : NetworkX graph
579
+
580
+ sources : non-empty set of nodes
581
+ Starting nodes for paths. If this is just a set containing a
582
+ single node, then all paths computed by this function will start
583
+ from that node. If there are two or more nodes in the set, the
584
+ computed paths may begin from any one of the start nodes.
585
+
586
+ cutoff : integer or float, optional
587
+ Length (sum of edge weights) at which the search is stopped.
588
+ If cutoff is provided, only return paths with summed weight <= cutoff.
589
+
590
+ weight : string or function
591
+ If this is a string, then edge weights will be accessed via the
592
+ edge attribute with this key (that is, the weight of the edge
593
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
594
+ such edge attribute exists, the weight of the edge is assumed to
595
+ be one.
596
+
597
+ If this is a function, the weight of an edge is the value
598
+ returned by the function. The function must accept exactly three
599
+ positional arguments: the two endpoints of an edge and the
600
+ dictionary of edge attributes for that edge. The function must
601
+ return a number or None to indicate a hidden edge.
602
+
603
+ Returns
604
+ -------
605
+ length : dict
606
+ Dict keyed by node to shortest path length to nearest source.
607
+
608
+ Examples
609
+ --------
610
+ >>> G = nx.path_graph(5)
611
+ >>> length = nx.multi_source_dijkstra_path_length(G, {0, 4})
612
+ >>> for node in [0, 1, 2, 3, 4]:
613
+ ... print(f"{node}: {length[node]}")
614
+ 0: 0
615
+ 1: 1
616
+ 2: 2
617
+ 3: 1
618
+ 4: 0
619
+
620
+ Notes
621
+ -----
622
+ Edge weight attributes must be numerical.
623
+ Distances are calculated as sums of weighted edges traversed.
624
+
625
+ The weight function can be used to hide edges by returning None.
626
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
627
+ will find the shortest red path.
628
+
629
+ Raises
630
+ ------
631
+ ValueError
632
+ If `sources` is empty.
633
+ NodeNotFound
634
+ If any of `sources` is not in `G`.
635
+
636
+ See Also
637
+ --------
638
+ multi_source_dijkstra
639
+
640
+ """
641
+ if not sources:
642
+ raise ValueError("sources must not be empty")
643
+ for s in sources:
644
+ if s not in G:
645
+ raise nx.NodeNotFound(f"Node {s} not found in graph")
646
+ weight = _weight_function(G, weight)
647
+ return _dijkstra_multisource(G, sources, weight, cutoff=cutoff)
648
+
649
+
650
+ @nx._dispatchable(edge_attrs="weight")
651
+ def multi_source_dijkstra(G, sources, target=None, cutoff=None, weight="weight"):
652
+ """Find shortest weighted paths and lengths from a given set of
653
+ source nodes.
654
+
655
+ Uses Dijkstra's algorithm to compute the shortest paths and lengths
656
+ between one of the source nodes and the given `target`, or all other
657
+ reachable nodes if not specified, for a weighted graph.
658
+
659
+ Parameters
660
+ ----------
661
+ G : NetworkX graph
662
+
663
+ sources : non-empty set of nodes
664
+ Starting nodes for paths. If this is just a set containing a
665
+ single node, then all paths computed by this function will start
666
+ from that node. If there are two or more nodes in the set, the
667
+ computed paths may begin from any one of the start nodes.
668
+
669
+ target : node label, optional
670
+ Ending node for path
671
+
672
+ cutoff : integer or float, optional
673
+ Length (sum of edge weights) at which the search is stopped.
674
+ If cutoff is provided, only return paths with summed weight <= cutoff.
675
+
676
+ weight : string or function
677
+ If this is a string, then edge weights will be accessed via the
678
+ edge attribute with this key (that is, the weight of the edge
679
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
680
+ such edge attribute exists, the weight of the edge is assumed to
681
+ be one.
682
+
683
+ If this is a function, the weight of an edge is the value
684
+ returned by the function. The function must accept exactly three
685
+ positional arguments: the two endpoints of an edge and the
686
+ dictionary of edge attributes for that edge. The function must
687
+ return a number or None to indicate a hidden edge.
688
+
689
+ Returns
690
+ -------
691
+ distance, path : pair of dictionaries, or numeric and list
692
+ If target is None, returns a tuple of two dictionaries keyed by node.
693
+ The first dictionary stores distance from one of the source nodes.
694
+ The second stores the path from one of the sources to that node.
695
+ If target is not None, returns a tuple of (distance, path) where
696
+ distance is the distance from source to target and path is a list
697
+ representing the path from source to target.
698
+
699
+ Examples
700
+ --------
701
+ >>> G = nx.path_graph(5)
702
+ >>> length, path = nx.multi_source_dijkstra(G, {0, 4})
703
+ >>> for node in [0, 1, 2, 3, 4]:
704
+ ... print(f"{node}: {length[node]}")
705
+ 0: 0
706
+ 1: 1
707
+ 2: 2
708
+ 3: 1
709
+ 4: 0
710
+ >>> path[1]
711
+ [0, 1]
712
+ >>> path[3]
713
+ [4, 3]
714
+
715
+ >>> length, path = nx.multi_source_dijkstra(G, {0, 4}, 1)
716
+ >>> length
717
+ 1
718
+ >>> path
719
+ [0, 1]
720
+
721
+ Notes
722
+ -----
723
+ Edge weight attributes must be numerical.
724
+ Distances are calculated as sums of weighted edges traversed.
725
+
726
+ The weight function can be used to hide edges by returning None.
727
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
728
+ will find the shortest red path.
729
+
730
+ Based on the Python cookbook recipe (119466) at
731
+ https://code.activestate.com/recipes/119466/
732
+
733
+ This algorithm is not guaranteed to work if edge weights
734
+ are negative or are floating point numbers
735
+ (overflows and roundoff errors can cause problems).
736
+
737
+ Raises
738
+ ------
739
+ ValueError
740
+ If `sources` is empty.
741
+ NodeNotFound
742
+ If any of `sources` is not in `G`.
743
+
744
+ See Also
745
+ --------
746
+ multi_source_dijkstra_path
747
+ multi_source_dijkstra_path_length
748
+
749
+ """
750
+ if not sources:
751
+ raise ValueError("sources must not be empty")
752
+ for s in sources:
753
+ if s not in G:
754
+ raise nx.NodeNotFound(f"Node {s} not found in graph")
755
+ if target in sources:
756
+ return (0, [target])
757
+ weight = _weight_function(G, weight)
758
+ paths = {source: [source] for source in sources} # dictionary of paths
759
+ dist = _dijkstra_multisource(
760
+ G, sources, weight, paths=paths, cutoff=cutoff, target=target
761
+ )
762
+ if target is None:
763
+ return (dist, paths)
764
+ try:
765
+ return (dist[target], paths[target])
766
+ except KeyError as err:
767
+ raise nx.NetworkXNoPath(f"No path to {target}.") from err
768
+
769
+
770
+ def _dijkstra(G, source, weight, pred=None, paths=None, cutoff=None, target=None):
771
+ """Uses Dijkstra's algorithm to find shortest weighted paths from a
772
+ single source.
773
+
774
+ This is a convenience function for :func:`_dijkstra_multisource`
775
+ with all the arguments the same, except the keyword argument
776
+ `sources` set to ``[source]``.
777
+
778
+ """
779
+ return _dijkstra_multisource(
780
+ G, [source], weight, pred=pred, paths=paths, cutoff=cutoff, target=target
781
+ )
782
+
783
+
784
+ def _dijkstra_multisource(
785
+ G, sources, weight, pred=None, paths=None, cutoff=None, target=None
786
+ ):
787
+ """Uses Dijkstra's algorithm to find shortest weighted paths
788
+
789
+ Parameters
790
+ ----------
791
+ G : NetworkX graph
792
+
793
+ sources : non-empty iterable of nodes
794
+ Starting nodes for paths. If this is just an iterable containing
795
+ a single node, then all paths computed by this function will
796
+ start from that node. If there are two or more nodes in this
797
+ iterable, the computed paths may begin from any one of the start
798
+ nodes.
799
+
800
+ weight: function
801
+ Function with (u, v, data) input that returns that edge's weight
802
+ or None to indicate a hidden edge
803
+
804
+ pred: dict of lists, optional(default=None)
805
+ dict to store a list of predecessors keyed by that node
806
+ If None, predecessors are not stored.
807
+
808
+ paths: dict, optional (default=None)
809
+ dict to store the path list from source to each node, keyed by node.
810
+ If None, paths are not stored.
811
+
812
+ target : node label, optional
813
+ Ending node for path. Search is halted when target is found.
814
+
815
+ cutoff : integer or float, optional
816
+ Length (sum of edge weights) at which the search is stopped.
817
+ If cutoff is provided, only return paths with summed weight <= cutoff.
818
+
819
+ Returns
820
+ -------
821
+ distance : dictionary
822
+ A mapping from node to shortest distance to that node from one
823
+ of the source nodes.
824
+
825
+ Raises
826
+ ------
827
+ NodeNotFound
828
+ If any of `sources` is not in `G`.
829
+
830
+ Notes
831
+ -----
832
+ The optional predecessor and path dictionaries can be accessed by
833
+ the caller through the original pred and paths objects passed
834
+ as arguments. No need to explicitly return pred or paths.
835
+
836
+ """
837
+ # If `paths` is specified, we use a temporary internal dictionary (`pred_dict`) to
838
+ # store predecessors, used to reconstruct paths. However, if the caller
839
+ # passed in a `pred` dictionary, we must compute *all* predecessors, since the caller
840
+ # expects the full predecessor structure.
841
+ pred_dict = pred if paths is None or pred is not None else {}
842
+
843
+ G_succ = G._adj # For speed-up (and works for both directed and undirected graphs)
844
+
845
+ dist = {} # dictionary of final distances
846
+ seen = {}
847
+ # fringe is heapq with 3-tuples (distance,c,node)
848
+ # use the count c to avoid comparing nodes (may not be able to)
849
+ c = count()
850
+ fringe = []
851
+ for source in sources:
852
+ seen[source] = 0
853
+ heappush(fringe, (0, next(c), source))
854
+ number_of_sources = len(seen)
855
+ while fringe:
856
+ (dist_v, _, v) = heappop(fringe)
857
+ if v in dist:
858
+ continue # already searched this node.
859
+ dist[v] = dist_v
860
+ if v == target:
861
+ break
862
+ for u, e in G_succ[v].items():
863
+ cost = weight(v, u, e)
864
+ if cost is None:
865
+ continue
866
+ vu_dist = dist_v + cost
867
+ if cutoff is not None and vu_dist > cutoff:
868
+ continue
869
+ if u in dist:
870
+ u_dist = dist[u]
871
+ if vu_dist < u_dist:
872
+ raise ValueError("Contradictory paths found:", "negative weights?")
873
+ elif pred is not None and vu_dist == u_dist:
874
+ # Found another shortest path to u with equal distance (including zero-weight edges).
875
+ # We must store *all* predecessors because `pred` was provided by the caller.
876
+ pred_dict[u].append(v)
877
+ elif u not in seen or vu_dist < seen[u]:
878
+ seen[u] = vu_dist
879
+ heappush(fringe, (vu_dist, next(c), u))
880
+ if pred_dict is not None:
881
+ pred_dict[u] = [v]
882
+ elif pred is not None and vu_dist == seen[u]:
883
+ # Found another shortest path to u
884
+ # We must store *all* predecessors because `pred` was provided by the caller.
885
+ pred_dict[u].append(v)
886
+
887
+ if paths is not None:
888
+ # Reconstruct the path from source to target using the predecessor dictionary.
889
+ if target is None:
890
+ # Since `dist` is in increasing distance order, each predecessor's path is
891
+ # already computed by the time we process `v`. We skip the first
892
+ # `number_of_sources` entries because sources already have their paths defined.
893
+ for v in islice(dist, number_of_sources, None):
894
+ # `v` must be in `pred_dict`: any node with a distance (and not a source)
895
+ # has a predecessor.
896
+ paths[v] = paths[pred_dict[v][0]] + [v]
897
+ else:
898
+ # Caller requested the path to a specific target node.
899
+ path = paths[target] = [target]
900
+ while (current_preds := pred_dict.get(path[-1])) is not None:
901
+ path.append(current_preds[0])
902
+ # The path was built in reverse order, so reverse it at the end.
903
+ path.reverse()
904
+
905
+ # The optional predecessor and path dictionaries can be accessed
906
+ # by the caller via the pred and paths objects passed as arguments.
907
+ return dist
908
+
909
+
910
+ @nx._dispatchable(edge_attrs="weight")
911
+ def dijkstra_predecessor_and_distance(G, source, cutoff=None, weight="weight"):
912
+ """Compute weighted shortest path length and predecessors.
913
+
914
+ Uses Dijkstra's Method to obtain the shortest weighted paths
915
+ and return dictionaries of predecessors for each node and
916
+ distance for each node from the `source`.
917
+
918
+ Parameters
919
+ ----------
920
+ G : NetworkX graph
921
+
922
+ source : node label
923
+ Starting node for path
924
+
925
+ cutoff : integer or float, optional
926
+ Length (sum of edge weights) at which the search is stopped.
927
+ If cutoff is provided, only return paths with summed weight <= cutoff.
928
+
929
+ weight : string or function
930
+ If this is a string, then edge weights will be accessed via the
931
+ edge attribute with this key (that is, the weight of the edge
932
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
933
+ such edge attribute exists, the weight of the edge is assumed to
934
+ be one.
935
+
936
+ If this is a function, the weight of an edge is the value
937
+ returned by the function. The function must accept exactly three
938
+ positional arguments: the two endpoints of an edge and the
939
+ dictionary of edge attributes for that edge. The function must
940
+ return a number or None to indicate a hidden edge.
941
+
942
+ Returns
943
+ -------
944
+ pred, distance : dictionaries
945
+ Returns two dictionaries representing a list of predecessors
946
+ of a node and the distance to each node.
947
+
948
+ Raises
949
+ ------
950
+ NodeNotFound
951
+ If `source` is not in `G`.
952
+
953
+ Notes
954
+ -----
955
+ Edge weight attributes must be numerical.
956
+ Distances are calculated as sums of weighted edges traversed.
957
+
958
+ The list of predecessors contains more than one element only when
959
+ there are more than one shortest paths to the key node.
960
+
961
+ Examples
962
+ --------
963
+ >>> G = nx.path_graph(5, create_using=nx.DiGraph())
964
+ >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0)
965
+ >>> sorted(pred.items())
966
+ [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])]
967
+ >>> sorted(dist.items())
968
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
969
+
970
+ >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0, 1)
971
+ >>> sorted(pred.items())
972
+ [(0, []), (1, [0])]
973
+ >>> sorted(dist.items())
974
+ [(0, 0), (1, 1)]
975
+ """
976
+ if source not in G:
977
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
978
+ weight = _weight_function(G, weight)
979
+ pred = {source: []} # dictionary of predecessors
980
+ return (pred, _dijkstra(G, source, weight, pred=pred, cutoff=cutoff))
981
+
982
+
983
+ @nx._dispatchable(edge_attrs="weight")
984
+ def all_pairs_dijkstra(G, cutoff=None, weight="weight"):
985
+ """Find shortest weighted paths and lengths between all nodes.
986
+
987
+ Parameters
988
+ ----------
989
+ G : NetworkX graph
990
+
991
+ cutoff : integer or float, optional
992
+ Length (sum of edge weights) at which the search is stopped.
993
+ If cutoff is provided, only return paths with summed weight <= cutoff.
994
+
995
+ weight : string or function
996
+ If this is a string, then edge weights will be accessed via the
997
+ edge attribute with this key (that is, the weight of the edge
998
+ joining `u` to `v` will be ``G.edge[u][v][weight]``). If no
999
+ such edge attribute exists, the weight of the edge is assumed to
1000
+ be one.
1001
+
1002
+ If this is a function, the weight of an edge is the value
1003
+ returned by the function. The function must accept exactly three
1004
+ positional arguments: the two endpoints of an edge and the
1005
+ dictionary of edge attributes for that edge. The function must
1006
+ return a number or None to indicate a hidden edge.
1007
+
1008
+ Yields
1009
+ ------
1010
+ (node, (distance, path)) : (node obj, (dict, dict))
1011
+ Each source node has two associated dicts. The first holds distance
1012
+ keyed by target and the second holds paths keyed by target.
1013
+ (See single_source_dijkstra for the source/target node terminology.)
1014
+ If desired you can apply `dict()` to this function to create a dict
1015
+ keyed by source node to the two dicts.
1016
+
1017
+ Examples
1018
+ --------
1019
+ >>> G = nx.path_graph(5)
1020
+ >>> len_path = dict(nx.all_pairs_dijkstra(G))
1021
+ >>> len_path[3][0][1]
1022
+ 2
1023
+ >>> for node in [0, 1, 2, 3, 4]:
1024
+ ... print(f"3 - {node}: {len_path[3][0][node]}")
1025
+ 3 - 0: 3
1026
+ 3 - 1: 2
1027
+ 3 - 2: 1
1028
+ 3 - 3: 0
1029
+ 3 - 4: 1
1030
+ >>> len_path[3][1][1]
1031
+ [3, 2, 1]
1032
+ >>> for n, (dist, path) in nx.all_pairs_dijkstra(G):
1033
+ ... print(path[1])
1034
+ [0, 1]
1035
+ [1]
1036
+ [2, 1]
1037
+ [3, 2, 1]
1038
+ [4, 3, 2, 1]
1039
+
1040
+ Notes
1041
+ -----
1042
+ Edge weight attributes must be numerical.
1043
+ Distances are calculated as sums of weighted edges traversed.
1044
+
1045
+ The yielded dicts only have keys for reachable nodes.
1046
+ """
1047
+ for n in G:
1048
+ dist, path = single_source_dijkstra(G, n, cutoff=cutoff, weight=weight)
1049
+ yield (n, (dist, path))
1050
+
1051
+
1052
+ @nx._dispatchable(edge_attrs="weight")
1053
+ def all_pairs_dijkstra_path_length(G, cutoff=None, weight="weight"):
1054
+ """Compute shortest path lengths between all nodes in a weighted graph.
1055
+
1056
+ Parameters
1057
+ ----------
1058
+ G : NetworkX graph
1059
+
1060
+ cutoff : integer or float, optional
1061
+ Length (sum of edge weights) at which the search is stopped.
1062
+ If cutoff is provided, only return paths with summed weight <= cutoff.
1063
+
1064
+ weight : string or function
1065
+ If this is a string, then edge weights will be accessed via the
1066
+ edge attribute with this key (that is, the weight of the edge
1067
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1068
+ such edge attribute exists, the weight of the edge is assumed to
1069
+ be one.
1070
+
1071
+ If this is a function, the weight of an edge is the value
1072
+ returned by the function. The function must accept exactly three
1073
+ positional arguments: the two endpoints of an edge and the
1074
+ dictionary of edge attributes for that edge. The function must
1075
+ return a number or None to indicate a hidden edge.
1076
+
1077
+ Returns
1078
+ -------
1079
+ distance : iterator
1080
+ (source, dictionary) iterator with dictionary keyed by target and
1081
+ shortest path length as the key value.
1082
+
1083
+ Examples
1084
+ --------
1085
+ >>> G = nx.path_graph(5)
1086
+ >>> length = dict(nx.all_pairs_dijkstra_path_length(G))
1087
+ >>> for node in [0, 1, 2, 3, 4]:
1088
+ ... print(f"1 - {node}: {length[1][node]}")
1089
+ 1 - 0: 1
1090
+ 1 - 1: 0
1091
+ 1 - 2: 1
1092
+ 1 - 3: 2
1093
+ 1 - 4: 3
1094
+ >>> length[3][2]
1095
+ 1
1096
+ >>> length[2][2]
1097
+ 0
1098
+
1099
+ Notes
1100
+ -----
1101
+ Edge weight attributes must be numerical.
1102
+ Distances are calculated as sums of weighted edges traversed.
1103
+
1104
+ The dictionary returned only has keys for reachable node pairs.
1105
+ """
1106
+ length = single_source_dijkstra_path_length
1107
+ for n in G:
1108
+ yield (n, length(G, n, cutoff=cutoff, weight=weight))
1109
+
1110
+
1111
+ @nx._dispatchable(edge_attrs="weight")
1112
+ def all_pairs_dijkstra_path(G, cutoff=None, weight="weight"):
1113
+ """Compute shortest paths between all nodes in a weighted graph.
1114
+
1115
+ Parameters
1116
+ ----------
1117
+ G : NetworkX graph
1118
+
1119
+ cutoff : integer or float, optional
1120
+ Length (sum of edge weights) at which the search is stopped.
1121
+ If cutoff is provided, only return paths with summed weight <= cutoff.
1122
+
1123
+ weight : string or function
1124
+ If this is a string, then edge weights will be accessed via the
1125
+ edge attribute with this key (that is, the weight of the edge
1126
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1127
+ such edge attribute exists, the weight of the edge is assumed to
1128
+ be one.
1129
+
1130
+ If this is a function, the weight of an edge is the value
1131
+ returned by the function. The function must accept exactly three
1132
+ positional arguments: the two endpoints of an edge and the
1133
+ dictionary of edge attributes for that edge. The function must
1134
+ return a number or None to indicate a hidden edge.
1135
+
1136
+ Returns
1137
+ -------
1138
+ paths : iterator
1139
+ (source, dictionary) iterator with dictionary keyed by target and
1140
+ shortest path as the key value.
1141
+
1142
+ Examples
1143
+ --------
1144
+ >>> G = nx.path_graph(5)
1145
+ >>> path = dict(nx.all_pairs_dijkstra_path(G))
1146
+ >>> path[0][4]
1147
+ [0, 1, 2, 3, 4]
1148
+
1149
+ Notes
1150
+ -----
1151
+ Edge weight attributes must be numerical.
1152
+ Distances are calculated as sums of weighted edges traversed.
1153
+
1154
+ See Also
1155
+ --------
1156
+ floyd_warshall, all_pairs_bellman_ford_path
1157
+
1158
+ """
1159
+ path = single_source_dijkstra_path
1160
+ # TODO This can be trivially parallelized.
1161
+ for n in G:
1162
+ yield (n, path(G, n, cutoff=cutoff, weight=weight))
1163
+
1164
+
1165
+ @nx._dispatchable(edge_attrs="weight")
1166
+ def bellman_ford_predecessor_and_distance(
1167
+ G, source, target=None, weight="weight", heuristic=False
1168
+ ):
1169
+ """Compute shortest path lengths and predecessors on shortest paths
1170
+ in weighted graphs.
1171
+
1172
+ The algorithm has a running time of $O(mn)$ where $n$ is the number of
1173
+ nodes and $m$ is the number of edges. It is slower than Dijkstra but
1174
+ can handle negative edge weights.
1175
+
1176
+ If a negative cycle is detected, you can use :func:`find_negative_cycle`
1177
+ to return the cycle and examine it. Shortest paths are not defined when
1178
+ a negative cycle exists because once reached, the path can cycle forever
1179
+ to build up arbitrarily low weights.
1180
+
1181
+ Parameters
1182
+ ----------
1183
+ G : NetworkX graph
1184
+ The algorithm works for all types of graphs, including directed
1185
+ graphs and multigraphs.
1186
+
1187
+ source: node label
1188
+ Starting node for path
1189
+
1190
+ target : node label, optional
1191
+ Ending node for path
1192
+
1193
+ weight : string or function
1194
+ If this is a string, then edge weights will be accessed via the
1195
+ edge attribute with this key (that is, the weight of the edge
1196
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1197
+ such edge attribute exists, the weight of the edge is assumed to
1198
+ be one.
1199
+
1200
+ If this is a function, the weight of an edge is the value
1201
+ returned by the function. The function must accept exactly three
1202
+ positional arguments: the two endpoints of an edge and the
1203
+ dictionary of edge attributes for that edge. The function must
1204
+ return a number.
1205
+
1206
+ heuristic : bool
1207
+ Determines whether to use a heuristic to early detect negative
1208
+ cycles at a hopefully negligible cost.
1209
+
1210
+ Returns
1211
+ -------
1212
+ pred, dist : dictionaries
1213
+ Returns two dictionaries keyed by node to predecessor in the
1214
+ path and to the distance from the source respectively.
1215
+
1216
+ Raises
1217
+ ------
1218
+ NodeNotFound
1219
+ If `source` is not in `G`.
1220
+
1221
+ NetworkXUnbounded
1222
+ If the (di)graph contains a negative (di)cycle, the
1223
+ algorithm raises an exception to indicate the presence of the
1224
+ negative (di)cycle. Note: any negative weight edge in an
1225
+ undirected graph is a negative cycle.
1226
+
1227
+ Examples
1228
+ --------
1229
+ >>> G = nx.path_graph(5, create_using=nx.DiGraph())
1230
+ >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0)
1231
+ >>> sorted(pred.items())
1232
+ [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])]
1233
+ >>> sorted(dist.items())
1234
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
1235
+
1236
+ >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0, 1)
1237
+ >>> sorted(pred.items())
1238
+ [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])]
1239
+ >>> sorted(dist.items())
1240
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
1241
+
1242
+ >>> G = nx.cycle_graph(5, create_using=nx.DiGraph())
1243
+ >>> G[1][2]["weight"] = -7
1244
+ >>> nx.bellman_ford_predecessor_and_distance(G, 0)
1245
+ Traceback (most recent call last):
1246
+ ...
1247
+ networkx.exception.NetworkXUnbounded: Negative cycle detected.
1248
+
1249
+ See Also
1250
+ --------
1251
+ find_negative_cycle
1252
+
1253
+ Notes
1254
+ -----
1255
+ Edge weight attributes must be numerical.
1256
+ Distances are calculated as sums of weighted edges traversed.
1257
+
1258
+ The dictionaries returned only have keys for nodes reachable from
1259
+ the source.
1260
+
1261
+ In the case where the (di)graph is not connected, if a component
1262
+ not containing the source contains a negative (di)cycle, it
1263
+ will not be detected.
1264
+
1265
+ In NetworkX v2.1 and prior, the source node had predecessor `[None]`.
1266
+ In NetworkX v2.2 this changed to the source node having predecessor `[]`
1267
+ """
1268
+ if source not in G:
1269
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
1270
+ weight = _weight_function(G, weight)
1271
+ if G.is_multigraph():
1272
+ if any(
1273
+ weight(u, v, {k: d}) < 0
1274
+ for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True)
1275
+ ):
1276
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
1277
+ else:
1278
+ if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)):
1279
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
1280
+
1281
+ dist = {source: 0}
1282
+ pred = {source: []}
1283
+
1284
+ if len(G) == 1:
1285
+ return pred, dist
1286
+
1287
+ weight = _weight_function(G, weight)
1288
+
1289
+ dist = _bellman_ford(
1290
+ G, [source], weight, pred=pred, dist=dist, target=target, heuristic=heuristic
1291
+ )
1292
+ return (pred, dist)
1293
+
1294
+
1295
+ def _bellman_ford(
1296
+ G,
1297
+ source,
1298
+ weight,
1299
+ pred=None,
1300
+ paths=None,
1301
+ dist=None,
1302
+ target=None,
1303
+ heuristic=True,
1304
+ ):
1305
+ """Calls relaxation loop for Bellman–Ford algorithm and builds paths
1306
+
1307
+ This is an implementation of the SPFA variant.
1308
+ See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm
1309
+
1310
+ Parameters
1311
+ ----------
1312
+ G : NetworkX graph
1313
+
1314
+ source: list
1315
+ List of source nodes. The shortest path from any of the source
1316
+ nodes will be found if multiple sources are provided.
1317
+
1318
+ weight : function
1319
+ The weight of an edge is the value returned by the function. The
1320
+ function must accept exactly three positional arguments: the two
1321
+ endpoints of an edge and the dictionary of edge attributes for
1322
+ that edge. The function must return a number.
1323
+
1324
+ pred: dict of lists, optional (default=None)
1325
+ dict to store a list of predecessors keyed by that node
1326
+ If None, predecessors are not stored
1327
+
1328
+ paths: dict, optional (default=None)
1329
+ dict to store the path list from source to each node, keyed by node
1330
+ If None, paths are not stored
1331
+
1332
+ dist: dict, optional (default=None)
1333
+ dict to store distance from source to the keyed node
1334
+ If None, returned dist dict contents default to 0 for every node in the
1335
+ source list
1336
+
1337
+ target: node label, optional
1338
+ Ending node for path. Path lengths to other destinations may (and
1339
+ probably will) be incorrect.
1340
+
1341
+ heuristic : bool
1342
+ Determines whether to use a heuristic to early detect negative
1343
+ cycles at a hopefully negligible cost.
1344
+
1345
+ Returns
1346
+ -------
1347
+ dist : dict
1348
+ Returns a dict keyed by node to the distance from the source.
1349
+ Dicts for paths and pred are in the mutated input dicts by those names.
1350
+
1351
+ Raises
1352
+ ------
1353
+ NodeNotFound
1354
+ If any of `source` is not in `G`.
1355
+
1356
+ NetworkXUnbounded
1357
+ If the (di)graph contains a negative (di)cycle, the
1358
+ algorithm raises an exception to indicate the presence of the
1359
+ negative (di)cycle. Note: any negative weight edge in an
1360
+ undirected graph is a negative cycle
1361
+ """
1362
+ if pred is None:
1363
+ pred = {v: [] for v in source}
1364
+
1365
+ if dist is None:
1366
+ dist = {v: 0 for v in source}
1367
+
1368
+ negative_cycle_found = _inner_bellman_ford(
1369
+ G,
1370
+ source,
1371
+ weight,
1372
+ pred,
1373
+ dist,
1374
+ heuristic,
1375
+ )
1376
+ if negative_cycle_found is not None:
1377
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
1378
+
1379
+ if paths is not None:
1380
+ sources = set(source)
1381
+ dsts = [target] if target is not None else pred
1382
+ for dst in dsts:
1383
+ gen = _build_paths_from_predecessors(sources, dst, pred)
1384
+ paths[dst] = next(gen)
1385
+
1386
+ return dist
1387
+
1388
+
1389
+ def _inner_bellman_ford(
1390
+ G,
1391
+ sources,
1392
+ weight,
1393
+ pred,
1394
+ dist=None,
1395
+ heuristic=True,
1396
+ ):
1397
+ """Inner Relaxation loop for Bellman–Ford algorithm.
1398
+
1399
+ This is an implementation of the SPFA variant.
1400
+ See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm
1401
+
1402
+ Parameters
1403
+ ----------
1404
+ G : NetworkX graph
1405
+
1406
+ source: list
1407
+ List of source nodes. The shortest path from any of the source
1408
+ nodes will be found if multiple sources are provided.
1409
+
1410
+ weight : function
1411
+ The weight of an edge is the value returned by the function. The
1412
+ function must accept exactly three positional arguments: the two
1413
+ endpoints of an edge and the dictionary of edge attributes for
1414
+ that edge. The function must return a number.
1415
+
1416
+ pred: dict of lists
1417
+ dict to store a list of predecessors keyed by that node
1418
+
1419
+ dist: dict, optional (default=None)
1420
+ dict to store distance from source to the keyed node
1421
+ If None, returned dist dict contents default to 0 for every node in the
1422
+ source list
1423
+
1424
+ heuristic : bool
1425
+ Determines whether to use a heuristic to early detect negative
1426
+ cycles at a hopefully negligible cost.
1427
+
1428
+ Returns
1429
+ -------
1430
+ node or None
1431
+ Return a node `v` where processing discovered a negative cycle.
1432
+ If no negative cycle found, return None.
1433
+
1434
+ Raises
1435
+ ------
1436
+ NodeNotFound
1437
+ If any of `source` is not in `G`.
1438
+ """
1439
+ for s in sources:
1440
+ if s not in G:
1441
+ raise nx.NodeNotFound(f"Source {s} not in G")
1442
+
1443
+ if pred is None:
1444
+ pred = {v: [] for v in sources}
1445
+
1446
+ if dist is None:
1447
+ dist = {v: 0 for v in sources}
1448
+
1449
+ # Heuristic Storage setup. Note: use None because nodes cannot be None
1450
+ nonexistent_edge = (None, None)
1451
+ pred_edge = {v: None for v in sources}
1452
+ recent_update = {v: nonexistent_edge for v in sources}
1453
+
1454
+ G_succ = G._adj # For speed-up (and works for both directed and undirected graphs)
1455
+ inf = float("inf")
1456
+ n = len(G)
1457
+
1458
+ count = {}
1459
+ q = deque(sources)
1460
+ in_q = set(sources)
1461
+ while q:
1462
+ u = q.popleft()
1463
+ in_q.remove(u)
1464
+
1465
+ # Skip relaxations if any of the predecessors of u is in the queue.
1466
+ if all(pred_u not in in_q for pred_u in pred[u]):
1467
+ dist_u = dist[u]
1468
+ for v, e in G_succ[u].items():
1469
+ dist_v = dist_u + weight(u, v, e)
1470
+
1471
+ if dist_v < dist.get(v, inf):
1472
+ # In this conditional branch we are updating the path with v.
1473
+ # If it happens that some earlier update also added node v
1474
+ # that implies the existence of a negative cycle since
1475
+ # after the update node v would lie on the update path twice.
1476
+ # The update path is stored up to one of the source nodes,
1477
+ # therefore u is always in the dict recent_update
1478
+ if heuristic:
1479
+ if v in recent_update[u]:
1480
+ # Negative cycle found!
1481
+ pred[v].append(u)
1482
+ return v
1483
+
1484
+ # Transfer the recent update info from u to v if the
1485
+ # same source node is the head of the update path.
1486
+ # If the source node is responsible for the cost update,
1487
+ # then clear the history and use it instead.
1488
+ if v in pred_edge and pred_edge[v] == u:
1489
+ recent_update[v] = recent_update[u]
1490
+ else:
1491
+ recent_update[v] = (u, v)
1492
+
1493
+ if v not in in_q:
1494
+ q.append(v)
1495
+ in_q.add(v)
1496
+ count_v = count.get(v, 0) + 1
1497
+ if count_v == n:
1498
+ # Negative cycle found!
1499
+ return v
1500
+
1501
+ count[v] = count_v
1502
+ dist[v] = dist_v
1503
+ pred[v] = [u]
1504
+ pred_edge[v] = u
1505
+
1506
+ elif dist.get(v) is not None and dist_v == dist.get(v):
1507
+ pred[v].append(u)
1508
+
1509
+ # successfully found shortest_path. No negative cycles found.
1510
+ return None
1511
+
1512
+
1513
+ @nx._dispatchable(edge_attrs="weight")
1514
+ def bellman_ford_path(G, source, target, weight="weight"):
1515
+ """Returns the shortest path from source to target in a weighted graph G.
1516
+
1517
+ Parameters
1518
+ ----------
1519
+ G : NetworkX graph
1520
+
1521
+ source : node
1522
+ Starting node
1523
+
1524
+ target : node
1525
+ Ending node
1526
+
1527
+ weight : string or function (default="weight")
1528
+ If this is a string, then edge weights will be accessed via the
1529
+ edge attribute with this key (that is, the weight of the edge
1530
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1531
+ such edge attribute exists, the weight of the edge is assumed to
1532
+ be one.
1533
+
1534
+ If this is a function, the weight of an edge is the value
1535
+ returned by the function. The function must accept exactly three
1536
+ positional arguments: the two endpoints of an edge and the
1537
+ dictionary of edge attributes for that edge. The function must
1538
+ return a number.
1539
+
1540
+ Returns
1541
+ -------
1542
+ path : list
1543
+ List of nodes in a shortest path.
1544
+
1545
+ Raises
1546
+ ------
1547
+ NodeNotFound
1548
+ If `source` is not in `G`.
1549
+
1550
+ NetworkXNoPath
1551
+ If no path exists between source and target.
1552
+
1553
+ Examples
1554
+ --------
1555
+ >>> G = nx.path_graph(5)
1556
+ >>> nx.bellman_ford_path(G, 0, 4)
1557
+ [0, 1, 2, 3, 4]
1558
+
1559
+ Notes
1560
+ -----
1561
+ Edge weight attributes must be numerical.
1562
+ Distances are calculated as sums of weighted edges traversed.
1563
+
1564
+ See Also
1565
+ --------
1566
+ dijkstra_path, bellman_ford_path_length
1567
+ """
1568
+ length, path = single_source_bellman_ford(G, source, target=target, weight=weight)
1569
+ return path
1570
+
1571
+
1572
+ @nx._dispatchable(edge_attrs="weight")
1573
+ def bellman_ford_path_length(G, source, target, weight="weight"):
1574
+ """Returns the shortest path length from source to target
1575
+ in a weighted graph.
1576
+
1577
+ Parameters
1578
+ ----------
1579
+ G : NetworkX graph
1580
+
1581
+ source : node label
1582
+ starting node for path
1583
+
1584
+ target : node label
1585
+ ending node for path
1586
+
1587
+ weight : string or function (default="weight")
1588
+ If this is a string, then edge weights will be accessed via the
1589
+ edge attribute with this key (that is, the weight of the edge
1590
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1591
+ such edge attribute exists, the weight of the edge is assumed to
1592
+ be one.
1593
+
1594
+ If this is a function, the weight of an edge is the value
1595
+ returned by the function. The function must accept exactly three
1596
+ positional arguments: the two endpoints of an edge and the
1597
+ dictionary of edge attributes for that edge. The function must
1598
+ return a number.
1599
+
1600
+ Returns
1601
+ -------
1602
+ length : number
1603
+ Shortest path length.
1604
+
1605
+ Raises
1606
+ ------
1607
+ NodeNotFound
1608
+ If `source` is not in `G`.
1609
+
1610
+ NetworkXNoPath
1611
+ If no path exists between source and target.
1612
+
1613
+ Examples
1614
+ --------
1615
+ >>> G = nx.path_graph(5)
1616
+ >>> nx.bellman_ford_path_length(G, 0, 4)
1617
+ 4
1618
+
1619
+ Notes
1620
+ -----
1621
+ Edge weight attributes must be numerical.
1622
+ Distances are calculated as sums of weighted edges traversed.
1623
+
1624
+ See Also
1625
+ --------
1626
+ dijkstra_path_length, bellman_ford_path
1627
+ """
1628
+ if source == target:
1629
+ if source not in G:
1630
+ raise nx.NodeNotFound(f"Node {source} not found in graph")
1631
+ return 0
1632
+
1633
+ weight = _weight_function(G, weight)
1634
+
1635
+ length = _bellman_ford(G, [source], weight, target=target)
1636
+
1637
+ try:
1638
+ return length[target]
1639
+ except KeyError as err:
1640
+ raise nx.NetworkXNoPath(f"node {target} not reachable from {source}") from err
1641
+
1642
+
1643
+ @nx._dispatchable(edge_attrs="weight")
1644
+ def single_source_bellman_ford_path(G, source, weight="weight"):
1645
+ """Compute shortest path between source and all other reachable
1646
+ nodes for a weighted graph.
1647
+
1648
+ Parameters
1649
+ ----------
1650
+ G : NetworkX graph
1651
+
1652
+ source : node
1653
+ Starting node for path.
1654
+
1655
+ weight : string or function (default="weight")
1656
+ If this is a string, then edge weights will be accessed via the
1657
+ edge attribute with this key (that is, the weight of the edge
1658
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1659
+ such edge attribute exists, the weight of the edge is assumed to
1660
+ be one.
1661
+
1662
+ If this is a function, the weight of an edge is the value
1663
+ returned by the function. The function must accept exactly three
1664
+ positional arguments: the two endpoints of an edge and the
1665
+ dictionary of edge attributes for that edge. The function must
1666
+ return a number.
1667
+
1668
+ Returns
1669
+ -------
1670
+ paths : dictionary
1671
+ Dictionary of shortest path lengths keyed by target.
1672
+
1673
+ Raises
1674
+ ------
1675
+ NodeNotFound
1676
+ If `source` is not in `G`.
1677
+
1678
+ Examples
1679
+ --------
1680
+ >>> G = nx.path_graph(5)
1681
+ >>> path = nx.single_source_bellman_ford_path(G, 0)
1682
+ >>> path[4]
1683
+ [0, 1, 2, 3, 4]
1684
+
1685
+ Notes
1686
+ -----
1687
+ Edge weight attributes must be numerical.
1688
+ Distances are calculated as sums of weighted edges traversed.
1689
+
1690
+ See Also
1691
+ --------
1692
+ single_source_dijkstra, single_source_bellman_ford
1693
+
1694
+ """
1695
+ (length, path) = single_source_bellman_ford(G, source, weight=weight)
1696
+ return path
1697
+
1698
+
1699
+ @nx._dispatchable(edge_attrs="weight")
1700
+ def single_source_bellman_ford_path_length(G, source, weight="weight"):
1701
+ """Compute the shortest path length between source and all other
1702
+ reachable nodes for a weighted graph.
1703
+
1704
+ Parameters
1705
+ ----------
1706
+ G : NetworkX graph
1707
+
1708
+ source : node label
1709
+ Starting node for path
1710
+
1711
+ weight : string or function (default="weight")
1712
+ If this is a string, then edge weights will be accessed via the
1713
+ edge attribute with this key (that is, the weight of the edge
1714
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1715
+ such edge attribute exists, the weight of the edge is assumed to
1716
+ be one.
1717
+
1718
+ If this is a function, the weight of an edge is the value
1719
+ returned by the function. The function must accept exactly three
1720
+ positional arguments: the two endpoints of an edge and the
1721
+ dictionary of edge attributes for that edge. The function must
1722
+ return a number.
1723
+
1724
+ Returns
1725
+ -------
1726
+ length : dictionary
1727
+ Dictionary of shortest path length keyed by target
1728
+
1729
+ Raises
1730
+ ------
1731
+ NodeNotFound
1732
+ If `source` is not in `G`.
1733
+
1734
+ Examples
1735
+ --------
1736
+ >>> G = nx.path_graph(5)
1737
+ >>> length = nx.single_source_bellman_ford_path_length(G, 0)
1738
+ >>> length[4]
1739
+ 4
1740
+ >>> for node in [0, 1, 2, 3, 4]:
1741
+ ... print(f"{node}: {length[node]}")
1742
+ 0: 0
1743
+ 1: 1
1744
+ 2: 2
1745
+ 3: 3
1746
+ 4: 4
1747
+
1748
+ Notes
1749
+ -----
1750
+ Edge weight attributes must be numerical.
1751
+ Distances are calculated as sums of weighted edges traversed.
1752
+
1753
+ See Also
1754
+ --------
1755
+ single_source_dijkstra, single_source_bellman_ford
1756
+
1757
+ """
1758
+ weight = _weight_function(G, weight)
1759
+ return _bellman_ford(G, [source], weight)
1760
+
1761
+
1762
+ @nx._dispatchable(edge_attrs="weight")
1763
+ def single_source_bellman_ford(G, source, target=None, weight="weight"):
1764
+ """Compute shortest paths and lengths in a weighted graph G.
1765
+
1766
+ Uses Bellman-Ford algorithm for shortest paths.
1767
+
1768
+ Parameters
1769
+ ----------
1770
+ G : NetworkX graph
1771
+
1772
+ source : node label
1773
+ Starting node for path
1774
+
1775
+ target : node label, optional
1776
+ Ending node for path
1777
+
1778
+ weight : string or function
1779
+ If this is a string, then edge weights will be accessed via the
1780
+ edge attribute with this key (that is, the weight of the edge
1781
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1782
+ such edge attribute exists, the weight of the edge is assumed to
1783
+ be one.
1784
+
1785
+ If this is a function, the weight of an edge is the value
1786
+ returned by the function. The function must accept exactly three
1787
+ positional arguments: the two endpoints of an edge and the
1788
+ dictionary of edge attributes for that edge. The function must
1789
+ return a number.
1790
+
1791
+ Returns
1792
+ -------
1793
+ distance, path : pair of dictionaries, or numeric and list
1794
+ If target is None, returns a tuple of two dictionaries keyed by node.
1795
+ The first dictionary stores distance from one of the source nodes.
1796
+ The second stores the path from one of the sources to that node.
1797
+ If target is not None, returns a tuple of (distance, path) where
1798
+ distance is the distance from source to target and path is a list
1799
+ representing the path from source to target.
1800
+
1801
+ Raises
1802
+ ------
1803
+ NodeNotFound
1804
+ If `source` is not in `G`.
1805
+
1806
+ Examples
1807
+ --------
1808
+ >>> G = nx.path_graph(5)
1809
+ >>> length, path = nx.single_source_bellman_ford(G, 0)
1810
+ >>> length[4]
1811
+ 4
1812
+ >>> for node in [0, 1, 2, 3, 4]:
1813
+ ... print(f"{node}: {length[node]}")
1814
+ 0: 0
1815
+ 1: 1
1816
+ 2: 2
1817
+ 3: 3
1818
+ 4: 4
1819
+ >>> path[4]
1820
+ [0, 1, 2, 3, 4]
1821
+ >>> length, path = nx.single_source_bellman_ford(G, 0, 1)
1822
+ >>> length
1823
+ 1
1824
+ >>> path
1825
+ [0, 1]
1826
+
1827
+ Notes
1828
+ -----
1829
+ Edge weight attributes must be numerical.
1830
+ Distances are calculated as sums of weighted edges traversed.
1831
+
1832
+ See Also
1833
+ --------
1834
+ single_source_dijkstra
1835
+ single_source_bellman_ford_path
1836
+ single_source_bellman_ford_path_length
1837
+ """
1838
+ if source == target:
1839
+ if source not in G:
1840
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
1841
+ return (0, [source])
1842
+
1843
+ weight = _weight_function(G, weight)
1844
+
1845
+ paths = {source: [source]} # dictionary of paths
1846
+ dist = _bellman_ford(G, [source], weight, paths=paths, target=target)
1847
+ if target is None:
1848
+ return (dist, paths)
1849
+ try:
1850
+ return (dist[target], paths[target])
1851
+ except KeyError as err:
1852
+ msg = f"Node {target} not reachable from {source}"
1853
+ raise nx.NetworkXNoPath(msg) from err
1854
+
1855
+
1856
+ @nx._dispatchable(edge_attrs="weight")
1857
+ def all_pairs_bellman_ford_path_length(G, weight="weight"):
1858
+ """Compute shortest path lengths between all nodes in a weighted graph.
1859
+
1860
+ Parameters
1861
+ ----------
1862
+ G : NetworkX graph
1863
+
1864
+ weight : string or function (default="weight")
1865
+ If this is a string, then edge weights will be accessed via the
1866
+ edge attribute with this key (that is, the weight of the edge
1867
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1868
+ such edge attribute exists, the weight of the edge is assumed to
1869
+ be one.
1870
+
1871
+ If this is a function, the weight of an edge is the value
1872
+ returned by the function. The function must accept exactly three
1873
+ positional arguments: the two endpoints of an edge and the
1874
+ dictionary of edge attributes for that edge. The function must
1875
+ return a number.
1876
+
1877
+ Returns
1878
+ -------
1879
+ distance : iterator
1880
+ (source, dictionary) iterator with dictionary keyed by target and
1881
+ shortest path length as the key value.
1882
+
1883
+ Examples
1884
+ --------
1885
+ >>> G = nx.path_graph(5)
1886
+ >>> length = dict(nx.all_pairs_bellman_ford_path_length(G))
1887
+ >>> for node in [0, 1, 2, 3, 4]:
1888
+ ... print(f"1 - {node}: {length[1][node]}")
1889
+ 1 - 0: 1
1890
+ 1 - 1: 0
1891
+ 1 - 2: 1
1892
+ 1 - 3: 2
1893
+ 1 - 4: 3
1894
+ >>> length[3][2]
1895
+ 1
1896
+ >>> length[2][2]
1897
+ 0
1898
+
1899
+ Notes
1900
+ -----
1901
+ Edge weight attributes must be numerical.
1902
+ Distances are calculated as sums of weighted edges traversed.
1903
+
1904
+ The dictionary returned only has keys for reachable node pairs.
1905
+ """
1906
+ length = single_source_bellman_ford_path_length
1907
+ for n in G:
1908
+ yield (n, dict(length(G, n, weight=weight)))
1909
+
1910
+
1911
+ @nx._dispatchable(edge_attrs="weight")
1912
+ def all_pairs_bellman_ford_path(G, weight="weight"):
1913
+ """Compute shortest paths between all nodes in a weighted graph.
1914
+
1915
+ Parameters
1916
+ ----------
1917
+ G : NetworkX graph
1918
+
1919
+ weight : string or function (default="weight")
1920
+ If this is a string, then edge weights will be accessed via the
1921
+ edge attribute with this key (that is, the weight of the edge
1922
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1923
+ such edge attribute exists, the weight of the edge is assumed to
1924
+ be one.
1925
+
1926
+ If this is a function, the weight of an edge is the value
1927
+ returned by the function. The function must accept exactly three
1928
+ positional arguments: the two endpoints of an edge and the
1929
+ dictionary of edge attributes for that edge. The function must
1930
+ return a number.
1931
+
1932
+ Returns
1933
+ -------
1934
+ paths : iterator
1935
+ (source, dictionary) iterator with dictionary keyed by target and
1936
+ shortest path as the key value.
1937
+
1938
+ Examples
1939
+ --------
1940
+ >>> G = nx.path_graph(5)
1941
+ >>> path = dict(nx.all_pairs_bellman_ford_path(G))
1942
+ >>> path[0][4]
1943
+ [0, 1, 2, 3, 4]
1944
+
1945
+ Notes
1946
+ -----
1947
+ Edge weight attributes must be numerical.
1948
+ Distances are calculated as sums of weighted edges traversed.
1949
+
1950
+ See Also
1951
+ --------
1952
+ floyd_warshall, all_pairs_dijkstra_path
1953
+
1954
+ """
1955
+ path = single_source_bellman_ford_path
1956
+ for n in G:
1957
+ yield (n, path(G, n, weight=weight))
1958
+
1959
+
1960
+ @nx._dispatchable(edge_attrs="weight")
1961
+ def goldberg_radzik(G, source, weight="weight"):
1962
+ """Compute shortest path lengths and predecessors on shortest paths
1963
+ in weighted graphs.
1964
+
1965
+ The algorithm has a running time of $O(mn)$ where $n$ is the number of
1966
+ nodes and $m$ is the number of edges. It is slower than Dijkstra but
1967
+ can handle negative edge weights.
1968
+
1969
+ Parameters
1970
+ ----------
1971
+ G : NetworkX graph
1972
+ The algorithm works for all types of graphs, including directed
1973
+ graphs and multigraphs.
1974
+
1975
+ source: node label
1976
+ Starting node for path
1977
+
1978
+ weight : string or function
1979
+ If this is a string, then edge weights will be accessed via the
1980
+ edge attribute with this key (that is, the weight of the edge
1981
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
1982
+ such edge attribute exists, the weight of the edge is assumed to
1983
+ be one.
1984
+
1985
+ If this is a function, the weight of an edge is the value
1986
+ returned by the function. The function must accept exactly three
1987
+ positional arguments: the two endpoints of an edge and the
1988
+ dictionary of edge attributes for that edge. The function must
1989
+ return a number.
1990
+
1991
+ Returns
1992
+ -------
1993
+ pred, dist : dictionaries
1994
+ Returns two dictionaries keyed by node to predecessor in the
1995
+ path and to the distance from the source respectively.
1996
+
1997
+ Raises
1998
+ ------
1999
+ NodeNotFound
2000
+ If `source` is not in `G`.
2001
+
2002
+ NetworkXUnbounded
2003
+ If the (di)graph contains a negative (di)cycle, the
2004
+ algorithm raises an exception to indicate the presence of the
2005
+ negative (di)cycle. Note: any negative weight edge in an
2006
+ undirected graph is a negative cycle.
2007
+
2008
+ As of NetworkX v3.2, a zero weight cycle is no longer
2009
+ incorrectly reported as a negative weight cycle.
2010
+
2011
+
2012
+ Examples
2013
+ --------
2014
+ >>> G = nx.path_graph(5, create_using=nx.DiGraph())
2015
+ >>> pred, dist = nx.goldberg_radzik(G, 0)
2016
+ >>> sorted(pred.items())
2017
+ [(0, None), (1, 0), (2, 1), (3, 2), (4, 3)]
2018
+ >>> sorted(dist.items())
2019
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
2020
+
2021
+ >>> G = nx.cycle_graph(5, create_using=nx.DiGraph())
2022
+ >>> G[1][2]["weight"] = -7
2023
+ >>> nx.goldberg_radzik(G, 0)
2024
+ Traceback (most recent call last):
2025
+ ...
2026
+ networkx.exception.NetworkXUnbounded: Negative cycle detected.
2027
+
2028
+ Notes
2029
+ -----
2030
+ Edge weight attributes must be numerical.
2031
+ Distances are calculated as sums of weighted edges traversed.
2032
+
2033
+ The dictionaries returned only have keys for nodes reachable from
2034
+ the source.
2035
+
2036
+ In the case where the (di)graph is not connected, if a component
2037
+ not containing the source contains a negative (di)cycle, it
2038
+ will not be detected.
2039
+
2040
+ """
2041
+ if source not in G:
2042
+ raise nx.NodeNotFound(f"Node {source} is not found in the graph")
2043
+ weight = _weight_function(G, weight)
2044
+ if G.is_multigraph():
2045
+ if any(
2046
+ weight(u, v, {k: d}) < 0
2047
+ for u, v, k, d in nx.selfloop_edges(G, keys=True, data=True)
2048
+ ):
2049
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
2050
+ else:
2051
+ if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)):
2052
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
2053
+
2054
+ if len(G) == 1:
2055
+ return {source: None}, {source: 0}
2056
+
2057
+ G_succ = G._adj # For speed-up (and works for both directed and undirected graphs)
2058
+
2059
+ inf = float("inf")
2060
+ d = {u: inf for u in G}
2061
+ d[source] = 0
2062
+ pred = {source: None}
2063
+
2064
+ def topo_sort(relabeled):
2065
+ """Topologically sort nodes relabeled in the previous round and detect
2066
+ negative cycles.
2067
+ """
2068
+ # List of nodes to scan in this round. Denoted by A in Goldberg and
2069
+ # Radzik's paper.
2070
+ to_scan = []
2071
+ # In the DFS in the loop below, neg_count records for each node the
2072
+ # number of edges of negative reduced costs on the path from a DFS root
2073
+ # to the node in the DFS forest. The reduced cost of an edge (u, v) is
2074
+ # defined as d[u] + weight[u][v] - d[v].
2075
+ #
2076
+ # neg_count also doubles as the DFS visit marker array.
2077
+ neg_count = {}
2078
+ for u in relabeled - neg_count.keys():
2079
+ d_u = d[u]
2080
+ # Skip nodes without out-edges of negative reduced costs.
2081
+ if all(d_u + weight(u, v, e) >= d[v] for v, e in G_succ[u].items()):
2082
+ continue
2083
+ # Nonrecursive DFS that inserts nodes reachable from u via edges of
2084
+ # nonpositive reduced costs into to_scan in (reverse) topological
2085
+ # order.
2086
+ stack = [(u, iter(G_succ[u].items()))]
2087
+ in_stack = {u}
2088
+ neg_count[u] = 0
2089
+ while stack:
2090
+ u, it = stack[-1]
2091
+ try:
2092
+ v, e = next(it)
2093
+ except StopIteration:
2094
+ to_scan.append(u)
2095
+ stack.pop()
2096
+ in_stack.remove(u)
2097
+ continue
2098
+ t = d[u] + weight(u, v, e)
2099
+ d_v = d[v]
2100
+ if t < d_v:
2101
+ d[v] = t
2102
+ pred[v] = u
2103
+ if v not in neg_count:
2104
+ neg_count[v] = neg_count[u] + 1
2105
+ stack.append((v, iter(G_succ[v].items())))
2106
+ in_stack.add(v)
2107
+ elif v in in_stack and neg_count[u] + 1 > neg_count[v]:
2108
+ # (u, v) is a back edge, and the cycle formed by the
2109
+ # path v to u and (u, v) contains at least one edge of
2110
+ # negative reduced cost. The cycle must be of negative
2111
+ # cost.
2112
+ raise nx.NetworkXUnbounded("Negative cycle detected.")
2113
+ to_scan.reverse()
2114
+ return to_scan
2115
+
2116
+ def relax(to_scan):
2117
+ """Relax out-edges of relabeled nodes."""
2118
+ relabeled = set()
2119
+ # Scan nodes in to_scan in topological order and relax incident
2120
+ # out-edges. Add the relabeled nodes to labeled.
2121
+ for u in to_scan:
2122
+ d_u = d[u]
2123
+ for v, e in G_succ[u].items():
2124
+ w_e = weight(u, v, e)
2125
+ if d_u + w_e < d[v]:
2126
+ d[v] = d_u + w_e
2127
+ pred[v] = u
2128
+ relabeled.add(v)
2129
+ return relabeled
2130
+
2131
+ # Set of nodes relabeled in the last round of scan operations. Denoted by B
2132
+ # in Goldberg and Radzik's paper.
2133
+ relabeled = {source}
2134
+
2135
+ while relabeled:
2136
+ to_scan = topo_sort(relabeled)
2137
+ relabeled = relax(to_scan)
2138
+
2139
+ d = {u: d[u] for u in pred}
2140
+ return pred, d
2141
+
2142
+
2143
+ @nx._dispatchable(edge_attrs="weight")
2144
+ def negative_edge_cycle(G, weight="weight", heuristic=True):
2145
+ """Returns True if there exists a negative edge cycle anywhere in G.
2146
+
2147
+ Parameters
2148
+ ----------
2149
+ G : NetworkX graph
2150
+
2151
+ weight : string or function
2152
+ If this is a string, then edge weights will be accessed via the
2153
+ edge attribute with this key (that is, the weight of the edge
2154
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
2155
+ such edge attribute exists, the weight of the edge is assumed to
2156
+ be one.
2157
+
2158
+ If this is a function, the weight of an edge is the value
2159
+ returned by the function. The function must accept exactly three
2160
+ positional arguments: the two endpoints of an edge and the
2161
+ dictionary of edge attributes for that edge. The function must
2162
+ return a number.
2163
+
2164
+ heuristic : bool
2165
+ Determines whether to use a heuristic to early detect negative
2166
+ cycles at a negligible cost. In case of graphs with a negative cycle,
2167
+ the performance of detection increases by at least an order of magnitude.
2168
+
2169
+ Returns
2170
+ -------
2171
+ negative_cycle : bool
2172
+ True if a negative edge cycle exists, otherwise False.
2173
+
2174
+ Examples
2175
+ --------
2176
+ >>> G = nx.cycle_graph(5, create_using=nx.DiGraph())
2177
+ >>> print(nx.negative_edge_cycle(G))
2178
+ False
2179
+ >>> G[1][2]["weight"] = -7
2180
+ >>> print(nx.negative_edge_cycle(G))
2181
+ True
2182
+
2183
+ Notes
2184
+ -----
2185
+ Edge weight attributes must be numerical.
2186
+ Distances are calculated as sums of weighted edges traversed.
2187
+
2188
+ This algorithm uses bellman_ford_predecessor_and_distance() but finds
2189
+ negative cycles on any component by first adding a new node connected to
2190
+ every node, and starting bellman_ford_predecessor_and_distance on that
2191
+ node. It then removes that extra node.
2192
+ """
2193
+ if G.size() == 0:
2194
+ return False
2195
+
2196
+ # find unused node to use temporarily
2197
+ newnode = -1
2198
+ while newnode in G:
2199
+ newnode -= 1
2200
+ # connect it to all nodes
2201
+ G.add_edges_from([(newnode, n) for n in G])
2202
+
2203
+ try:
2204
+ bellman_ford_predecessor_and_distance(
2205
+ G, newnode, weight=weight, heuristic=heuristic
2206
+ )
2207
+ except nx.NetworkXUnbounded:
2208
+ return True
2209
+ finally:
2210
+ G.remove_node(newnode)
2211
+ return False
2212
+
2213
+
2214
+ @nx._dispatchable(edge_attrs="weight")
2215
+ def find_negative_cycle(G, source, weight="weight"):
2216
+ """Returns a cycle with negative total weight if it exists.
2217
+
2218
+ Bellman-Ford is used to find shortest_paths. That algorithm
2219
+ stops if there exists a negative cycle. This algorithm
2220
+ picks up from there and returns the found negative cycle.
2221
+
2222
+ The cycle consists of a list of nodes in the cycle order. The last
2223
+ node equals the first to make it a cycle.
2224
+ You can look up the edge weights in the original graph. In the case
2225
+ of multigraphs the relevant edge is the minimal weight edge between
2226
+ the nodes in the 2-tuple.
2227
+
2228
+ If the graph has no negative cycle, a NetworkXError is raised.
2229
+
2230
+ Parameters
2231
+ ----------
2232
+ G : NetworkX graph
2233
+
2234
+ source: node label
2235
+ The search for the negative cycle will start from this node.
2236
+
2237
+ weight : string or function
2238
+ If this is a string, then edge weights will be accessed via the
2239
+ edge attribute with this key (that is, the weight of the edge
2240
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
2241
+ such edge attribute exists, the weight of the edge is assumed to
2242
+ be one.
2243
+
2244
+ If this is a function, the weight of an edge is the value
2245
+ returned by the function. The function must accept exactly three
2246
+ positional arguments: the two endpoints of an edge and the
2247
+ dictionary of edge attributes for that edge. The function must
2248
+ return a number.
2249
+
2250
+ Examples
2251
+ --------
2252
+ >>> G = nx.DiGraph()
2253
+ >>> G.add_weighted_edges_from(
2254
+ ... [(0, 1, 2), (1, 2, 2), (2, 0, 1), (1, 4, 2), (4, 0, -5)]
2255
+ ... )
2256
+ >>> nx.find_negative_cycle(G, 0)
2257
+ [4, 0, 1, 4]
2258
+
2259
+ Returns
2260
+ -------
2261
+ cycle : list
2262
+ A list of nodes in the order of the cycle found. The last node
2263
+ equals the first to indicate a cycle.
2264
+
2265
+ Raises
2266
+ ------
2267
+ NetworkXError
2268
+ If no negative cycle is found.
2269
+ """
2270
+ weight = _weight_function(G, weight)
2271
+ pred = {source: []}
2272
+
2273
+ v = _inner_bellman_ford(G, [source], weight, pred=pred)
2274
+ if v is None:
2275
+ raise nx.NetworkXError("No negative cycles detected.")
2276
+
2277
+ # negative cycle detected... find it
2278
+ neg_cycle = []
2279
+ stack = [(v, list(pred[v]))]
2280
+ seen = {v}
2281
+ while stack:
2282
+ node, preds = stack[-1]
2283
+ if v in preds:
2284
+ # found the cycle
2285
+ neg_cycle.extend([node, v])
2286
+ neg_cycle = list(reversed(neg_cycle))
2287
+ return neg_cycle
2288
+
2289
+ if preds:
2290
+ nbr = preds.pop()
2291
+ if nbr not in seen:
2292
+ stack.append((nbr, list(pred[nbr])))
2293
+ neg_cycle.append(node)
2294
+ seen.add(nbr)
2295
+ else:
2296
+ stack.pop()
2297
+ if neg_cycle:
2298
+ neg_cycle.pop()
2299
+ else:
2300
+ if v in G[v] and weight(G, v, v) < 0:
2301
+ return [v, v]
2302
+ # should not reach here
2303
+ raise nx.NetworkXError("Negative cycle is detected but not found")
2304
+ # should not get here...
2305
+ msg = "negative cycle detected but not identified"
2306
+ raise nx.NetworkXUnbounded(msg)
2307
+
2308
+
2309
+ @nx._dispatchable(edge_attrs="weight")
2310
+ def bidirectional_dijkstra(G, source, target, weight="weight"):
2311
+ r"""Dijkstra's algorithm for shortest paths using bidirectional search.
2312
+
2313
+ Parameters
2314
+ ----------
2315
+ G : NetworkX graph
2316
+
2317
+ source : node
2318
+ Starting node.
2319
+
2320
+ target : node
2321
+ Ending node.
2322
+
2323
+ weight : string or function
2324
+ If this is a string, then edge weights will be accessed via the
2325
+ edge attribute with this key (that is, the weight of the edge
2326
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
2327
+ such edge attribute exists, the weight of the edge is assumed to
2328
+ be one.
2329
+
2330
+ If this is a function, the weight of an edge is the value
2331
+ returned by the function. The function must accept exactly three
2332
+ positional arguments: the two endpoints of an edge and the
2333
+ dictionary of edge attributes for that edge. The function must
2334
+ return a number or None to indicate a hidden edge.
2335
+
2336
+ Returns
2337
+ -------
2338
+ length, path : number and list
2339
+ length is the distance from source to target.
2340
+ path is a list of nodes on a path from source to target.
2341
+
2342
+ Raises
2343
+ ------
2344
+ NodeNotFound
2345
+ If `source` or `target` is not in `G`.
2346
+
2347
+ NetworkXNoPath
2348
+ If no path exists between source and target.
2349
+
2350
+ Examples
2351
+ --------
2352
+ >>> G = nx.path_graph(5)
2353
+ >>> length, path = nx.bidirectional_dijkstra(G, 0, 4)
2354
+ >>> print(length)
2355
+ 4
2356
+ >>> print(path)
2357
+ [0, 1, 2, 3, 4]
2358
+
2359
+ Notes
2360
+ -----
2361
+ Edge weight attributes must be numerical.
2362
+ Distances are calculated as sums of weighted edges traversed.
2363
+
2364
+ The weight function can be used to hide edges by returning None.
2365
+ So ``weight = lambda u, v, d: 1 if d['color']=="red" else None``
2366
+ will find the shortest red path.
2367
+
2368
+ In practice bidirectional Dijkstra is much more than twice as fast as
2369
+ ordinary Dijkstra.
2370
+
2371
+ Ordinary Dijkstra expands nodes in a sphere-like manner from the
2372
+ source. The radius of this sphere will eventually be the length
2373
+ of the shortest path. Bidirectional Dijkstra will expand nodes
2374
+ from both the source and the target, making two spheres of half
2375
+ this radius. Volume of the first sphere is `\pi*r*r` while the
2376
+ others are `2*\pi*r/2*r/2`, making up half the volume.
2377
+
2378
+ This algorithm is not guaranteed to work if edge weights
2379
+ are negative or are floating point numbers
2380
+ (overflows and roundoff errors can cause problems).
2381
+
2382
+ See Also
2383
+ --------
2384
+ shortest_path
2385
+ shortest_path_length
2386
+ """
2387
+ if source not in G:
2388
+ raise nx.NodeNotFound(f"Source {source} is not in G")
2389
+
2390
+ if target not in G:
2391
+ raise nx.NodeNotFound(f"Target {target} is not in G")
2392
+
2393
+ if source == target:
2394
+ return (0, [source])
2395
+
2396
+ weight = _weight_function(G, weight)
2397
+ # Init: [Forward, Backward]
2398
+ dists = [{}, {}] # dictionary of final distances
2399
+ preds = [{source: None}, {target: None}] # dictionary of preds
2400
+
2401
+ def path(curr, direction):
2402
+ ret = []
2403
+ while curr is not None:
2404
+ ret.append(curr)
2405
+ curr = preds[direction][curr]
2406
+ return list(reversed(ret)) if direction == 0 else ret
2407
+
2408
+ fringe = [[], []] # heap of (distance, node) for choosing node to expand
2409
+ seen = [{source: 0}, {target: 0}] # dict of distances to seen nodes
2410
+ c = count()
2411
+ # initialize fringe heap
2412
+ heappush(fringe[0], (0, next(c), source))
2413
+ heappush(fringe[1], (0, next(c), target))
2414
+ # neighbors for extracting correct neighbor information
2415
+ if G.is_directed():
2416
+ neighbors = [G._succ, G._pred]
2417
+ else:
2418
+ neighbors = [G._adj, G._adj]
2419
+ # variables to hold shortest discovered path
2420
+ finaldist = None
2421
+ meetnode = None
2422
+ direction = 1
2423
+ while fringe[0] and fringe[1]:
2424
+ # choose direction
2425
+ # direction == 0 is forward direction and direction == 1 is back
2426
+ direction = 1 - direction
2427
+ # extract closest to expand
2428
+ (dist, _, v) = heappop(fringe[direction])
2429
+ if v in dists[direction]:
2430
+ # Shortest path to v has already been found
2431
+ continue
2432
+ # update distance
2433
+ dists[direction][v] = dist # equal to seen[direction][v]
2434
+ if v in dists[1 - direction]:
2435
+ # if we have scanned v in both directions we are done
2436
+ # we have now discovered the shortest path
2437
+ return (finaldist, path(meetnode, 0) + path(preds[1][meetnode], 1))
2438
+
2439
+ for w, d in neighbors[direction][v].items():
2440
+ # weight(v, w, d) for forward and weight(w, v, d) for back direction
2441
+ cost = weight(v, w, d) if direction == 0 else weight(w, v, d)
2442
+ if cost is None:
2443
+ continue
2444
+ vwLength = dist + cost
2445
+ if w in dists[direction]:
2446
+ if vwLength < dists[direction][w]:
2447
+ raise ValueError("Contradictory paths found: negative weights?")
2448
+ elif w not in seen[direction] or vwLength < seen[direction][w]:
2449
+ # relaxing
2450
+ seen[direction][w] = vwLength
2451
+ heappush(fringe[direction], (vwLength, next(c), w))
2452
+ preds[direction][w] = v
2453
+ if w in seen[1 - direction]:
2454
+ # see if this path is better than the already
2455
+ # discovered shortest path
2456
+ finaldist_w = vwLength + seen[1 - direction][w]
2457
+ if finaldist is None or finaldist > finaldist_w:
2458
+ finaldist, meetnode = finaldist_w, w
2459
+ raise nx.NetworkXNoPath(f"No path between {source} and {target}.")
2460
+
2461
+
2462
+ @nx._dispatchable(edge_attrs="weight")
2463
+ def johnson(G, weight="weight"):
2464
+ r"""Uses Johnson's Algorithm to compute shortest paths.
2465
+
2466
+ Johnson's Algorithm finds a shortest path between each pair of
2467
+ nodes in a weighted graph even if negative weights are present.
2468
+
2469
+ Parameters
2470
+ ----------
2471
+ G : NetworkX graph
2472
+
2473
+ weight : string or function
2474
+ If this is a string, then edge weights will be accessed via the
2475
+ edge attribute with this key (that is, the weight of the edge
2476
+ joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
2477
+ such edge attribute exists, the weight of the edge is assumed to
2478
+ be one.
2479
+
2480
+ If this is a function, the weight of an edge is the value
2481
+ returned by the function. The function must accept exactly three
2482
+ positional arguments: the two endpoints of an edge and the
2483
+ dictionary of edge attributes for that edge. The function must
2484
+ return a number.
2485
+
2486
+ Returns
2487
+ -------
2488
+ distance : dictionary
2489
+ Dictionary, keyed by source and target, of shortest paths.
2490
+
2491
+ Examples
2492
+ --------
2493
+ >>> graph = nx.DiGraph()
2494
+ >>> graph.add_weighted_edges_from(
2495
+ ... [("0", "3", 3), ("0", "1", -5), ("0", "2", 2), ("1", "2", 4), ("2", "3", 1)]
2496
+ ... )
2497
+ >>> paths = nx.johnson(graph, weight="weight")
2498
+ >>> paths["0"]["2"]
2499
+ ['0', '1', '2']
2500
+
2501
+ Notes
2502
+ -----
2503
+ Johnson's algorithm is suitable even for graphs with negative weights. It
2504
+ works by using the Bellman–Ford algorithm to compute a transformation of
2505
+ the input graph that removes all negative weights, allowing Dijkstra's
2506
+ algorithm to be used on the transformed graph.
2507
+
2508
+ The time complexity of this algorithm is $O(n^2 \log n + n m)$,
2509
+ where $n$ is the number of nodes and $m$ the number of edges in the
2510
+ graph. For dense graphs, this may be faster than the Floyd–Warshall
2511
+ algorithm.
2512
+
2513
+ See Also
2514
+ --------
2515
+ floyd_warshall_predecessor_and_distance
2516
+ floyd_warshall_numpy
2517
+ all_pairs_shortest_path
2518
+ all_pairs_shortest_path_length
2519
+ all_pairs_dijkstra_path
2520
+ bellman_ford_predecessor_and_distance
2521
+ all_pairs_bellman_ford_path
2522
+ all_pairs_bellman_ford_path_length
2523
+
2524
+ """
2525
+ dist = {v: 0 for v in G}
2526
+ pred = {v: [] for v in G}
2527
+ weight = _weight_function(G, weight)
2528
+
2529
+ # Calculate distance of shortest paths
2530
+ dist_bellman = _bellman_ford(G, list(G), weight, pred=pred, dist=dist)
2531
+
2532
+ # Update the weight function to take into account the Bellman--Ford
2533
+ # relaxation distances.
2534
+ def new_weight(u, v, d):
2535
+ return weight(u, v, d) + dist_bellman[u] - dist_bellman[v]
2536
+
2537
+ def dist_path(v):
2538
+ paths = {v: [v]}
2539
+ _dijkstra(G, v, new_weight, paths=paths)
2540
+ return paths
2541
+
2542
+ return {v: dist_path(v) for v in G}