okstra 0.107.2 → 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 (649) hide show
  1. package/package.json +1 -1
  2. package/runtime/BUILD.json +2 -2
  3. package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
  4. package/runtime/prompts/profiles/_common-contract.md +3 -2
  5. package/runtime/python/okstra_ctl/graphify_cmd.py +225 -0
  6. package/runtime/python/okstra_ctl/resolve_task_key.py +15 -9
  7. package/runtime/python/okstra_ctl/session.py +44 -0
  8. package/runtime/python/okstra_project/__init__.py +2 -0
  9. package/runtime/python/okstra_project/state.py +36 -0
  10. package/runtime/python/okstra_token_usage/claude.py +15 -9
  11. package/runtime/python/okstra_token_usage/cli.py +23 -0
  12. package/runtime/python/okstra_token_usage/collect.py +163 -4
  13. package/runtime/python/okstra_vendor/__init__.py +41 -0
  14. package/runtime/python/okstra_vendor/graphify/.vendored-version +1 -0
  15. package/runtime/python/okstra_vendor/graphify/__init__.py +28 -0
  16. package/runtime/python/okstra_vendor/graphify/__main__.py +1371 -0
  17. package/runtime/python/okstra_vendor/graphify/analyze.py +540 -0
  18. package/runtime/python/okstra_vendor/graphify/benchmark.py +129 -0
  19. package/runtime/python/okstra_vendor/graphify/build.py +107 -0
  20. package/runtime/python/okstra_vendor/graphify/cache.py +169 -0
  21. package/runtime/python/okstra_vendor/graphify/cluster.py +137 -0
  22. package/runtime/python/okstra_vendor/graphify/detect.py +510 -0
  23. package/runtime/python/okstra_vendor/graphify/export.py +1014 -0
  24. package/runtime/python/okstra_vendor/graphify/extract.py +3277 -0
  25. package/runtime/python/okstra_vendor/graphify/hooks.py +220 -0
  26. package/runtime/python/okstra_vendor/graphify/ingest.py +297 -0
  27. package/runtime/python/okstra_vendor/graphify/manifest.py +4 -0
  28. package/runtime/python/okstra_vendor/graphify/report.py +175 -0
  29. package/runtime/python/okstra_vendor/graphify/security.py +203 -0
  30. package/runtime/python/okstra_vendor/graphify/serve.py +373 -0
  31. package/runtime/python/okstra_vendor/graphify/skill-aider.md +1184 -0
  32. package/runtime/python/okstra_vendor/graphify/skill-claw.md +1184 -0
  33. package/runtime/python/okstra_vendor/graphify/skill-codex.md +1242 -0
  34. package/runtime/python/okstra_vendor/graphify/skill-copilot.md +1268 -0
  35. package/runtime/python/okstra_vendor/graphify/skill-droid.md +1239 -0
  36. package/runtime/python/okstra_vendor/graphify/skill-kiro.md +1183 -0
  37. package/runtime/python/okstra_vendor/graphify/skill-opencode.md +1238 -0
  38. package/runtime/python/okstra_vendor/graphify/skill-trae.md +1208 -0
  39. package/runtime/python/okstra_vendor/graphify/skill-vscode.md +253 -0
  40. package/runtime/python/okstra_vendor/graphify/skill-windows.md +1245 -0
  41. package/runtime/python/okstra_vendor/graphify/skill.md +1319 -0
  42. package/runtime/python/okstra_vendor/graphify/transcribe.py +182 -0
  43. package/runtime/python/okstra_vendor/graphify/validate.py +72 -0
  44. package/runtime/python/okstra_vendor/graphify/watch.py +188 -0
  45. package/runtime/python/okstra_vendor/graphify/wiki.py +214 -0
  46. package/runtime/python/okstra_vendor/networkx/__init__.py +62 -0
  47. package/runtime/python/okstra_vendor/networkx/algorithms/__init__.py +134 -0
  48. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/__init__.py +26 -0
  49. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clique.py +259 -0
  50. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clustering_coefficient.py +71 -0
  51. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/connectivity.py +412 -0
  52. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/density.py +396 -0
  53. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/distance_measures.py +150 -0
  54. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/dominating_set.py +149 -0
  55. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/kcomponents.py +369 -0
  56. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/matching.py +44 -0
  57. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/maxcut.py +143 -0
  58. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/ramsey.py +53 -0
  59. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/steinertree.py +265 -0
  60. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
  61. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +41 -0
  62. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +112 -0
  63. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +199 -0
  64. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +146 -0
  65. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +59 -0
  66. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +78 -0
  67. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +303 -0
  68. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +8 -0
  69. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +94 -0
  70. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +31 -0
  71. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +306 -0
  72. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +1014 -0
  73. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +274 -0
  74. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +68 -0
  75. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/traveling_salesman.py +1508 -0
  76. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/treewidth.py +255 -0
  77. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/vertex_cover.py +83 -0
  78. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/__init__.py +5 -0
  79. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/connectivity.py +122 -0
  80. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/correlation.py +302 -0
  81. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/mixing.py +255 -0
  82. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/neighbor_degree.py +160 -0
  83. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/pairs.py +127 -0
  84. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
  85. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +81 -0
  86. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +143 -0
  87. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +122 -0
  88. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +174 -0
  89. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +107 -0
  90. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +87 -0
  91. package/runtime/python/okstra_vendor/networkx/algorithms/asteroidal.py +164 -0
  92. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/__init__.py +88 -0
  93. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/basic.py +322 -0
  94. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/centrality.py +290 -0
  95. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/cluster.py +289 -0
  96. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/covering.py +57 -0
  97. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/edgelist.py +360 -0
  98. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/extendability.py +105 -0
  99. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/generators.py +603 -0
  100. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/link_analysis.py +316 -0
  101. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matching.py +590 -0
  102. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matrix.py +232 -0
  103. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/projection.py +526 -0
  104. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/redundancy.py +112 -0
  105. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/spectral.py +69 -0
  106. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
  107. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +125 -0
  108. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +192 -0
  109. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +84 -0
  110. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +33 -0
  111. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +240 -0
  112. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +334 -0
  113. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +407 -0
  114. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +218 -0
  115. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +327 -0
  116. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +138 -0
  117. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +409 -0
  118. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +35 -0
  119. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +80 -0
  120. package/runtime/python/okstra_vendor/networkx/algorithms/boundary.py +168 -0
  121. package/runtime/python/okstra_vendor/networkx/algorithms/bridges.py +205 -0
  122. package/runtime/python/okstra_vendor/networkx/algorithms/broadcasting.py +164 -0
  123. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/__init__.py +20 -0
  124. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness.py +591 -0
  125. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness_subset.py +236 -0
  126. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/closeness.py +282 -0
  127. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness.py +364 -0
  128. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness_subset.py +227 -0
  129. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_closeness.py +96 -0
  130. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/degree_alg.py +150 -0
  131. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/dispersion.py +107 -0
  132. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/eigenvector.py +357 -0
  133. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/flow_matrix.py +130 -0
  134. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/group.py +787 -0
  135. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/harmonic.py +88 -0
  136. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/katz.py +331 -0
  137. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/laplacian.py +150 -0
  138. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/load.py +200 -0
  139. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/percolation.py +128 -0
  140. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/reaching.py +209 -0
  141. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/second_order.py +141 -0
  142. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/subgraph_alg.py +361 -0
  143. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
  144. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +923 -0
  145. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +354 -0
  146. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +274 -0
  147. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +259 -0
  148. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +147 -0
  149. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +43 -0
  150. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +144 -0
  151. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +73 -0
  152. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +186 -0
  153. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +277 -0
  154. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +122 -0
  155. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +345 -0
  156. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +220 -0
  157. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +344 -0
  158. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +87 -0
  159. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +140 -0
  160. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +82 -0
  161. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +110 -0
  162. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +302 -0
  163. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +64 -0
  164. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/trophic.py +181 -0
  165. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/voterank_alg.py +95 -0
  166. package/runtime/python/okstra_vendor/networkx/algorithms/chains.py +172 -0
  167. package/runtime/python/okstra_vendor/networkx/algorithms/chordal.py +443 -0
  168. package/runtime/python/okstra_vendor/networkx/algorithms/clique.py +818 -0
  169. package/runtime/python/okstra_vendor/networkx/algorithms/cluster.py +732 -0
  170. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/__init__.py +4 -0
  171. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/equitable_coloring.py +505 -0
  172. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/greedy_coloring.py +565 -0
  173. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
  174. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +863 -0
  175. package/runtime/python/okstra_vendor/networkx/algorithms/communicability_alg.py +163 -0
  176. package/runtime/python/okstra_vendor/networkx/algorithms/community/__init__.py +28 -0
  177. package/runtime/python/okstra_vendor/networkx/algorithms/community/asyn_fluid.py +153 -0
  178. package/runtime/python/okstra_vendor/networkx/algorithms/community/bipartitions.py +354 -0
  179. package/runtime/python/okstra_vendor/networkx/algorithms/community/centrality.py +171 -0
  180. package/runtime/python/okstra_vendor/networkx/algorithms/community/community_utils.py +30 -0
  181. package/runtime/python/okstra_vendor/networkx/algorithms/community/divisive.py +216 -0
  182. package/runtime/python/okstra_vendor/networkx/algorithms/community/kclique.py +79 -0
  183. package/runtime/python/okstra_vendor/networkx/algorithms/community/label_propagation.py +338 -0
  184. package/runtime/python/okstra_vendor/networkx/algorithms/community/leiden.py +162 -0
  185. package/runtime/python/okstra_vendor/networkx/algorithms/community/local.py +220 -0
  186. package/runtime/python/okstra_vendor/networkx/algorithms/community/louvain.py +384 -0
  187. package/runtime/python/okstra_vendor/networkx/algorithms/community/lukes.py +227 -0
  188. package/runtime/python/okstra_vendor/networkx/algorithms/community/modularity_max.py +452 -0
  189. package/runtime/python/okstra_vendor/networkx/algorithms/community/quality.py +347 -0
  190. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
  191. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +147 -0
  192. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +157 -0
  193. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +85 -0
  194. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +106 -0
  195. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +91 -0
  196. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +241 -0
  197. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +138 -0
  198. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +76 -0
  199. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +264 -0
  200. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +152 -0
  201. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +340 -0
  202. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +139 -0
  203. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +26 -0
  204. package/runtime/python/okstra_vendor/networkx/algorithms/components/__init__.py +6 -0
  205. package/runtime/python/okstra_vendor/networkx/algorithms/components/attracting.py +115 -0
  206. package/runtime/python/okstra_vendor/networkx/algorithms/components/biconnected.py +394 -0
  207. package/runtime/python/okstra_vendor/networkx/algorithms/components/connected.py +282 -0
  208. package/runtime/python/okstra_vendor/networkx/algorithms/components/semiconnected.py +71 -0
  209. package/runtime/python/okstra_vendor/networkx/algorithms/components/strongly_connected.py +359 -0
  210. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
  211. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +70 -0
  212. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +248 -0
  213. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +138 -0
  214. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +55 -0
  215. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +193 -0
  216. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +96 -0
  217. package/runtime/python/okstra_vendor/networkx/algorithms/components/weakly_connected.py +196 -0
  218. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/__init__.py +11 -0
  219. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/connectivity.py +811 -0
  220. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/cuts.py +616 -0
  221. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/disjoint_paths.py +408 -0
  222. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_augmentation.py +1270 -0
  223. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_kcomponents.py +592 -0
  224. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcomponents.py +220 -0
  225. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcutsets.py +235 -0
  226. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/stoerwagner.py +152 -0
  227. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
  228. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +421 -0
  229. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +309 -0
  230. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +249 -0
  231. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +502 -0
  232. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +488 -0
  233. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +323 -0
  234. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +280 -0
  235. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +102 -0
  236. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/utils.py +88 -0
  237. package/runtime/python/okstra_vendor/networkx/algorithms/core.py +588 -0
  238. package/runtime/python/okstra_vendor/networkx/algorithms/covering.py +142 -0
  239. package/runtime/python/okstra_vendor/networkx/algorithms/cuts.py +416 -0
  240. package/runtime/python/okstra_vendor/networkx/algorithms/cycles.py +1234 -0
  241. package/runtime/python/okstra_vendor/networkx/algorithms/d_separation.py +677 -0
  242. package/runtime/python/okstra_vendor/networkx/algorithms/dag.py +1392 -0
  243. package/runtime/python/okstra_vendor/networkx/algorithms/distance_measures.py +1095 -0
  244. package/runtime/python/okstra_vendor/networkx/algorithms/distance_regular.py +272 -0
  245. package/runtime/python/okstra_vendor/networkx/algorithms/dominance.py +142 -0
  246. package/runtime/python/okstra_vendor/networkx/algorithms/dominating.py +268 -0
  247. package/runtime/python/okstra_vendor/networkx/algorithms/efficiency_measures.py +167 -0
  248. package/runtime/python/okstra_vendor/networkx/algorithms/euler.py +470 -0
  249. package/runtime/python/okstra_vendor/networkx/algorithms/flow/__init__.py +11 -0
  250. package/runtime/python/okstra_vendor/networkx/algorithms/flow/boykovkolmogorov.py +370 -0
  251. package/runtime/python/okstra_vendor/networkx/algorithms/flow/capacityscaling.py +407 -0
  252. package/runtime/python/okstra_vendor/networkx/algorithms/flow/dinitz_alg.py +238 -0
  253. package/runtime/python/okstra_vendor/networkx/algorithms/flow/edmondskarp.py +241 -0
  254. package/runtime/python/okstra_vendor/networkx/algorithms/flow/gomory_hu.py +178 -0
  255. package/runtime/python/okstra_vendor/networkx/algorithms/flow/maxflow.py +611 -0
  256. package/runtime/python/okstra_vendor/networkx/algorithms/flow/mincost.py +356 -0
  257. package/runtime/python/okstra_vendor/networkx/algorithms/flow/networksimplex.py +662 -0
  258. package/runtime/python/okstra_vendor/networkx/algorithms/flow/preflowpush.py +425 -0
  259. package/runtime/python/okstra_vendor/networkx/algorithms/flow/shortestaugmentingpath.py +300 -0
  260. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
  261. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
  262. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
  263. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
  264. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +128 -0
  265. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +573 -0
  266. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +155 -0
  267. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +475 -0
  268. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +481 -0
  269. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
  270. package/runtime/python/okstra_vendor/networkx/algorithms/flow/utils.py +194 -0
  271. package/runtime/python/okstra_vendor/networkx/algorithms/graph_hashing.py +435 -0
  272. package/runtime/python/okstra_vendor/networkx/algorithms/graphical.py +483 -0
  273. package/runtime/python/okstra_vendor/networkx/algorithms/hierarchy.py +57 -0
  274. package/runtime/python/okstra_vendor/networkx/algorithms/hybrid.py +196 -0
  275. package/runtime/python/okstra_vendor/networkx/algorithms/isolate.py +107 -0
  276. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/__init__.py +7 -0
  277. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/ismags.py +1306 -0
  278. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorph.py +336 -0
  279. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorphvf2.py +1262 -0
  280. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/matchhelpers.py +352 -0
  281. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/temporalisomorphvf2.py +308 -0
  282. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
  283. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
  284. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
  285. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
  286. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
  287. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +719 -0
  288. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +103 -0
  289. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +490 -0
  290. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +64 -0
  291. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +212 -0
  292. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +202 -0
  293. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +1655 -0
  294. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +3118 -0
  295. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +196 -0
  296. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tree_isomorphism.py +264 -0
  297. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2pp.py +1102 -0
  298. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2userfunc.py +192 -0
  299. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/__init__.py +2 -0
  300. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/hits_alg.py +337 -0
  301. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/pagerank_alg.py +498 -0
  302. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
  303. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +77 -0
  304. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +213 -0
  305. package/runtime/python/okstra_vendor/networkx/algorithms/link_prediction.py +687 -0
  306. package/runtime/python/okstra_vendor/networkx/algorithms/lowest_common_ancestors.py +280 -0
  307. package/runtime/python/okstra_vendor/networkx/algorithms/matching.py +1148 -0
  308. package/runtime/python/okstra_vendor/networkx/algorithms/minors/__init__.py +27 -0
  309. package/runtime/python/okstra_vendor/networkx/algorithms/minors/contraction.py +738 -0
  310. package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +544 -0
  311. package/runtime/python/okstra_vendor/networkx/algorithms/mis.py +78 -0
  312. package/runtime/python/okstra_vendor/networkx/algorithms/moral.py +59 -0
  313. package/runtime/python/okstra_vendor/networkx/algorithms/node_classification.py +219 -0
  314. package/runtime/python/okstra_vendor/networkx/algorithms/non_randomness.py +155 -0
  315. package/runtime/python/okstra_vendor/networkx/algorithms/operators/__init__.py +4 -0
  316. package/runtime/python/okstra_vendor/networkx/algorithms/operators/all.py +324 -0
  317. package/runtime/python/okstra_vendor/networkx/algorithms/operators/binary.py +468 -0
  318. package/runtime/python/okstra_vendor/networkx/algorithms/operators/product.py +633 -0
  319. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
  320. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +328 -0
  321. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +451 -0
  322. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +491 -0
  323. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +55 -0
  324. package/runtime/python/okstra_vendor/networkx/algorithms/operators/unary.py +77 -0
  325. package/runtime/python/okstra_vendor/networkx/algorithms/perfect_graph.py +73 -0
  326. package/runtime/python/okstra_vendor/networkx/algorithms/planar_drawing.py +464 -0
  327. package/runtime/python/okstra_vendor/networkx/algorithms/planarity.py +1463 -0
  328. package/runtime/python/okstra_vendor/networkx/algorithms/polynomials.py +306 -0
  329. package/runtime/python/okstra_vendor/networkx/algorithms/reciprocity.py +98 -0
  330. package/runtime/python/okstra_vendor/networkx/algorithms/regular.py +167 -0
  331. package/runtime/python/okstra_vendor/networkx/algorithms/richclub.py +138 -0
  332. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/__init__.py +5 -0
  333. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/astar.py +239 -0
  334. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/dense.py +264 -0
  335. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/generic.py +716 -0
  336. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
  337. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +254 -0
  338. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +212 -0
  339. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +88 -0
  340. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +511 -0
  341. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +149 -0
  342. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +983 -0
  343. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/unweighted.py +625 -0
  344. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/weighted.py +2542 -0
  345. package/runtime/python/okstra_vendor/networkx/algorithms/similarity.py +2107 -0
  346. package/runtime/python/okstra_vendor/networkx/algorithms/simple_paths.py +966 -0
  347. package/runtime/python/okstra_vendor/networkx/algorithms/smallworld.py +404 -0
  348. package/runtime/python/okstra_vendor/networkx/algorithms/smetric.py +30 -0
  349. package/runtime/python/okstra_vendor/networkx/algorithms/sparsifiers.py +296 -0
  350. package/runtime/python/okstra_vendor/networkx/algorithms/structuralholes.py +374 -0
  351. package/runtime/python/okstra_vendor/networkx/algorithms/summarization.py +564 -0
  352. package/runtime/python/okstra_vendor/networkx/algorithms/swap.py +406 -0
  353. package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
  354. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +23 -0
  355. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +154 -0
  356. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +144 -0
  357. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +109 -0
  358. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +136 -0
  359. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +129 -0
  360. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +300 -0
  361. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +678 -0
  362. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +80 -0
  363. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +266 -0
  364. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +85 -0
  365. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +171 -0
  366. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +984 -0
  367. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +340 -0
  368. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +835 -0
  369. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +831 -0
  370. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +85 -0
  371. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +299 -0
  372. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +115 -0
  373. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +58 -0
  374. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +314 -0
  375. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +872 -0
  376. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +163 -0
  377. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +46 -0
  378. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +24 -0
  379. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +26 -0
  380. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +615 -0
  381. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +459 -0
  382. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +556 -0
  383. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +179 -0
  384. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +62 -0
  385. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +15 -0
  386. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +140 -0
  387. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +60 -0
  388. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +27 -0
  389. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +274 -0
  390. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +556 -0
  391. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +57 -0
  392. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +37 -0
  393. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +88 -0
  394. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +149 -0
  395. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +1158 -0
  396. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +803 -0
  397. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +76 -0
  398. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +8 -0
  399. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +138 -0
  400. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +191 -0
  401. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +642 -0
  402. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +179 -0
  403. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +270 -0
  404. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +431 -0
  405. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +161 -0
  406. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +248 -0
  407. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +41 -0
  408. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +103 -0
  409. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +54 -0
  410. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +157 -0
  411. package/runtime/python/okstra_vendor/networkx/algorithms/threshold.py +981 -0
  412. package/runtime/python/okstra_vendor/networkx/algorithms/time_dependent.py +142 -0
  413. package/runtime/python/okstra_vendor/networkx/algorithms/tournament.py +406 -0
  414. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/__init__.py +5 -0
  415. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/beamsearch.py +90 -0
  416. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/breadth_first_search.py +576 -0
  417. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/depth_first_search.py +529 -0
  418. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgebfs.py +185 -0
  419. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgedfs.py +182 -0
  420. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
  421. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +25 -0
  422. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +203 -0
  423. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +307 -0
  424. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +147 -0
  425. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +131 -0
  426. package/runtime/python/okstra_vendor/networkx/algorithms/tree/__init__.py +7 -0
  427. package/runtime/python/okstra_vendor/networkx/algorithms/tree/branchings.py +1042 -0
  428. package/runtime/python/okstra_vendor/networkx/algorithms/tree/coding.py +413 -0
  429. package/runtime/python/okstra_vendor/networkx/algorithms/tree/decomposition.py +88 -0
  430. package/runtime/python/okstra_vendor/networkx/algorithms/tree/distance_measures.py +219 -0
  431. package/runtime/python/okstra_vendor/networkx/algorithms/tree/mst.py +1281 -0
  432. package/runtime/python/okstra_vendor/networkx/algorithms/tree/operations.py +106 -0
  433. package/runtime/python/okstra_vendor/networkx/algorithms/tree/recognition.py +273 -0
  434. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
  435. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +624 -0
  436. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +114 -0
  437. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +79 -0
  438. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +99 -0
  439. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +934 -0
  440. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +53 -0
  441. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +174 -0
  442. package/runtime/python/okstra_vendor/networkx/algorithms/triads.py +500 -0
  443. package/runtime/python/okstra_vendor/networkx/algorithms/vitality.py +76 -0
  444. package/runtime/python/okstra_vendor/networkx/algorithms/voronoi.py +86 -0
  445. package/runtime/python/okstra_vendor/networkx/algorithms/walks.py +77 -0
  446. package/runtime/python/okstra_vendor/networkx/algorithms/wiener.py +278 -0
  447. package/runtime/python/okstra_vendor/networkx/classes/__init__.py +13 -0
  448. package/runtime/python/okstra_vendor/networkx/classes/coreviews.py +435 -0
  449. package/runtime/python/okstra_vendor/networkx/classes/digraph.py +1363 -0
  450. package/runtime/python/okstra_vendor/networkx/classes/filters.py +95 -0
  451. package/runtime/python/okstra_vendor/networkx/classes/function.py +1549 -0
  452. package/runtime/python/okstra_vendor/networkx/classes/graph.py +2082 -0
  453. package/runtime/python/okstra_vendor/networkx/classes/graphviews.py +269 -0
  454. package/runtime/python/okstra_vendor/networkx/classes/multidigraph.py +977 -0
  455. package/runtime/python/okstra_vendor/networkx/classes/multigraph.py +1294 -0
  456. package/runtime/python/okstra_vendor/networkx/classes/reportviews.py +1447 -0
  457. package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
  458. package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +192 -0
  459. package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +476 -0
  460. package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +362 -0
  461. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +331 -0
  462. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +110 -0
  463. package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +177 -0
  464. package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +1045 -0
  465. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +950 -0
  466. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +12 -0
  467. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +349 -0
  468. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +459 -0
  469. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +528 -0
  470. package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +1421 -0
  471. package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +131 -0
  472. package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +371 -0
  473. package/runtime/python/okstra_vendor/networkx/conftest.py +261 -0
  474. package/runtime/python/okstra_vendor/networkx/convert.py +502 -0
  475. package/runtime/python/okstra_vendor/networkx/convert_matrix.py +1314 -0
  476. package/runtime/python/okstra_vendor/networkx/drawing/__init__.py +7 -0
  477. package/runtime/python/okstra_vendor/networkx/drawing/layout.py +2036 -0
  478. package/runtime/python/okstra_vendor/networkx/drawing/nx_agraph.py +470 -0
  479. package/runtime/python/okstra_vendor/networkx/drawing/nx_latex.py +570 -0
  480. package/runtime/python/okstra_vendor/networkx/drawing/nx_pydot.py +361 -0
  481. package/runtime/python/okstra_vendor/networkx/drawing/nx_pylab.py +2978 -0
  482. package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
  483. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
  484. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
  485. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
  486. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
  487. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
  488. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
  489. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +237 -0
  490. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +229 -0
  491. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +285 -0
  492. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +631 -0
  493. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +146 -0
  494. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +1582 -0
  495. package/runtime/python/okstra_vendor/networkx/exception.py +131 -0
  496. package/runtime/python/okstra_vendor/networkx/generators/__init__.py +34 -0
  497. package/runtime/python/okstra_vendor/networkx/generators/atlas.dat.gz +0 -0
  498. package/runtime/python/okstra_vendor/networkx/generators/atlas.py +227 -0
  499. package/runtime/python/okstra_vendor/networkx/generators/classic.py +1091 -0
  500. package/runtime/python/okstra_vendor/networkx/generators/cographs.py +68 -0
  501. package/runtime/python/okstra_vendor/networkx/generators/community.py +1070 -0
  502. package/runtime/python/okstra_vendor/networkx/generators/degree_seq.py +886 -0
  503. package/runtime/python/okstra_vendor/networkx/generators/directed.py +572 -0
  504. package/runtime/python/okstra_vendor/networkx/generators/duplication.py +174 -0
  505. package/runtime/python/okstra_vendor/networkx/generators/ego.py +66 -0
  506. package/runtime/python/okstra_vendor/networkx/generators/expanders.py +499 -0
  507. package/runtime/python/okstra_vendor/networkx/generators/geometric.py +1037 -0
  508. package/runtime/python/okstra_vendor/networkx/generators/harary_graph.py +163 -0
  509. package/runtime/python/okstra_vendor/networkx/generators/internet_as_graphs.py +443 -0
  510. package/runtime/python/okstra_vendor/networkx/generators/intersection.py +125 -0
  511. package/runtime/python/okstra_vendor/networkx/generators/interval_graph.py +70 -0
  512. package/runtime/python/okstra_vendor/networkx/generators/joint_degree_seq.py +664 -0
  513. package/runtime/python/okstra_vendor/networkx/generators/lattice.py +405 -0
  514. package/runtime/python/okstra_vendor/networkx/generators/line.py +501 -0
  515. package/runtime/python/okstra_vendor/networkx/generators/mycielski.py +110 -0
  516. package/runtime/python/okstra_vendor/networkx/generators/nonisomorphic_trees.py +259 -0
  517. package/runtime/python/okstra_vendor/networkx/generators/random_clustered.py +117 -0
  518. package/runtime/python/okstra_vendor/networkx/generators/random_graphs.py +1416 -0
  519. package/runtime/python/okstra_vendor/networkx/generators/small.py +1070 -0
  520. package/runtime/python/okstra_vendor/networkx/generators/social.py +554 -0
  521. package/runtime/python/okstra_vendor/networkx/generators/spectral_graph_forge.py +120 -0
  522. package/runtime/python/okstra_vendor/networkx/generators/stochastic.py +54 -0
  523. package/runtime/python/okstra_vendor/networkx/generators/sudoku.py +131 -0
  524. package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
  525. package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +75 -0
  526. package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +642 -0
  527. package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +20 -0
  528. package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +362 -0
  529. package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +224 -0
  530. package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +189 -0
  531. package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +103 -0
  532. package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +39 -0
  533. package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +182 -0
  534. package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +488 -0
  535. package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +133 -0
  536. package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +221 -0
  537. package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +28 -0
  538. package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +144 -0
  539. package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +125 -0
  540. package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +264 -0
  541. package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +316 -0
  542. package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +30 -0
  543. package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +82 -0
  544. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +33 -0
  545. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +495 -0
  546. package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +220 -0
  547. package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +49 -0
  548. package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +72 -0
  549. package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +92 -0
  550. package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +64 -0
  551. package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +195 -0
  552. package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +15 -0
  553. package/runtime/python/okstra_vendor/networkx/generators/time_series.py +74 -0
  554. package/runtime/python/okstra_vendor/networkx/generators/trees.py +1070 -0
  555. package/runtime/python/okstra_vendor/networkx/generators/triads.py +94 -0
  556. package/runtime/python/okstra_vendor/networkx/lazy_imports.py +188 -0
  557. package/runtime/python/okstra_vendor/networkx/linalg/__init__.py +13 -0
  558. package/runtime/python/okstra_vendor/networkx/linalg/algebraicconnectivity.py +650 -0
  559. package/runtime/python/okstra_vendor/networkx/linalg/attrmatrix.py +466 -0
  560. package/runtime/python/okstra_vendor/networkx/linalg/bethehessianmatrix.py +77 -0
  561. package/runtime/python/okstra_vendor/networkx/linalg/graphmatrix.py +168 -0
  562. package/runtime/python/okstra_vendor/networkx/linalg/laplacianmatrix.py +512 -0
  563. package/runtime/python/okstra_vendor/networkx/linalg/modularitymatrix.py +166 -0
  564. package/runtime/python/okstra_vendor/networkx/linalg/spectrum.py +186 -0
  565. package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
  566. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +400 -0
  567. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +108 -0
  568. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +40 -0
  569. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +275 -0
  570. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +334 -0
  571. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +86 -0
  572. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +70 -0
  573. package/runtime/python/okstra_vendor/networkx/readwrite/__init__.py +17 -0
  574. package/runtime/python/okstra_vendor/networkx/readwrite/adjlist.py +330 -0
  575. package/runtime/python/okstra_vendor/networkx/readwrite/edgelist.py +489 -0
  576. package/runtime/python/okstra_vendor/networkx/readwrite/gexf.py +1084 -0
  577. package/runtime/python/okstra_vendor/networkx/readwrite/gml.py +879 -0
  578. package/runtime/python/okstra_vendor/networkx/readwrite/graph6.py +427 -0
  579. package/runtime/python/okstra_vendor/networkx/readwrite/graphml.py +1053 -0
  580. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/__init__.py +19 -0
  581. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/adjacency.py +156 -0
  582. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/cytoscape.py +190 -0
  583. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/node_link.py +261 -0
  584. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
  585. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +78 -0
  586. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +78 -0
  587. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +109 -0
  588. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +48 -0
  589. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tree.py +137 -0
  590. package/runtime/python/okstra_vendor/networkx/readwrite/leda.py +108 -0
  591. package/runtime/python/okstra_vendor/networkx/readwrite/multiline_adjlist.py +393 -0
  592. package/runtime/python/okstra_vendor/networkx/readwrite/p2g.py +113 -0
  593. package/runtime/python/okstra_vendor/networkx/readwrite/pajek.py +286 -0
  594. package/runtime/python/okstra_vendor/networkx/readwrite/sparse6.py +379 -0
  595. package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
  596. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +354 -0
  597. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +318 -0
  598. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +612 -0
  599. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +744 -0
  600. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +181 -0
  601. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +1531 -0
  602. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +30 -0
  603. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +63 -0
  604. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +128 -0
  605. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +166 -0
  606. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +1742 -0
  607. package/runtime/python/okstra_vendor/networkx/readwrite/text.py +851 -0
  608. package/runtime/python/okstra_vendor/networkx/relabel.py +285 -0
  609. package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
  610. package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +248 -0
  611. package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +321 -0
  612. package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +531 -0
  613. package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +349 -0
  614. package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +281 -0
  615. package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +40 -0
  616. package/runtime/python/okstra_vendor/networkx/tests/test_import.py +11 -0
  617. package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +96 -0
  618. package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +349 -0
  619. package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +8 -0
  620. package/runtime/python/okstra_vendor/networkx/utils/__init__.py +8 -0
  621. package/runtime/python/okstra_vendor/networkx/utils/backends.py +2171 -0
  622. package/runtime/python/okstra_vendor/networkx/utils/configs.py +396 -0
  623. package/runtime/python/okstra_vendor/networkx/utils/decorators.py +1233 -0
  624. package/runtime/python/okstra_vendor/networkx/utils/heaps.py +338 -0
  625. package/runtime/python/okstra_vendor/networkx/utils/mapped_queue.py +297 -0
  626. package/runtime/python/okstra_vendor/networkx/utils/misc.py +703 -0
  627. package/runtime/python/okstra_vendor/networkx/utils/random_sequence.py +198 -0
  628. package/runtime/python/okstra_vendor/networkx/utils/rcm.py +159 -0
  629. package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
  630. package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +11 -0
  631. package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +225 -0
  632. package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +263 -0
  633. package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +510 -0
  634. package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +131 -0
  635. package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +268 -0
  636. package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +393 -0
  637. package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +53 -0
  638. package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +63 -0
  639. package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +55 -0
  640. package/runtime/python/okstra_vendor/networkx/utils/union_find.py +106 -0
  641. package/runtime/skills/okstra-graphify/SKILL.md +161 -0
  642. package/runtime/skills/okstra-inspect/SKILL.md +17 -9
  643. package/runtime/templates/reports/settings.template.json +4 -0
  644. package/runtime/validators/forbidden_actions.py +8 -2
  645. package/runtime/validators/validate_session_conformance.py +26 -5
  646. package/src/cli-registry.mjs +7 -0
  647. package/src/commands/graphify.mjs +32 -0
  648. package/src/commands/lifecycle/doctor.mjs +9 -0
  649. package/src/lib/skill-catalog.mjs +1 -0
@@ -0,0 +1,1148 @@
1
+ """Functions for computing and verifying matchings in a graph."""
2
+
3
+ from itertools import combinations, repeat
4
+
5
+ import networkx as nx
6
+ from networkx.utils import not_implemented_for
7
+
8
+ __all__ = [
9
+ "is_matching",
10
+ "is_maximal_matching",
11
+ "is_perfect_matching",
12
+ "max_weight_matching",
13
+ "min_weight_matching",
14
+ "maximal_matching",
15
+ ]
16
+
17
+
18
+ @not_implemented_for("multigraph")
19
+ @not_implemented_for("directed")
20
+ @nx._dispatchable
21
+ def maximal_matching(G):
22
+ r"""Find a maximal matching in the graph.
23
+
24
+ A matching is a subset of edges in which no node occurs more than once.
25
+ A maximal matching cannot add more edges and still be a matching.
26
+
27
+ Parameters
28
+ ----------
29
+ G : NetworkX graph
30
+ Undirected graph
31
+
32
+ Returns
33
+ -------
34
+ matching : set
35
+ A maximal matching of the graph.
36
+
37
+ Examples
38
+ --------
39
+ >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)])
40
+ >>> sorted(nx.maximal_matching(G))
41
+ [(1, 2), (3, 5)]
42
+
43
+ Notes
44
+ -----
45
+ The algorithm greedily selects a maximal matching M of the graph G
46
+ (i.e. no superset of M exists). It runs in $O(|E|)$ time.
47
+ """
48
+ matching = set()
49
+ nodes = set()
50
+ for edge in G.edges():
51
+ # If the edge isn't covered, add it to the matching
52
+ # then remove neighborhood of u and v from consideration.
53
+ u, v = edge
54
+ if u not in nodes and v not in nodes and u != v:
55
+ matching.add(edge)
56
+ nodes.update(edge)
57
+ return matching
58
+
59
+
60
+ def matching_dict_to_set(matching):
61
+ """Converts matching dict format to matching set format
62
+
63
+ Converts a dictionary representing a matching (as returned by
64
+ :func:`max_weight_matching`) to a set representing a matching (as
65
+ returned by :func:`maximal_matching`).
66
+
67
+ In the definition of maximal matching adopted by NetworkX,
68
+ self-loops are not allowed, so the provided dictionary is expected
69
+ to never have any mapping from a key to itself. However, the
70
+ dictionary is expected to have mirrored key/value pairs, for
71
+ example, key ``u`` with value ``v`` and key ``v`` with value ``u``.
72
+
73
+ """
74
+ edges = set()
75
+ for edge in matching.items():
76
+ u, v = edge
77
+ if (v, u) in edges or edge in edges:
78
+ continue
79
+ if u == v:
80
+ raise nx.NetworkXError(f"Selfloops cannot appear in matchings {edge}")
81
+ edges.add(edge)
82
+ return edges
83
+
84
+
85
+ @nx._dispatchable
86
+ def is_matching(G, matching):
87
+ """Return True if ``matching`` is a valid matching of ``G``
88
+
89
+ A *matching* in a graph is a set of edges in which no two distinct
90
+ edges share a common endpoint. Each node is incident to at most one
91
+ edge in the matching. The edges are said to be independent.
92
+
93
+ Parameters
94
+ ----------
95
+ G : NetworkX graph
96
+
97
+ matching : dict or set
98
+ A dictionary or set representing a matching. If a dictionary, it
99
+ must have ``matching[u] == v`` and ``matching[v] == u`` for each
100
+ edge ``(u, v)`` in the matching. If a set, it must have elements
101
+ of the form ``(u, v)``, where ``(u, v)`` is an edge in the
102
+ matching.
103
+
104
+ Returns
105
+ -------
106
+ bool
107
+ Whether the given set or dictionary represents a valid matching
108
+ in the graph.
109
+
110
+ Raises
111
+ ------
112
+ NetworkXError
113
+ If the proposed matching has an edge to a node not in G.
114
+ Or if the matching is not a collection of 2-tuple edges.
115
+
116
+ Examples
117
+ --------
118
+ >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)])
119
+ >>> nx.is_maximal_matching(G, {1: 3, 2: 4}) # using dict to represent matching
120
+ True
121
+
122
+ >>> nx.is_matching(G, {(1, 3), (2, 4)}) # using set to represent matching
123
+ True
124
+
125
+ """
126
+ if isinstance(matching, dict):
127
+ matching = matching_dict_to_set(matching)
128
+
129
+ nodes = set()
130
+ for edge in matching:
131
+ if len(edge) != 2:
132
+ raise nx.NetworkXError(f"matching has non-2-tuple edge {edge}")
133
+ u, v = edge
134
+ if u not in G or v not in G:
135
+ raise nx.NetworkXError(f"matching contains edge {edge} with node not in G")
136
+ if u == v:
137
+ return False
138
+ if not G.has_edge(u, v):
139
+ return False
140
+ if u in nodes or v in nodes:
141
+ return False
142
+ nodes.update(edge)
143
+ return True
144
+
145
+
146
+ @nx._dispatchable
147
+ def is_maximal_matching(G, matching):
148
+ """Return True if ``matching`` is a maximal matching of ``G``
149
+
150
+ A *maximal matching* in a graph is a matching in which adding any
151
+ edge would cause the set to no longer be a valid matching.
152
+
153
+ Parameters
154
+ ----------
155
+ G : NetworkX graph
156
+
157
+ matching : dict or set
158
+ A dictionary or set representing a matching. If a dictionary, it
159
+ must have ``matching[u] == v`` and ``matching[v] == u`` for each
160
+ edge ``(u, v)`` in the matching. If a set, it must have elements
161
+ of the form ``(u, v)``, where ``(u, v)`` is an edge in the
162
+ matching.
163
+
164
+ Returns
165
+ -------
166
+ bool
167
+ Whether the given set or dictionary represents a valid maximal
168
+ matching in the graph.
169
+
170
+ Examples
171
+ --------
172
+ >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (3, 4), (3, 5)])
173
+ >>> nx.is_maximal_matching(G, {(1, 2), (3, 4)})
174
+ True
175
+
176
+ """
177
+ if isinstance(matching, dict):
178
+ matching = matching_dict_to_set(matching)
179
+ # If the given set is not a matching, then it is not a maximal matching.
180
+ edges = set()
181
+ nodes = set()
182
+ for edge in matching:
183
+ if len(edge) != 2:
184
+ raise nx.NetworkXError(f"matching has non-2-tuple edge {edge}")
185
+ u, v = edge
186
+ if u not in G or v not in G:
187
+ raise nx.NetworkXError(f"matching contains edge {edge} with node not in G")
188
+ if u == v:
189
+ return False
190
+ if not G.has_edge(u, v):
191
+ return False
192
+ if u in nodes or v in nodes:
193
+ return False
194
+ nodes.update(edge)
195
+ edges.add(edge)
196
+ edges.add((v, u))
197
+ # A matching is maximal if adding any new edge from G to it
198
+ # causes the resulting set to match some node twice.
199
+ # Be careful to check for adding selfloops
200
+ for u, v in G.edges:
201
+ if (u, v) not in edges:
202
+ # could add edge (u, v) to edges and have a bigger matching
203
+ if u not in nodes and v not in nodes and u != v:
204
+ return False
205
+ return True
206
+
207
+
208
+ @nx._dispatchable
209
+ def is_perfect_matching(G, matching):
210
+ """Return True if ``matching`` is a perfect matching for ``G``
211
+
212
+ A *perfect matching* in a graph is a matching in which exactly one edge
213
+ is incident upon each vertex.
214
+
215
+ Parameters
216
+ ----------
217
+ G : NetworkX graph
218
+
219
+ matching : dict or set
220
+ A dictionary or set representing a matching. If a dictionary, it
221
+ must have ``matching[u] == v`` and ``matching[v] == u`` for each
222
+ edge ``(u, v)`` in the matching. If a set, it must have elements
223
+ of the form ``(u, v)``, where ``(u, v)`` is an edge in the
224
+ matching.
225
+
226
+ Returns
227
+ -------
228
+ bool
229
+ Whether the given set or dictionary represents a valid perfect
230
+ matching in the graph.
231
+
232
+ Examples
233
+ --------
234
+ >>> G = nx.Graph([(1, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5), (4, 6)])
235
+ >>> my_match = {1: 2, 3: 5, 4: 6}
236
+ >>> nx.is_perfect_matching(G, my_match)
237
+ True
238
+
239
+ """
240
+ if isinstance(matching, dict):
241
+ matching = matching_dict_to_set(matching)
242
+
243
+ nodes = set()
244
+ for edge in matching:
245
+ if len(edge) != 2:
246
+ raise nx.NetworkXError(f"matching has non-2-tuple edge {edge}")
247
+ u, v = edge
248
+ if u not in G or v not in G:
249
+ raise nx.NetworkXError(f"matching contains edge {edge} with node not in G")
250
+ if u == v:
251
+ return False
252
+ if not G.has_edge(u, v):
253
+ return False
254
+ if u in nodes or v in nodes:
255
+ return False
256
+ nodes.update(edge)
257
+ return len(nodes) == len(G)
258
+
259
+
260
+ @not_implemented_for("multigraph")
261
+ @not_implemented_for("directed")
262
+ @nx._dispatchable(edge_attrs="weight")
263
+ def min_weight_matching(G, weight="weight"):
264
+ """Compute a minimum-weight maximum-cardinality matching of `G`.
265
+
266
+ The minimum-weight maximum-cardinality matching is the matching
267
+ that has the minimum weight among all maximum-cardinality matchings.
268
+
269
+ Use the maximum-weight algorithm with edge weights subtracted
270
+ from the maximum weight of all edges.
271
+
272
+ A matching is a subset of edges in which no node occurs more than once.
273
+ The weight of a matching is the sum of the weights of its edges.
274
+ A maximal matching cannot add more edges and still be a matching.
275
+ The cardinality of a matching is the number of matched edges.
276
+
277
+ This method replaces the edge weights with 1 plus the maximum edge weight
278
+ minus the original edge weight.
279
+
280
+ new_weight = (max_weight + 1) - edge_weight
281
+
282
+ then runs :func:`max_weight_matching` with the new weights.
283
+ The max weight matching with these new weights corresponds
284
+ to the min weight matching using the original weights.
285
+ Adding 1 to the max edge weight keeps all edge weights positive
286
+ and as integers if they started as integers.
287
+
288
+ Read the documentation of `max_weight_matching` for more information.
289
+
290
+ Parameters
291
+ ----------
292
+ G : NetworkX graph
293
+ Undirected graph
294
+
295
+ weight: string, optional (default='weight')
296
+ Edge data key corresponding to the edge weight.
297
+ If key not found, uses 1 as weight.
298
+
299
+ Returns
300
+ -------
301
+ matching : set
302
+ A minimal weight matching of the graph.
303
+
304
+ See Also
305
+ --------
306
+ max_weight_matching
307
+ """
308
+ if len(G.edges) == 0:
309
+ return max_weight_matching(G, maxcardinality=True, weight=weight)
310
+ G_edges = G.edges(data=weight, default=1)
311
+ max_weight = 1 + max(w for _, _, w in G_edges)
312
+ InvG = nx.Graph()
313
+ edges = ((u, v, max_weight - w) for u, v, w in G_edges)
314
+ InvG.add_weighted_edges_from(edges, weight=weight)
315
+ return max_weight_matching(InvG, maxcardinality=True, weight=weight)
316
+
317
+
318
+ @not_implemented_for("multigraph")
319
+ @not_implemented_for("directed")
320
+ @nx._dispatchable(edge_attrs="weight")
321
+ def max_weight_matching(G, maxcardinality=False, weight="weight"):
322
+ """Compute a maximum-weighted matching of G.
323
+
324
+ A matching is a subset of edges in which no node occurs more than once.
325
+ The weight of a matching is the sum of the weights of its edges.
326
+ A maximal matching cannot add more edges and still be a matching.
327
+ The cardinality of a matching is the number of matched edges.
328
+
329
+ Parameters
330
+ ----------
331
+ G : NetworkX graph
332
+ Undirected graph
333
+
334
+ maxcardinality: bool, optional (default=False)
335
+ If maxcardinality is True, compute the maximum-cardinality matching
336
+ with maximum weight among all maximum-cardinality matchings.
337
+
338
+ weight: string, optional (default='weight')
339
+ Edge data key corresponding to the edge weight.
340
+ If key not found, uses 1 as weight.
341
+
342
+
343
+ Returns
344
+ -------
345
+ matching : set
346
+ A maximal matching of the graph.
347
+
348
+ Examples
349
+ --------
350
+ >>> G = nx.Graph()
351
+ >>> edges = [(1, 2, 6), (1, 3, 2), (2, 3, 1), (2, 4, 7), (3, 5, 9), (4, 5, 3)]
352
+ >>> G.add_weighted_edges_from(edges)
353
+ >>> sorted(nx.max_weight_matching(G))
354
+ [(2, 4), (5, 3)]
355
+
356
+ Notes
357
+ -----
358
+ If G has edges with weight attributes the edge data are used as
359
+ weight values else the weights are assumed to be 1.
360
+
361
+ This function takes time O(number_of_nodes ** 3).
362
+
363
+ If all edge weights are integers, the algorithm uses only integer
364
+ computations. If floating point weights are used, the algorithm
365
+ could return a slightly suboptimal matching due to numeric
366
+ precision errors.
367
+
368
+ This method is based on the "blossom" method for finding augmenting
369
+ paths and the "primal-dual" method for finding a matching of maximum
370
+ weight, both methods invented by Jack Edmonds [1]_.
371
+
372
+ Bipartite graphs can also be matched using the functions present in
373
+ :mod:`networkx.algorithms.bipartite.matching`.
374
+
375
+ References
376
+ ----------
377
+ .. [1] "Efficient Algorithms for Finding Maximum Matching in Graphs",
378
+ Zvi Galil, ACM Computing Surveys, 1986.
379
+ """
380
+ #
381
+ # The algorithm is taken from "Efficient Algorithms for Finding Maximum
382
+ # Matching in Graphs" by Zvi Galil, ACM Computing Surveys, 1986.
383
+ # It is based on the "blossom" method for finding augmenting paths and
384
+ # the "primal-dual" method for finding a matching of maximum weight, both
385
+ # methods invented by Jack Edmonds.
386
+ #
387
+ # A C program for maximum weight matching by Ed Rothberg was used
388
+ # extensively to validate this new code.
389
+ #
390
+ # Many terms used in the code comments are explained in the paper
391
+ # by Galil. You will probably need the paper to make sense of this code.
392
+ #
393
+
394
+ class NoNode:
395
+ """Dummy value which is different from any node."""
396
+
397
+ class Blossom:
398
+ """Representation of a non-trivial blossom or sub-blossom."""
399
+
400
+ __slots__ = ["childs", "edges", "mybestedges"]
401
+
402
+ # b.childs is an ordered list of b's sub-blossoms, starting with
403
+ # the base and going round the blossom.
404
+
405
+ # b.edges is the list of b's connecting edges, such that
406
+ # b.edges[i] = (v, w) where v is a vertex in b.childs[i]
407
+ # and w is a vertex in b.childs[wrap(i+1)].
408
+
409
+ # If b is a top-level S-blossom,
410
+ # b.mybestedges is a list of least-slack edges to neighboring
411
+ # S-blossoms, or None if no such list has been computed yet.
412
+ # This is used for efficient computation of delta3.
413
+
414
+ # Generate the blossom's leaf vertices.
415
+ def leaves(self):
416
+ stack = [*self.childs]
417
+ while stack:
418
+ t = stack.pop()
419
+ if isinstance(t, Blossom):
420
+ stack.extend(t.childs)
421
+ else:
422
+ yield t
423
+
424
+ # Get a list of vertices.
425
+ gnodes = list(G)
426
+ if not gnodes:
427
+ return set() # don't bother with empty graphs
428
+
429
+ # Find the maximum edge weight.
430
+ maxweight = 0
431
+ allinteger = True
432
+ for i, j, d in G.edges(data=True):
433
+ wt = d.get(weight, 1)
434
+ if i != j and wt > maxweight:
435
+ maxweight = wt
436
+ allinteger = allinteger and (str(type(wt)).split("'")[1] in ("int", "long"))
437
+
438
+ # If v is a matched vertex, mate[v] is its partner vertex.
439
+ # If v is a single vertex, v does not occur as a key in mate.
440
+ # Initially all vertices are single; updated during augmentation.
441
+ mate = {}
442
+
443
+ # If b is a top-level blossom,
444
+ # label.get(b) is None if b is unlabeled (free),
445
+ # 1 if b is an S-blossom,
446
+ # 2 if b is a T-blossom.
447
+ # The label of a vertex is found by looking at the label of its top-level
448
+ # containing blossom.
449
+ # If v is a vertex inside a T-blossom, label[v] is 2 iff v is reachable
450
+ # from an S-vertex outside the blossom.
451
+ # Labels are assigned during a stage and reset after each augmentation.
452
+ label = {}
453
+
454
+ # If b is a labeled top-level blossom,
455
+ # labeledge[b] = (v, w) is the edge through which b obtained its label
456
+ # such that w is a vertex in b, or None if b's base vertex is single.
457
+ # If w is a vertex inside a T-blossom and label[w] == 2,
458
+ # labeledge[w] = (v, w) is an edge through which w is reachable from
459
+ # outside the blossom.
460
+ labeledge = {}
461
+
462
+ # If v is a vertex, inblossom[v] is the top-level blossom to which v
463
+ # belongs.
464
+ # If v is a top-level vertex, inblossom[v] == v since v is itself
465
+ # a (trivial) top-level blossom.
466
+ # Initially all vertices are top-level trivial blossoms.
467
+ inblossom = dict(zip(gnodes, gnodes))
468
+
469
+ # If b is a sub-blossom,
470
+ # blossomparent[b] is its immediate parent (sub-)blossom.
471
+ # If b is a top-level blossom, blossomparent[b] is None.
472
+ blossomparent = dict(zip(gnodes, repeat(None)))
473
+
474
+ # If b is a (sub-)blossom,
475
+ # blossombase[b] is its base VERTEX (i.e. recursive sub-blossom).
476
+ blossombase = dict(zip(gnodes, gnodes))
477
+
478
+ # If w is a free vertex (or an unreached vertex inside a T-blossom),
479
+ # bestedge[w] = (v, w) is the least-slack edge from an S-vertex,
480
+ # or None if there is no such edge.
481
+ # If b is a (possibly trivial) top-level S-blossom,
482
+ # bestedge[b] = (v, w) is the least-slack edge to a different S-blossom
483
+ # (v inside b), or None if there is no such edge.
484
+ # This is used for efficient computation of delta2 and delta3.
485
+ bestedge = {}
486
+
487
+ # If v is a vertex,
488
+ # dualvar[v] = 2 * u(v) where u(v) is the v's variable in the dual
489
+ # optimization problem (if all edge weights are integers, multiplication
490
+ # by two ensures that all values remain integers throughout the algorithm).
491
+ # Initially, u(v) = maxweight / 2.
492
+ dualvar = dict(zip(gnodes, repeat(maxweight)))
493
+
494
+ # If b is a non-trivial blossom,
495
+ # blossomdual[b] = z(b) where z(b) is b's variable in the dual
496
+ # optimization problem.
497
+ blossomdual = {}
498
+
499
+ # If (v, w) in allowedge or (w, v) in allowedg, then the edge
500
+ # (v, w) is known to have zero slack in the optimization problem;
501
+ # otherwise the edge may or may not have zero slack.
502
+ allowedge = {}
503
+
504
+ # Queue of newly discovered S-vertices.
505
+ queue = []
506
+
507
+ # Return 2 * slack of edge (v, w) (does not work inside blossoms).
508
+ def slack(v, w):
509
+ return dualvar[v] + dualvar[w] - 2 * G[v][w].get(weight, 1)
510
+
511
+ # Assign label t to the top-level blossom containing vertex w,
512
+ # coming through an edge from vertex v.
513
+ def assignLabel(w, t, v):
514
+ b = inblossom[w]
515
+ assert label.get(w) is None and label.get(b) is None
516
+ label[w] = label[b] = t
517
+ if v is not None:
518
+ labeledge[w] = labeledge[b] = (v, w)
519
+ else:
520
+ labeledge[w] = labeledge[b] = None
521
+ bestedge[w] = bestedge[b] = None
522
+ if t == 1:
523
+ # b became an S-vertex/blossom; add it(s vertices) to the queue.
524
+ if isinstance(b, Blossom):
525
+ queue.extend(b.leaves())
526
+ else:
527
+ queue.append(b)
528
+ elif t == 2:
529
+ # b became a T-vertex/blossom; assign label S to its mate.
530
+ # (If b is a non-trivial blossom, its base is the only vertex
531
+ # with an external mate.)
532
+ base = blossombase[b]
533
+ assignLabel(mate[base], 1, base)
534
+
535
+ # Trace back from vertices v and w to discover either a new blossom
536
+ # or an augmenting path. Return the base vertex of the new blossom,
537
+ # or NoNode if an augmenting path was found.
538
+ def scanBlossom(v, w):
539
+ # Trace back from v and w, placing breadcrumbs as we go.
540
+ path = []
541
+ base = NoNode
542
+ while v is not NoNode:
543
+ # Look for a breadcrumb in v's blossom or put a new breadcrumb.
544
+ b = inblossom[v]
545
+ if label[b] & 4:
546
+ base = blossombase[b]
547
+ break
548
+ assert label[b] == 1
549
+ path.append(b)
550
+ label[b] = 5
551
+ # Trace one step back.
552
+ if labeledge[b] is None:
553
+ # The base of blossom b is single; stop tracing this path.
554
+ assert blossombase[b] not in mate
555
+ v = NoNode
556
+ else:
557
+ assert labeledge[b][0] == mate[blossombase[b]]
558
+ v = labeledge[b][0]
559
+ b = inblossom[v]
560
+ assert label[b] == 2
561
+ # b is a T-blossom; trace one more step back.
562
+ v = labeledge[b][0]
563
+ # Swap v and w so that we alternate between both paths.
564
+ if w is not NoNode:
565
+ v, w = w, v
566
+ # Remove breadcrumbs.
567
+ for b in path:
568
+ label[b] = 1
569
+ # Return base vertex, if we found one.
570
+ return base
571
+
572
+ # Construct a new blossom with given base, through S-vertices v and w.
573
+ # Label the new blossom as S; set its dual variable to zero;
574
+ # relabel its T-vertices to S and add them to the queue.
575
+ def addBlossom(base, v, w):
576
+ bb = inblossom[base]
577
+ bv = inblossom[v]
578
+ bw = inblossom[w]
579
+ # Create blossom.
580
+ b = Blossom()
581
+ blossombase[b] = base
582
+ blossomparent[b] = None
583
+ blossomparent[bb] = b
584
+ # Make list of sub-blossoms and their interconnecting edge endpoints.
585
+ b.childs = path = []
586
+ b.edges = edgs = [(v, w)]
587
+ # Trace back from v to base.
588
+ while bv != bb:
589
+ # Add bv to the new blossom.
590
+ blossomparent[bv] = b
591
+ path.append(bv)
592
+ edgs.append(labeledge[bv])
593
+ assert label[bv] == 2 or (
594
+ label[bv] == 1 and labeledge[bv][0] == mate[blossombase[bv]]
595
+ )
596
+ # Trace one step back.
597
+ v = labeledge[bv][0]
598
+ bv = inblossom[v]
599
+ # Add base sub-blossom; reverse lists.
600
+ path.append(bb)
601
+ path.reverse()
602
+ edgs.reverse()
603
+ # Trace back from w to base.
604
+ while bw != bb:
605
+ # Add bw to the new blossom.
606
+ blossomparent[bw] = b
607
+ path.append(bw)
608
+ edgs.append((labeledge[bw][1], labeledge[bw][0]))
609
+ assert label[bw] == 2 or (
610
+ label[bw] == 1 and labeledge[bw][0] == mate[blossombase[bw]]
611
+ )
612
+ # Trace one step back.
613
+ w = labeledge[bw][0]
614
+ bw = inblossom[w]
615
+ # Set label to S.
616
+ assert label[bb] == 1
617
+ label[b] = 1
618
+ labeledge[b] = labeledge[bb]
619
+ # Set dual variable to zero.
620
+ blossomdual[b] = 0
621
+ # Relabel vertices.
622
+ for v in b.leaves():
623
+ if label[inblossom[v]] == 2:
624
+ # This T-vertex now turns into an S-vertex because it becomes
625
+ # part of an S-blossom; add it to the queue.
626
+ queue.append(v)
627
+ inblossom[v] = b
628
+ # Compute b.mybestedges.
629
+ bestedgeto = {}
630
+ for bv in path:
631
+ if isinstance(bv, Blossom):
632
+ if bv.mybestedges is not None:
633
+ # Walk this subblossom's least-slack edges.
634
+ nblist = bv.mybestedges
635
+ # The sub-blossom won't need this data again.
636
+ bv.mybestedges = None
637
+ else:
638
+ # This subblossom does not have a list of least-slack
639
+ # edges; get the information from the vertices.
640
+ nblist = [
641
+ (v, w) for v in bv.leaves() for w in G.neighbors(v) if v != w
642
+ ]
643
+ else:
644
+ nblist = [(bv, w) for w in G.neighbors(bv) if bv != w]
645
+ for k in nblist:
646
+ (i, j) = k
647
+ if inblossom[j] == b:
648
+ i, j = j, i
649
+ bj = inblossom[j]
650
+ if (
651
+ bj != b
652
+ and label.get(bj) == 1
653
+ and ((bj not in bestedgeto) or slack(i, j) < slack(*bestedgeto[bj]))
654
+ ):
655
+ bestedgeto[bj] = k
656
+ # Forget about least-slack edge of the subblossom.
657
+ bestedge[bv] = None
658
+ b.mybestedges = list(bestedgeto.values())
659
+ # Select bestedge[b].
660
+ mybestedge = None
661
+ bestedge[b] = None
662
+ for k in b.mybestedges:
663
+ kslack = slack(*k)
664
+ if mybestedge is None or kslack < mybestslack:
665
+ mybestedge = k
666
+ mybestslack = kslack
667
+ bestedge[b] = mybestedge
668
+
669
+ # Expand the given top-level blossom.
670
+ def expandBlossom(b, endstage):
671
+ # This is an obnoxiously complicated recursive function for the sake of
672
+ # a stack-transformation. So, we hack around the complexity by using
673
+ # a trampoline pattern. By yielding the arguments to each recursive
674
+ # call, we keep the actual callstack flat.
675
+
676
+ def _recurse(b, endstage):
677
+ # Convert sub-blossoms into top-level blossoms.
678
+ for s in b.childs:
679
+ blossomparent[s] = None
680
+ if isinstance(s, Blossom):
681
+ if endstage and blossomdual[s] == 0:
682
+ # Recursively expand this sub-blossom.
683
+ yield s
684
+ else:
685
+ for v in s.leaves():
686
+ inblossom[v] = s
687
+ else:
688
+ inblossom[s] = s
689
+ # If we expand a T-blossom during a stage, its sub-blossoms must be
690
+ # relabeled.
691
+ if (not endstage) and label.get(b) == 2:
692
+ # Start at the sub-blossom through which the expanding
693
+ # blossom obtained its label, and relabel sub-blossoms untili
694
+ # we reach the base.
695
+ # Figure out through which sub-blossom the expanding blossom
696
+ # obtained its label initially.
697
+ entrychild = inblossom[labeledge[b][1]]
698
+ # Decide in which direction we will go round the blossom.
699
+ j = b.childs.index(entrychild)
700
+ if j & 1:
701
+ # Start index is odd; go forward and wrap.
702
+ j -= len(b.childs)
703
+ jstep = 1
704
+ else:
705
+ # Start index is even; go backward.
706
+ jstep = -1
707
+ # Move along the blossom until we get to the base.
708
+ v, w = labeledge[b]
709
+ while j != 0:
710
+ # Relabel the T-sub-blossom.
711
+ if jstep == 1:
712
+ p, q = b.edges[j]
713
+ else:
714
+ q, p = b.edges[j - 1]
715
+ label[w] = None
716
+ label[q] = None
717
+ assignLabel(w, 2, v)
718
+ # Step to the next S-sub-blossom and note its forward edge.
719
+ allowedge[(p, q)] = allowedge[(q, p)] = True
720
+ j += jstep
721
+ if jstep == 1:
722
+ v, w = b.edges[j]
723
+ else:
724
+ w, v = b.edges[j - 1]
725
+ # Step to the next T-sub-blossom.
726
+ allowedge[(v, w)] = allowedge[(w, v)] = True
727
+ j += jstep
728
+ # Relabel the base T-sub-blossom WITHOUT stepping through to
729
+ # its mate (so don't call assignLabel).
730
+ bw = b.childs[j]
731
+ label[w] = label[bw] = 2
732
+ labeledge[w] = labeledge[bw] = (v, w)
733
+ bestedge[bw] = None
734
+ # Continue along the blossom until we get back to entrychild.
735
+ j += jstep
736
+ while b.childs[j] != entrychild:
737
+ # Examine the vertices of the sub-blossom to see whether
738
+ # it is reachable from a neighboring S-vertex outside the
739
+ # expanding blossom.
740
+ bv = b.childs[j]
741
+ if label.get(bv) == 1:
742
+ # This sub-blossom just got label S through one of its
743
+ # neighbors; leave it be.
744
+ j += jstep
745
+ continue
746
+ if isinstance(bv, Blossom):
747
+ for v in bv.leaves():
748
+ if label.get(v):
749
+ break
750
+ else:
751
+ v = bv
752
+ # If the sub-blossom contains a reachable vertex, assign
753
+ # label T to the sub-blossom.
754
+ if label.get(v):
755
+ assert label[v] == 2
756
+ assert inblossom[v] == bv
757
+ label[v] = None
758
+ label[mate[blossombase[bv]]] = None
759
+ assignLabel(v, 2, labeledge[v][0])
760
+ j += jstep
761
+ # Remove the expanded blossom entirely.
762
+ label.pop(b, None)
763
+ labeledge.pop(b, None)
764
+ bestedge.pop(b, None)
765
+ del blossomparent[b]
766
+ del blossombase[b]
767
+ del blossomdual[b]
768
+
769
+ # Now, we apply the trampoline pattern. We simulate a recursive
770
+ # callstack by maintaining a stack of generators, each yielding a
771
+ # sequence of function arguments. We grow the stack by appending a call
772
+ # to _recurse on each argument tuple, and shrink the stack whenever a
773
+ # generator is exhausted.
774
+ stack = [_recurse(b, endstage)]
775
+ while stack:
776
+ top = stack[-1]
777
+ for s in top:
778
+ stack.append(_recurse(s, endstage))
779
+ break
780
+ else:
781
+ stack.pop()
782
+
783
+ # Swap matched/unmatched edges over an alternating path through blossom b
784
+ # between vertex v and the base vertex. Keep blossom bookkeeping
785
+ # consistent.
786
+ def augmentBlossom(b, v):
787
+ # This is an obnoxiously complicated recursive function for the sake of
788
+ # a stack-transformation. So, we hack around the complexity by using
789
+ # a trampoline pattern. By yielding the arguments to each recursive
790
+ # call, we keep the actual callstack flat.
791
+
792
+ def _recurse(b, v):
793
+ # Bubble up through the blossom tree from vertex v to an immediate
794
+ # sub-blossom of b.
795
+ t = v
796
+ while blossomparent[t] != b:
797
+ t = blossomparent[t]
798
+ # Recursively deal with the first sub-blossom.
799
+ if isinstance(t, Blossom):
800
+ yield (t, v)
801
+ # Decide in which direction we will go round the blossom.
802
+ i = j = b.childs.index(t)
803
+ if i & 1:
804
+ # Start index is odd; go forward and wrap.
805
+ j -= len(b.childs)
806
+ jstep = 1
807
+ else:
808
+ # Start index is even; go backward.
809
+ jstep = -1
810
+ # Move along the blossom until we get to the base.
811
+ while j != 0:
812
+ # Step to the next sub-blossom and augment it recursively.
813
+ j += jstep
814
+ t = b.childs[j]
815
+ if jstep == 1:
816
+ w, x = b.edges[j]
817
+ else:
818
+ x, w = b.edges[j - 1]
819
+ if isinstance(t, Blossom):
820
+ yield (t, w)
821
+ # Step to the next sub-blossom and augment it recursively.
822
+ j += jstep
823
+ t = b.childs[j]
824
+ if isinstance(t, Blossom):
825
+ yield (t, x)
826
+ # Match the edge connecting those sub-blossoms.
827
+ mate[w] = x
828
+ mate[x] = w
829
+ # Rotate the list of sub-blossoms to put the new base at the front.
830
+ b.childs = b.childs[i:] + b.childs[:i]
831
+ b.edges = b.edges[i:] + b.edges[:i]
832
+ blossombase[b] = blossombase[b.childs[0]]
833
+ assert blossombase[b] == v
834
+
835
+ # Now, we apply the trampoline pattern. We simulate a recursive
836
+ # callstack by maintaining a stack of generators, each yielding a
837
+ # sequence of function arguments. We grow the stack by appending a call
838
+ # to _recurse on each argument tuple, and shrink the stack whenever a
839
+ # generator is exhausted.
840
+ stack = [_recurse(b, v)]
841
+ while stack:
842
+ top = stack[-1]
843
+ for args in top:
844
+ stack.append(_recurse(*args))
845
+ break
846
+ else:
847
+ stack.pop()
848
+
849
+ # Swap matched/unmatched edges over an alternating path between two
850
+ # single vertices. The augmenting path runs through S-vertices v and w.
851
+ def augmentMatching(v, w):
852
+ for s, j in ((v, w), (w, v)):
853
+ # Match vertex s to vertex j. Then trace back from s
854
+ # until we find a single vertex, swapping matched and unmatched
855
+ # edges as we go.
856
+ while 1:
857
+ bs = inblossom[s]
858
+ assert label[bs] == 1
859
+ assert (labeledge[bs] is None and blossombase[bs] not in mate) or (
860
+ labeledge[bs][0] == mate[blossombase[bs]]
861
+ )
862
+ # Augment through the S-blossom from s to base.
863
+ if isinstance(bs, Blossom):
864
+ augmentBlossom(bs, s)
865
+ # Update mate[s]
866
+ mate[s] = j
867
+ # Trace one step back.
868
+ if labeledge[bs] is None:
869
+ # Reached single vertex; stop.
870
+ break
871
+ t = labeledge[bs][0]
872
+ bt = inblossom[t]
873
+ assert label[bt] == 2
874
+ # Trace one more step back.
875
+ s, j = labeledge[bt]
876
+ # Augment through the T-blossom from j to base.
877
+ assert blossombase[bt] == t
878
+ if isinstance(bt, Blossom):
879
+ augmentBlossom(bt, j)
880
+ # Update mate[j]
881
+ mate[j] = s
882
+
883
+ # Verify that the optimum solution has been reached.
884
+ def verifyOptimum():
885
+ if maxcardinality:
886
+ # Vertices may have negative dual;
887
+ # find a constant non-negative number to add to all vertex duals.
888
+ vdualoffset = max(0, -min(dualvar.values()))
889
+ else:
890
+ vdualoffset = 0
891
+ # 0. all dual variables are non-negative
892
+ assert min(dualvar.values()) + vdualoffset >= 0
893
+ assert len(blossomdual) == 0 or min(blossomdual.values()) >= 0
894
+ # 0. all edges have non-negative slack and
895
+ # 1. all matched edges have zero slack;
896
+ for i, j, d in G.edges(data=True):
897
+ wt = d.get(weight, 1)
898
+ if i == j:
899
+ continue # ignore self-loops
900
+ s = dualvar[i] + dualvar[j] - 2 * wt
901
+ iblossoms = [i]
902
+ jblossoms = [j]
903
+ while blossomparent[iblossoms[-1]] is not None:
904
+ iblossoms.append(blossomparent[iblossoms[-1]])
905
+ while blossomparent[jblossoms[-1]] is not None:
906
+ jblossoms.append(blossomparent[jblossoms[-1]])
907
+ iblossoms.reverse()
908
+ jblossoms.reverse()
909
+ for bi, bj in zip(iblossoms, jblossoms):
910
+ if bi != bj:
911
+ break
912
+ s += 2 * blossomdual[bi]
913
+ assert s >= 0
914
+ if mate.get(i) == j or mate.get(j) == i:
915
+ assert mate[i] == j and mate[j] == i
916
+ assert s == 0
917
+ # 2. all single vertices have zero dual value;
918
+ for v in gnodes:
919
+ assert (v in mate) or dualvar[v] + vdualoffset == 0
920
+ # 3. all blossoms with positive dual value are full.
921
+ for b in blossomdual:
922
+ if blossomdual[b] > 0:
923
+ assert len(b.edges) % 2 == 1
924
+ for i, j in b.edges[1::2]:
925
+ assert mate[i] == j and mate[j] == i
926
+ # Ok.
927
+
928
+ # Main loop: continue until no further improvement is possible.
929
+ while 1:
930
+ # Each iteration of this loop is a "stage".
931
+ # A stage finds an augmenting path and uses that to improve
932
+ # the matching.
933
+
934
+ # Remove labels from top-level blossoms/vertices.
935
+ label.clear()
936
+ labeledge.clear()
937
+
938
+ # Forget all about least-slack edges.
939
+ bestedge.clear()
940
+ for b in blossomdual:
941
+ b.mybestedges = None
942
+
943
+ # Loss of labeling means that we can not be sure that currently
944
+ # allowable edges remain allowable throughout this stage.
945
+ allowedge.clear()
946
+
947
+ # Make queue empty.
948
+ queue[:] = []
949
+
950
+ # Label single blossoms/vertices with S and put them in the queue.
951
+ for v in gnodes:
952
+ if (v not in mate) and label.get(inblossom[v]) is None:
953
+ assignLabel(v, 1, None)
954
+
955
+ # Loop until we succeed in augmenting the matching.
956
+ augmented = 0
957
+ while 1:
958
+ # Each iteration of this loop is a "substage".
959
+ # A substage tries to find an augmenting path;
960
+ # if found, the path is used to improve the matching and
961
+ # the stage ends. If there is no augmenting path, the
962
+ # primal-dual method is used to pump some slack out of
963
+ # the dual variables.
964
+
965
+ # Continue labeling until all vertices which are reachable
966
+ # through an alternating path have got a label.
967
+ while queue and not augmented:
968
+ # Take an S vertex from the queue.
969
+ v = queue.pop()
970
+ assert label[inblossom[v]] == 1
971
+
972
+ # Scan its neighbors:
973
+ for w in G.neighbors(v):
974
+ if w == v:
975
+ continue # ignore self-loops
976
+ # w is a neighbor to v
977
+ bv = inblossom[v]
978
+ bw = inblossom[w]
979
+ if bv == bw:
980
+ # this edge is internal to a blossom; ignore it
981
+ continue
982
+ if (v, w) not in allowedge:
983
+ kslack = slack(v, w)
984
+ if kslack <= 0:
985
+ # edge k has zero slack => it is allowable
986
+ allowedge[(v, w)] = allowedge[(w, v)] = True
987
+ if (v, w) in allowedge:
988
+ if label.get(bw) is None:
989
+ # (C1) w is a free vertex;
990
+ # label w with T and label its mate with S (R12).
991
+ assignLabel(w, 2, v)
992
+ elif label.get(bw) == 1:
993
+ # (C2) w is an S-vertex (not in the same blossom);
994
+ # follow back-links to discover either an
995
+ # augmenting path or a new blossom.
996
+ base = scanBlossom(v, w)
997
+ if base is not NoNode:
998
+ # Found a new blossom; add it to the blossom
999
+ # bookkeeping and turn it into an S-blossom.
1000
+ addBlossom(base, v, w)
1001
+ else:
1002
+ # Found an augmenting path; augment the
1003
+ # matching and end this stage.
1004
+ augmentMatching(v, w)
1005
+ augmented = 1
1006
+ break
1007
+ elif label.get(w) is None:
1008
+ # w is inside a T-blossom, but w itself has not
1009
+ # yet been reached from outside the blossom;
1010
+ # mark it as reached (we need this to relabel
1011
+ # during T-blossom expansion).
1012
+ assert label[bw] == 2
1013
+ label[w] = 2
1014
+ labeledge[w] = (v, w)
1015
+ elif label.get(bw) == 1:
1016
+ # keep track of the least-slack non-allowable edge to
1017
+ # a different S-blossom.
1018
+ if bestedge.get(bv) is None or kslack < slack(*bestedge[bv]):
1019
+ bestedge[bv] = (v, w)
1020
+ elif label.get(w) is None:
1021
+ # w is a free vertex (or an unreached vertex inside
1022
+ # a T-blossom) but we can not reach it yet;
1023
+ # keep track of the least-slack edge that reaches w.
1024
+ if bestedge.get(w) is None or kslack < slack(*bestedge[w]):
1025
+ bestedge[w] = (v, w)
1026
+
1027
+ if augmented:
1028
+ break
1029
+
1030
+ # There is no augmenting path under these constraints;
1031
+ # compute delta and reduce slack in the optimization problem.
1032
+ # (Note that our vertex dual variables, edge slacks and delta's
1033
+ # are pre-multiplied by two.)
1034
+ deltatype = -1
1035
+ delta = deltaedge = deltablossom = None
1036
+
1037
+ # Compute delta1: the minimum value of any vertex dual.
1038
+ if not maxcardinality:
1039
+ deltatype = 1
1040
+ delta = min(dualvar.values())
1041
+
1042
+ # Compute delta2: the minimum slack on any edge between
1043
+ # an S-vertex and a free vertex.
1044
+ for v in G.nodes():
1045
+ if label.get(inblossom[v]) is None and bestedge.get(v) is not None:
1046
+ d = slack(*bestedge[v])
1047
+ if deltatype == -1 or d < delta:
1048
+ delta = d
1049
+ deltatype = 2
1050
+ deltaedge = bestedge[v]
1051
+
1052
+ # Compute delta3: half the minimum slack on any edge between
1053
+ # a pair of S-blossoms.
1054
+ for b in blossomparent:
1055
+ if (
1056
+ blossomparent[b] is None
1057
+ and label.get(b) == 1
1058
+ and bestedge.get(b) is not None
1059
+ ):
1060
+ kslack = slack(*bestedge[b])
1061
+ if allinteger:
1062
+ assert (kslack % 2) == 0
1063
+ d = kslack // 2
1064
+ else:
1065
+ d = kslack / 2.0
1066
+ if deltatype == -1 or d < delta:
1067
+ delta = d
1068
+ deltatype = 3
1069
+ deltaedge = bestedge[b]
1070
+
1071
+ # Compute delta4: minimum z variable of any T-blossom.
1072
+ for b in blossomdual:
1073
+ if (
1074
+ blossomparent[b] is None
1075
+ and label.get(b) == 2
1076
+ and (deltatype == -1 or blossomdual[b] < delta)
1077
+ ):
1078
+ delta = blossomdual[b]
1079
+ deltatype = 4
1080
+ deltablossom = b
1081
+
1082
+ if deltatype == -1:
1083
+ # No further improvement possible; max-cardinality optimum
1084
+ # reached. Do a final delta update to make the optimum
1085
+ # verifiable.
1086
+ assert maxcardinality
1087
+ deltatype = 1
1088
+ delta = max(0, min(dualvar.values()))
1089
+
1090
+ # Update dual variables according to delta.
1091
+ for v in gnodes:
1092
+ if label.get(inblossom[v]) == 1:
1093
+ # S-vertex: 2*u = 2*u - 2*delta
1094
+ dualvar[v] -= delta
1095
+ elif label.get(inblossom[v]) == 2:
1096
+ # T-vertex: 2*u = 2*u + 2*delta
1097
+ dualvar[v] += delta
1098
+ for b in blossomdual:
1099
+ if blossomparent[b] is None:
1100
+ if label.get(b) == 1:
1101
+ # top-level S-blossom: z = z + 2*delta
1102
+ blossomdual[b] += delta
1103
+ elif label.get(b) == 2:
1104
+ # top-level T-blossom: z = z - 2*delta
1105
+ blossomdual[b] -= delta
1106
+
1107
+ # Take action at the point where minimum delta occurred.
1108
+ if deltatype == 1:
1109
+ # No further improvement possible; optimum reached.
1110
+ break
1111
+ elif deltatype == 2:
1112
+ # Use the least-slack edge to continue the search.
1113
+ (v, w) = deltaedge
1114
+ assert label[inblossom[v]] == 1
1115
+ allowedge[(v, w)] = allowedge[(w, v)] = True
1116
+ queue.append(v)
1117
+ elif deltatype == 3:
1118
+ # Use the least-slack edge to continue the search.
1119
+ (v, w) = deltaedge
1120
+ allowedge[(v, w)] = allowedge[(w, v)] = True
1121
+ assert label[inblossom[v]] == 1
1122
+ queue.append(v)
1123
+ elif deltatype == 4:
1124
+ # Expand the least-z blossom.
1125
+ expandBlossom(deltablossom, False)
1126
+
1127
+ # End of a this substage.
1128
+
1129
+ # Paranoia check that the matching is symmetric.
1130
+ for v in mate:
1131
+ assert mate[mate[v]] == v
1132
+
1133
+ # Stop when no more augmenting path can be found.
1134
+ if not augmented:
1135
+ break
1136
+
1137
+ # End of a stage; expand all S-blossoms which have zero dual.
1138
+ for b in list(blossomdual.keys()):
1139
+ if b not in blossomdual:
1140
+ continue # already expanded
1141
+ if blossomparent[b] is None and label.get(b) == 1 and blossomdual[b] == 0:
1142
+ expandBlossom(b, True)
1143
+
1144
+ # Verify that we reached the optimum solution (only for integer weights).
1145
+ if allinteger:
1146
+ verifyOptimum()
1147
+
1148
+ return matching_dict_to_set(mate)