okstra 0.130.3 → 0.131.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 (367) hide show
  1. package/README.md +0 -1
  2. package/docs/architecture.md +2 -2
  3. package/docs/cli.md +1 -1
  4. package/docs/for-ai/README.md +0 -2
  5. package/docs/for-ai/skills/okstra-run.md +13 -2
  6. package/docs/for-ai/skills/okstra-setup.md +4 -1
  7. package/docs/project-structure-overview.md +5 -4
  8. package/docs/task-process/implementation-planning.md +13 -0
  9. package/docs/task-process/implementation.md +17 -2
  10. package/package.json +1 -1
  11. package/runtime/BUILD.json +2 -2
  12. package/runtime/agents/workers/report-writer-worker.md +7 -0
  13. package/runtime/bin/lib/okstra/usage.sh +4 -4
  14. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  15. package/runtime/prompts/lead/plan-body-verification.md +26 -5
  16. package/runtime/prompts/lead/report-writer.md +6 -2
  17. package/runtime/prompts/profiles/_common-contract.md +2 -1
  18. package/runtime/prompts/profiles/_implementation-deliverable.md +6 -1
  19. package/runtime/prompts/profiles/_implementation-executor.md +2 -2
  20. package/runtime/prompts/profiles/_implementation-verifier.md +33 -10
  21. package/runtime/prompts/profiles/final-verification.md +21 -6
  22. package/runtime/prompts/profiles/implementation-planning.md +21 -4
  23. package/runtime/python/okstra_ctl/codex_dispatch.py +31 -0
  24. package/runtime/python/okstra_ctl/conformance.py +49 -11
  25. package/runtime/python/okstra_ctl/report_finalize.py +52 -1
  26. package/runtime/python/okstra_ctl/report_views.py +32 -5
  27. package/runtime/python/okstra_ctl/run.py +15 -3
  28. package/runtime/python/okstra_ctl/worker_prompt_contract.py +14 -6
  29. package/runtime/python/okstra_ctl/worker_prompt_policy.py +19 -1
  30. package/runtime/python/okstra_vendor/__init__.py +0 -44
  31. package/runtime/schemas/final-report-v1.0.schema.json +101 -6
  32. package/runtime/skills/okstra-run/SKILL.md +11 -4
  33. package/runtime/skills/okstra-setup/SKILL.md +3 -2
  34. package/runtime/skills/okstra-setup/references/project-config.md +16 -7
  35. package/runtime/templates/reports/final-report.template.md +18 -12
  36. package/runtime/templates/reports/i18n/en.json +1 -0
  37. package/runtime/templates/reports/i18n/ko.json +1 -0
  38. package/runtime/templates/reports/report.css +18 -0
  39. package/runtime/validators/lib/fixtures.sh +6 -0
  40. package/runtime/validators/validate-run.py +1722 -98
  41. package/src/cli-registry.mjs +0 -7
  42. package/src/commands/lifecycle/doctor.mjs +0 -9
  43. package/src/lib/skill-catalog.mjs +0 -1
  44. package/docs/for-ai/skills/okstra-graphify.md +0 -64
  45. package/runtime/python/okstra_ctl/graphify_cmd.py +0 -225
  46. package/runtime/python/okstra_vendor/graphify/.vendored-version +0 -1
  47. package/runtime/python/okstra_vendor/graphify/__init__.py +0 -28
  48. package/runtime/python/okstra_vendor/graphify/__main__.py +0 -1371
  49. package/runtime/python/okstra_vendor/graphify/analyze.py +0 -540
  50. package/runtime/python/okstra_vendor/graphify/benchmark.py +0 -129
  51. package/runtime/python/okstra_vendor/graphify/build.py +0 -107
  52. package/runtime/python/okstra_vendor/graphify/cache.py +0 -169
  53. package/runtime/python/okstra_vendor/graphify/cluster.py +0 -137
  54. package/runtime/python/okstra_vendor/graphify/detect.py +0 -510
  55. package/runtime/python/okstra_vendor/graphify/export.py +0 -1014
  56. package/runtime/python/okstra_vendor/graphify/extract.py +0 -3277
  57. package/runtime/python/okstra_vendor/graphify/hooks.py +0 -220
  58. package/runtime/python/okstra_vendor/graphify/ingest.py +0 -297
  59. package/runtime/python/okstra_vendor/graphify/manifest.py +0 -4
  60. package/runtime/python/okstra_vendor/graphify/report.py +0 -175
  61. package/runtime/python/okstra_vendor/graphify/security.py +0 -203
  62. package/runtime/python/okstra_vendor/graphify/serve.py +0 -373
  63. package/runtime/python/okstra_vendor/graphify/skill-aider.md +0 -1184
  64. package/runtime/python/okstra_vendor/graphify/skill-claw.md +0 -1184
  65. package/runtime/python/okstra_vendor/graphify/skill-codex.md +0 -1242
  66. package/runtime/python/okstra_vendor/graphify/skill-copilot.md +0 -1268
  67. package/runtime/python/okstra_vendor/graphify/skill-droid.md +0 -1239
  68. package/runtime/python/okstra_vendor/graphify/skill-kiro.md +0 -1183
  69. package/runtime/python/okstra_vendor/graphify/skill-opencode.md +0 -1238
  70. package/runtime/python/okstra_vendor/graphify/skill-trae.md +0 -1208
  71. package/runtime/python/okstra_vendor/graphify/skill-vscode.md +0 -253
  72. package/runtime/python/okstra_vendor/graphify/skill-windows.md +0 -1245
  73. package/runtime/python/okstra_vendor/graphify/skill.md +0 -1319
  74. package/runtime/python/okstra_vendor/graphify/transcribe.py +0 -182
  75. package/runtime/python/okstra_vendor/graphify/validate.py +0 -72
  76. package/runtime/python/okstra_vendor/graphify/watch.py +0 -188
  77. package/runtime/python/okstra_vendor/graphify/wiki.py +0 -214
  78. package/runtime/python/okstra_vendor/networkx/__init__.py +0 -62
  79. package/runtime/python/okstra_vendor/networkx/algorithms/__init__.py +0 -134
  80. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/__init__.py +0 -26
  81. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clique.py +0 -259
  82. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clustering_coefficient.py +0 -71
  83. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/connectivity.py +0 -412
  84. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/density.py +0 -396
  85. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/distance_measures.py +0 -150
  86. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/dominating_set.py +0 -149
  87. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/kcomponents.py +0 -369
  88. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/matching.py +0 -44
  89. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/maxcut.py +0 -143
  90. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/ramsey.py +0 -53
  91. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/steinertree.py +0 -265
  92. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/traveling_salesman.py +0 -1508
  93. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/treewidth.py +0 -255
  94. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/vertex_cover.py +0 -83
  95. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/__init__.py +0 -5
  96. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/connectivity.py +0 -122
  97. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/correlation.py +0 -302
  98. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/mixing.py +0 -255
  99. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/neighbor_degree.py +0 -160
  100. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/pairs.py +0 -127
  101. package/runtime/python/okstra_vendor/networkx/algorithms/asteroidal.py +0 -164
  102. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/__init__.py +0 -88
  103. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/basic.py +0 -322
  104. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/centrality.py +0 -290
  105. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/cluster.py +0 -289
  106. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/covering.py +0 -57
  107. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/edgelist.py +0 -360
  108. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/extendability.py +0 -105
  109. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/generators.py +0 -603
  110. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/link_analysis.py +0 -316
  111. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matching.py +0 -590
  112. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matrix.py +0 -232
  113. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/projection.py +0 -526
  114. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/redundancy.py +0 -112
  115. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/spectral.py +0 -69
  116. package/runtime/python/okstra_vendor/networkx/algorithms/boundary.py +0 -168
  117. package/runtime/python/okstra_vendor/networkx/algorithms/bridges.py +0 -205
  118. package/runtime/python/okstra_vendor/networkx/algorithms/broadcasting.py +0 -164
  119. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/__init__.py +0 -20
  120. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness.py +0 -591
  121. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness_subset.py +0 -236
  122. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/closeness.py +0 -282
  123. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness.py +0 -364
  124. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness_subset.py +0 -227
  125. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_closeness.py +0 -96
  126. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/degree_alg.py +0 -150
  127. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/dispersion.py +0 -107
  128. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/eigenvector.py +0 -357
  129. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/flow_matrix.py +0 -130
  130. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/group.py +0 -787
  131. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/harmonic.py +0 -88
  132. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/katz.py +0 -331
  133. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/laplacian.py +0 -150
  134. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/load.py +0 -200
  135. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/percolation.py +0 -128
  136. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/reaching.py +0 -209
  137. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/second_order.py +0 -141
  138. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/subgraph_alg.py +0 -361
  139. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/trophic.py +0 -181
  140. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/voterank_alg.py +0 -95
  141. package/runtime/python/okstra_vendor/networkx/algorithms/chains.py +0 -172
  142. package/runtime/python/okstra_vendor/networkx/algorithms/chordal.py +0 -443
  143. package/runtime/python/okstra_vendor/networkx/algorithms/clique.py +0 -818
  144. package/runtime/python/okstra_vendor/networkx/algorithms/cluster.py +0 -732
  145. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/__init__.py +0 -4
  146. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/equitable_coloring.py +0 -505
  147. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/greedy_coloring.py +0 -565
  148. package/runtime/python/okstra_vendor/networkx/algorithms/communicability_alg.py +0 -163
  149. package/runtime/python/okstra_vendor/networkx/algorithms/community/__init__.py +0 -28
  150. package/runtime/python/okstra_vendor/networkx/algorithms/community/asyn_fluid.py +0 -153
  151. package/runtime/python/okstra_vendor/networkx/algorithms/community/bipartitions.py +0 -354
  152. package/runtime/python/okstra_vendor/networkx/algorithms/community/centrality.py +0 -171
  153. package/runtime/python/okstra_vendor/networkx/algorithms/community/community_utils.py +0 -30
  154. package/runtime/python/okstra_vendor/networkx/algorithms/community/divisive.py +0 -216
  155. package/runtime/python/okstra_vendor/networkx/algorithms/community/kclique.py +0 -79
  156. package/runtime/python/okstra_vendor/networkx/algorithms/community/label_propagation.py +0 -338
  157. package/runtime/python/okstra_vendor/networkx/algorithms/community/leiden.py +0 -162
  158. package/runtime/python/okstra_vendor/networkx/algorithms/community/local.py +0 -220
  159. package/runtime/python/okstra_vendor/networkx/algorithms/community/louvain.py +0 -384
  160. package/runtime/python/okstra_vendor/networkx/algorithms/community/lukes.py +0 -227
  161. package/runtime/python/okstra_vendor/networkx/algorithms/community/modularity_max.py +0 -452
  162. package/runtime/python/okstra_vendor/networkx/algorithms/community/quality.py +0 -347
  163. package/runtime/python/okstra_vendor/networkx/algorithms/components/__init__.py +0 -6
  164. package/runtime/python/okstra_vendor/networkx/algorithms/components/attracting.py +0 -115
  165. package/runtime/python/okstra_vendor/networkx/algorithms/components/biconnected.py +0 -394
  166. package/runtime/python/okstra_vendor/networkx/algorithms/components/connected.py +0 -282
  167. package/runtime/python/okstra_vendor/networkx/algorithms/components/semiconnected.py +0 -71
  168. package/runtime/python/okstra_vendor/networkx/algorithms/components/strongly_connected.py +0 -359
  169. package/runtime/python/okstra_vendor/networkx/algorithms/components/weakly_connected.py +0 -196
  170. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/__init__.py +0 -11
  171. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/connectivity.py +0 -811
  172. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/cuts.py +0 -616
  173. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/disjoint_paths.py +0 -408
  174. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_augmentation.py +0 -1270
  175. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_kcomponents.py +0 -592
  176. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcomponents.py +0 -220
  177. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcutsets.py +0 -235
  178. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/stoerwagner.py +0 -152
  179. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/utils.py +0 -88
  180. package/runtime/python/okstra_vendor/networkx/algorithms/core.py +0 -588
  181. package/runtime/python/okstra_vendor/networkx/algorithms/covering.py +0 -142
  182. package/runtime/python/okstra_vendor/networkx/algorithms/cuts.py +0 -416
  183. package/runtime/python/okstra_vendor/networkx/algorithms/cycles.py +0 -1234
  184. package/runtime/python/okstra_vendor/networkx/algorithms/d_separation.py +0 -677
  185. package/runtime/python/okstra_vendor/networkx/algorithms/dag.py +0 -1392
  186. package/runtime/python/okstra_vendor/networkx/algorithms/distance_measures.py +0 -1095
  187. package/runtime/python/okstra_vendor/networkx/algorithms/distance_regular.py +0 -272
  188. package/runtime/python/okstra_vendor/networkx/algorithms/dominance.py +0 -142
  189. package/runtime/python/okstra_vendor/networkx/algorithms/dominating.py +0 -268
  190. package/runtime/python/okstra_vendor/networkx/algorithms/efficiency_measures.py +0 -167
  191. package/runtime/python/okstra_vendor/networkx/algorithms/euler.py +0 -470
  192. package/runtime/python/okstra_vendor/networkx/algorithms/flow/__init__.py +0 -11
  193. package/runtime/python/okstra_vendor/networkx/algorithms/flow/boykovkolmogorov.py +0 -370
  194. package/runtime/python/okstra_vendor/networkx/algorithms/flow/capacityscaling.py +0 -407
  195. package/runtime/python/okstra_vendor/networkx/algorithms/flow/dinitz_alg.py +0 -238
  196. package/runtime/python/okstra_vendor/networkx/algorithms/flow/edmondskarp.py +0 -241
  197. package/runtime/python/okstra_vendor/networkx/algorithms/flow/gomory_hu.py +0 -178
  198. package/runtime/python/okstra_vendor/networkx/algorithms/flow/maxflow.py +0 -611
  199. package/runtime/python/okstra_vendor/networkx/algorithms/flow/mincost.py +0 -356
  200. package/runtime/python/okstra_vendor/networkx/algorithms/flow/networksimplex.py +0 -662
  201. package/runtime/python/okstra_vendor/networkx/algorithms/flow/preflowpush.py +0 -425
  202. package/runtime/python/okstra_vendor/networkx/algorithms/flow/shortestaugmentingpath.py +0 -300
  203. package/runtime/python/okstra_vendor/networkx/algorithms/flow/utils.py +0 -194
  204. package/runtime/python/okstra_vendor/networkx/algorithms/graph_hashing.py +0 -435
  205. package/runtime/python/okstra_vendor/networkx/algorithms/graphical.py +0 -483
  206. package/runtime/python/okstra_vendor/networkx/algorithms/hierarchy.py +0 -57
  207. package/runtime/python/okstra_vendor/networkx/algorithms/hybrid.py +0 -196
  208. package/runtime/python/okstra_vendor/networkx/algorithms/isolate.py +0 -107
  209. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/__init__.py +0 -7
  210. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/ismags.py +0 -1306
  211. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorph.py +0 -336
  212. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorphvf2.py +0 -1262
  213. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/matchhelpers.py +0 -352
  214. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/temporalisomorphvf2.py +0 -308
  215. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tree_isomorphism.py +0 -264
  216. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2pp.py +0 -1102
  217. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2userfunc.py +0 -192
  218. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/__init__.py +0 -2
  219. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/hits_alg.py +0 -337
  220. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/pagerank_alg.py +0 -498
  221. package/runtime/python/okstra_vendor/networkx/algorithms/link_prediction.py +0 -687
  222. package/runtime/python/okstra_vendor/networkx/algorithms/lowest_common_ancestors.py +0 -280
  223. package/runtime/python/okstra_vendor/networkx/algorithms/matching.py +0 -1148
  224. package/runtime/python/okstra_vendor/networkx/algorithms/minors/__init__.py +0 -27
  225. package/runtime/python/okstra_vendor/networkx/algorithms/minors/contraction.py +0 -738
  226. package/runtime/python/okstra_vendor/networkx/algorithms/mis.py +0 -78
  227. package/runtime/python/okstra_vendor/networkx/algorithms/moral.py +0 -59
  228. package/runtime/python/okstra_vendor/networkx/algorithms/node_classification.py +0 -219
  229. package/runtime/python/okstra_vendor/networkx/algorithms/non_randomness.py +0 -155
  230. package/runtime/python/okstra_vendor/networkx/algorithms/operators/__init__.py +0 -4
  231. package/runtime/python/okstra_vendor/networkx/algorithms/operators/all.py +0 -324
  232. package/runtime/python/okstra_vendor/networkx/algorithms/operators/binary.py +0 -468
  233. package/runtime/python/okstra_vendor/networkx/algorithms/operators/product.py +0 -633
  234. package/runtime/python/okstra_vendor/networkx/algorithms/operators/unary.py +0 -77
  235. package/runtime/python/okstra_vendor/networkx/algorithms/perfect_graph.py +0 -73
  236. package/runtime/python/okstra_vendor/networkx/algorithms/planar_drawing.py +0 -464
  237. package/runtime/python/okstra_vendor/networkx/algorithms/planarity.py +0 -1463
  238. package/runtime/python/okstra_vendor/networkx/algorithms/polynomials.py +0 -306
  239. package/runtime/python/okstra_vendor/networkx/algorithms/reciprocity.py +0 -98
  240. package/runtime/python/okstra_vendor/networkx/algorithms/regular.py +0 -167
  241. package/runtime/python/okstra_vendor/networkx/algorithms/richclub.py +0 -138
  242. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/__init__.py +0 -5
  243. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/astar.py +0 -239
  244. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/dense.py +0 -264
  245. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/generic.py +0 -716
  246. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/unweighted.py +0 -625
  247. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/weighted.py +0 -2542
  248. package/runtime/python/okstra_vendor/networkx/algorithms/similarity.py +0 -2107
  249. package/runtime/python/okstra_vendor/networkx/algorithms/simple_paths.py +0 -966
  250. package/runtime/python/okstra_vendor/networkx/algorithms/smallworld.py +0 -404
  251. package/runtime/python/okstra_vendor/networkx/algorithms/smetric.py +0 -30
  252. package/runtime/python/okstra_vendor/networkx/algorithms/sparsifiers.py +0 -296
  253. package/runtime/python/okstra_vendor/networkx/algorithms/structuralholes.py +0 -374
  254. package/runtime/python/okstra_vendor/networkx/algorithms/summarization.py +0 -564
  255. package/runtime/python/okstra_vendor/networkx/algorithms/swap.py +0 -406
  256. package/runtime/python/okstra_vendor/networkx/algorithms/threshold.py +0 -981
  257. package/runtime/python/okstra_vendor/networkx/algorithms/time_dependent.py +0 -142
  258. package/runtime/python/okstra_vendor/networkx/algorithms/tournament.py +0 -406
  259. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/__init__.py +0 -5
  260. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/beamsearch.py +0 -90
  261. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/breadth_first_search.py +0 -576
  262. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/depth_first_search.py +0 -529
  263. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgebfs.py +0 -185
  264. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgedfs.py +0 -182
  265. package/runtime/python/okstra_vendor/networkx/algorithms/tree/__init__.py +0 -7
  266. package/runtime/python/okstra_vendor/networkx/algorithms/tree/branchings.py +0 -1042
  267. package/runtime/python/okstra_vendor/networkx/algorithms/tree/coding.py +0 -413
  268. package/runtime/python/okstra_vendor/networkx/algorithms/tree/decomposition.py +0 -88
  269. package/runtime/python/okstra_vendor/networkx/algorithms/tree/distance_measures.py +0 -219
  270. package/runtime/python/okstra_vendor/networkx/algorithms/tree/mst.py +0 -1281
  271. package/runtime/python/okstra_vendor/networkx/algorithms/tree/operations.py +0 -106
  272. package/runtime/python/okstra_vendor/networkx/algorithms/tree/recognition.py +0 -273
  273. package/runtime/python/okstra_vendor/networkx/algorithms/triads.py +0 -500
  274. package/runtime/python/okstra_vendor/networkx/algorithms/vitality.py +0 -76
  275. package/runtime/python/okstra_vendor/networkx/algorithms/voronoi.py +0 -86
  276. package/runtime/python/okstra_vendor/networkx/algorithms/walks.py +0 -77
  277. package/runtime/python/okstra_vendor/networkx/algorithms/wiener.py +0 -278
  278. package/runtime/python/okstra_vendor/networkx/classes/__init__.py +0 -13
  279. package/runtime/python/okstra_vendor/networkx/classes/coreviews.py +0 -435
  280. package/runtime/python/okstra_vendor/networkx/classes/digraph.py +0 -1363
  281. package/runtime/python/okstra_vendor/networkx/classes/filters.py +0 -95
  282. package/runtime/python/okstra_vendor/networkx/classes/function.py +0 -1549
  283. package/runtime/python/okstra_vendor/networkx/classes/graph.py +0 -2082
  284. package/runtime/python/okstra_vendor/networkx/classes/graphviews.py +0 -269
  285. package/runtime/python/okstra_vendor/networkx/classes/multidigraph.py +0 -977
  286. package/runtime/python/okstra_vendor/networkx/classes/multigraph.py +0 -1294
  287. package/runtime/python/okstra_vendor/networkx/classes/reportviews.py +0 -1447
  288. package/runtime/python/okstra_vendor/networkx/convert.py +0 -502
  289. package/runtime/python/okstra_vendor/networkx/convert_matrix.py +0 -1314
  290. package/runtime/python/okstra_vendor/networkx/drawing/__init__.py +0 -7
  291. package/runtime/python/okstra_vendor/networkx/drawing/layout.py +0 -2036
  292. package/runtime/python/okstra_vendor/networkx/drawing/nx_agraph.py +0 -470
  293. package/runtime/python/okstra_vendor/networkx/drawing/nx_latex.py +0 -570
  294. package/runtime/python/okstra_vendor/networkx/drawing/nx_pydot.py +0 -361
  295. package/runtime/python/okstra_vendor/networkx/drawing/nx_pylab.py +0 -2978
  296. package/runtime/python/okstra_vendor/networkx/exception.py +0 -131
  297. package/runtime/python/okstra_vendor/networkx/generators/__init__.py +0 -34
  298. package/runtime/python/okstra_vendor/networkx/generators/atlas.dat.gz +0 -0
  299. package/runtime/python/okstra_vendor/networkx/generators/atlas.py +0 -227
  300. package/runtime/python/okstra_vendor/networkx/generators/classic.py +0 -1091
  301. package/runtime/python/okstra_vendor/networkx/generators/cographs.py +0 -68
  302. package/runtime/python/okstra_vendor/networkx/generators/community.py +0 -1070
  303. package/runtime/python/okstra_vendor/networkx/generators/degree_seq.py +0 -886
  304. package/runtime/python/okstra_vendor/networkx/generators/directed.py +0 -572
  305. package/runtime/python/okstra_vendor/networkx/generators/duplication.py +0 -174
  306. package/runtime/python/okstra_vendor/networkx/generators/ego.py +0 -66
  307. package/runtime/python/okstra_vendor/networkx/generators/expanders.py +0 -499
  308. package/runtime/python/okstra_vendor/networkx/generators/geometric.py +0 -1037
  309. package/runtime/python/okstra_vendor/networkx/generators/harary_graph.py +0 -163
  310. package/runtime/python/okstra_vendor/networkx/generators/internet_as_graphs.py +0 -443
  311. package/runtime/python/okstra_vendor/networkx/generators/intersection.py +0 -125
  312. package/runtime/python/okstra_vendor/networkx/generators/interval_graph.py +0 -70
  313. package/runtime/python/okstra_vendor/networkx/generators/joint_degree_seq.py +0 -664
  314. package/runtime/python/okstra_vendor/networkx/generators/lattice.py +0 -405
  315. package/runtime/python/okstra_vendor/networkx/generators/line.py +0 -501
  316. package/runtime/python/okstra_vendor/networkx/generators/mycielski.py +0 -110
  317. package/runtime/python/okstra_vendor/networkx/generators/nonisomorphic_trees.py +0 -259
  318. package/runtime/python/okstra_vendor/networkx/generators/random_clustered.py +0 -117
  319. package/runtime/python/okstra_vendor/networkx/generators/random_graphs.py +0 -1416
  320. package/runtime/python/okstra_vendor/networkx/generators/small.py +0 -1070
  321. package/runtime/python/okstra_vendor/networkx/generators/social.py +0 -554
  322. package/runtime/python/okstra_vendor/networkx/generators/spectral_graph_forge.py +0 -120
  323. package/runtime/python/okstra_vendor/networkx/generators/stochastic.py +0 -54
  324. package/runtime/python/okstra_vendor/networkx/generators/sudoku.py +0 -131
  325. package/runtime/python/okstra_vendor/networkx/generators/time_series.py +0 -74
  326. package/runtime/python/okstra_vendor/networkx/generators/trees.py +0 -1070
  327. package/runtime/python/okstra_vendor/networkx/generators/triads.py +0 -94
  328. package/runtime/python/okstra_vendor/networkx/lazy_imports.py +0 -188
  329. package/runtime/python/okstra_vendor/networkx/linalg/__init__.py +0 -13
  330. package/runtime/python/okstra_vendor/networkx/linalg/algebraicconnectivity.py +0 -650
  331. package/runtime/python/okstra_vendor/networkx/linalg/attrmatrix.py +0 -466
  332. package/runtime/python/okstra_vendor/networkx/linalg/bethehessianmatrix.py +0 -77
  333. package/runtime/python/okstra_vendor/networkx/linalg/graphmatrix.py +0 -168
  334. package/runtime/python/okstra_vendor/networkx/linalg/laplacianmatrix.py +0 -512
  335. package/runtime/python/okstra_vendor/networkx/linalg/modularitymatrix.py +0 -166
  336. package/runtime/python/okstra_vendor/networkx/linalg/spectrum.py +0 -186
  337. package/runtime/python/okstra_vendor/networkx/readwrite/__init__.py +0 -17
  338. package/runtime/python/okstra_vendor/networkx/readwrite/adjlist.py +0 -330
  339. package/runtime/python/okstra_vendor/networkx/readwrite/edgelist.py +0 -489
  340. package/runtime/python/okstra_vendor/networkx/readwrite/gexf.py +0 -1084
  341. package/runtime/python/okstra_vendor/networkx/readwrite/gml.py +0 -879
  342. package/runtime/python/okstra_vendor/networkx/readwrite/graph6.py +0 -427
  343. package/runtime/python/okstra_vendor/networkx/readwrite/graphml.py +0 -1053
  344. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/__init__.py +0 -19
  345. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/adjacency.py +0 -156
  346. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/cytoscape.py +0 -190
  347. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/node_link.py +0 -261
  348. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tree.py +0 -137
  349. package/runtime/python/okstra_vendor/networkx/readwrite/leda.py +0 -108
  350. package/runtime/python/okstra_vendor/networkx/readwrite/multiline_adjlist.py +0 -393
  351. package/runtime/python/okstra_vendor/networkx/readwrite/p2g.py +0 -113
  352. package/runtime/python/okstra_vendor/networkx/readwrite/pajek.py +0 -286
  353. package/runtime/python/okstra_vendor/networkx/readwrite/sparse6.py +0 -379
  354. package/runtime/python/okstra_vendor/networkx/readwrite/text.py +0 -851
  355. package/runtime/python/okstra_vendor/networkx/relabel.py +0 -285
  356. package/runtime/python/okstra_vendor/networkx/utils/__init__.py +0 -8
  357. package/runtime/python/okstra_vendor/networkx/utils/backends.py +0 -2171
  358. package/runtime/python/okstra_vendor/networkx/utils/configs.py +0 -396
  359. package/runtime/python/okstra_vendor/networkx/utils/decorators.py +0 -1233
  360. package/runtime/python/okstra_vendor/networkx/utils/heaps.py +0 -338
  361. package/runtime/python/okstra_vendor/networkx/utils/mapped_queue.py +0 -297
  362. package/runtime/python/okstra_vendor/networkx/utils/misc.py +0 -703
  363. package/runtime/python/okstra_vendor/networkx/utils/random_sequence.py +0 -198
  364. package/runtime/python/okstra_vendor/networkx/utils/rcm.py +0 -159
  365. package/runtime/python/okstra_vendor/networkx/utils/union_find.py +0 -106
  366. package/runtime/skills/okstra-graphify/SKILL.md +0 -169
  367. package/src/commands/graphify.mjs +0 -32
@@ -1,677 +0,0 @@
1
- """
2
- Algorithm for testing d-separation in DAGs.
3
-
4
- *d-separation* is a test for conditional independence in probability
5
- distributions that can be factorized using DAGs. It is a purely
6
- graphical test that uses the underlying graph and makes no reference
7
- to the actual distribution parameters. See [1]_ for a formal
8
- definition.
9
-
10
- The implementation is based on the conceptually simple linear time
11
- algorithm presented in [2]_. Refer to [3]_, [4]_ for a couple of
12
- alternative algorithms.
13
-
14
- The functional interface in NetworkX consists of three functions:
15
-
16
- - `find_minimal_d_separator` returns a minimal d-separator set ``z``.
17
- That is, removing any node or nodes from it makes it no longer a d-separator.
18
- - `is_d_separator` checks if a given set is a d-separator.
19
- - `is_minimal_d_separator` checks if a given set is a minimal d-separator.
20
-
21
- D-separators
22
- ------------
23
-
24
- Here, we provide a brief overview of d-separation and related concepts that
25
- are relevant for understanding it:
26
-
27
- The ideas of d-separation and d-connection relate to paths being open or blocked.
28
-
29
- - A "path" is a sequence of nodes connected in order by edges. Unlike for most
30
- graph theory analysis, the direction of the edges is ignored. Thus the path
31
- can be thought of as a traditional path on the undirected version of the graph.
32
- - A "candidate d-separator" ``z`` is a set of nodes being considered as
33
- possibly blocking all paths between two prescribed sets ``x`` and ``y`` of nodes.
34
- We refer to each node in the candidate d-separator as "known".
35
- - A "collider" node on a path is a node that is a successor of its two neighbor
36
- nodes on the path. That is, ``c`` is a collider if the edge directions
37
- along the path look like ``... u -> c <- v ...``.
38
- - If a collider node or any of its descendants are "known", the collider
39
- is called an "open collider". Otherwise it is a "blocking collider".
40
- - Any path can be "blocked" in two ways. If the path contains a "known" node
41
- that is not a collider, the path is blocked. Also, if the path contains a
42
- collider that is not a "known" node, the path is blocked.
43
- - A path is "open" if it is not blocked. That is, it is open if every node is
44
- either an open collider or not a "known". Said another way, every
45
- "known" in the path is a collider and every collider is open (has a
46
- "known" as a inclusive descendant). The concept of "open path" is meant to
47
- demonstrate a probabilistic conditional dependence between two nodes given
48
- prescribed knowledge ("known" nodes).
49
- - Two sets ``x`` and ``y`` of nodes are "d-separated" by a set of nodes ``z``
50
- if all paths between nodes in ``x`` and nodes in ``y`` are blocked. That is,
51
- if there are no open paths from any node in ``x`` to any node in ``y``.
52
- Such a set ``z`` is a "d-separator" of ``x`` and ``y``.
53
- - A "minimal d-separator" is a d-separator ``z`` for which no node or subset
54
- of nodes can be removed with it still being a d-separator.
55
-
56
- The d-separator blocks some paths between ``x`` and ``y`` but opens others.
57
- Nodes in the d-separator block paths if the nodes are not colliders.
58
- But if a collider or its descendant nodes are in the d-separation set, the
59
- colliders are open, allowing a path through that collider.
60
-
61
- Illustration of D-separation with examples
62
- ------------------------------------------
63
-
64
- A pair of two nodes, ``u`` and ``v``, are d-connected if there is a path
65
- from ``u`` to ``v`` that is not blocked. That means, there is an open
66
- path from ``u`` to ``v``.
67
-
68
- For example, if the d-separating set is the empty set, then the following paths are
69
- open between ``u`` and ``v``:
70
-
71
- - u <- n -> v
72
- - u -> w -> ... -> n -> v
73
-
74
- If on the other hand, ``n`` is in the d-separating set, then ``n`` blocks
75
- those paths between ``u`` and ``v``.
76
-
77
- Colliders block a path if they and their descendants are not included
78
- in the d-separating set. An example of a path that is blocked when the
79
- d-separating set is empty is:
80
-
81
- - u -> w -> ... -> n <- v
82
-
83
- The node ``n`` is a collider in this path and is not in the d-separating set.
84
- So ``n`` blocks this path. However, if ``n`` or a descendant of ``n`` is
85
- included in the d-separating set, then the path through the collider
86
- at ``n`` (... -> n <- ...) is "open".
87
-
88
- D-separation is concerned with blocking all paths between nodes from ``x`` to ``y``.
89
- A d-separating set between ``x`` and ``y`` is one where all paths are blocked.
90
-
91
- D-separation and its applications in probability
92
- ------------------------------------------------
93
-
94
- D-separation is commonly used in probabilistic causal-graph models. D-separation
95
- connects the idea of probabilistic "dependence" with separation in a graph. If
96
- one assumes the causal Markov condition [5]_, (every node is conditionally
97
- independent of its non-descendants, given its parents) then d-separation implies
98
- conditional independence in probability distributions.
99
- Symmetrically, d-connection implies dependence.
100
-
101
- The intuition is as follows. The edges on a causal graph indicate which nodes
102
- influence the outcome of other nodes directly. An edge from u to v
103
- implies that the outcome of event ``u`` influences the probabilities for
104
- the outcome of event ``v``. Certainly knowing ``u`` changes predictions for ``v``.
105
- But also knowing ``v`` changes predictions for ``u``. The outcomes are dependent.
106
- Furthermore, an edge from ``v`` to ``w`` would mean that ``w`` and ``v`` are dependent
107
- and thus that ``u`` could indirectly influence ``w``.
108
-
109
- Without any knowledge about the system (candidate d-separating set is empty)
110
- a causal graph ``u -> v -> w`` allows all three nodes to be dependent. But
111
- if we know the outcome of ``v``, the conditional probabilities of outcomes for
112
- ``u`` and ``w`` are independent of each other. That is, once we know the outcome
113
- for ``v``, the probabilities for ``w`` do not depend on the outcome for ``u``.
114
- This is the idea behind ``v`` blocking the path if it is "known" (in the candidate
115
- d-separating set).
116
-
117
- The same argument works whether the direction of the edges are both
118
- left-going and when both arrows head out from the middle. Having a "known"
119
- node on a path blocks the collider-free path because those relationships
120
- make the conditional probabilities independent.
121
-
122
- The direction of the causal edges does impact dependence precisely in the
123
- case of a collider e.g. ``u -> v <- w``. In that situation, both ``u`` and ``w``
124
- influence ``v``. But they do not directly influence each other. So without any
125
- knowledge of any outcomes, ``u`` and ``w`` are independent. That is the idea behind
126
- colliders blocking the path. But, if ``v`` is known, the conditional probabilities
127
- of ``u`` and ``w`` can be dependent. This is the heart of Berkson's Paradox [6]_.
128
- For example, suppose ``u`` and ``w`` are boolean events (they either happen or do not)
129
- and ``v`` represents the outcome "at least one of ``u`` and ``w`` occur". Then knowing
130
- ``v`` is true makes the conditional probabilities of ``u`` and ``w`` dependent.
131
- Essentially, knowing that at least one of them is true raises the probability of
132
- each. But further knowledge that ``w`` is true (or false) change the conditional
133
- probability of ``u`` to either the original value or 1. So the conditional
134
- probability of ``u`` depends on the outcome of ``w`` even though there is no
135
- causal relationship between them. When a collider is known, dependence can
136
- occur across paths through that collider. This is the reason open colliders
137
- do not block paths.
138
-
139
- Furthermore, even if ``v`` is not "known", if one of its descendants is "known"
140
- we can use that information to know more about ``v`` which again makes
141
- ``u`` and ``w`` potentially dependent. Suppose the chance of ``n`` occurring
142
- is much higher when ``v`` occurs ("at least one of ``u`` and ``w`` occur").
143
- Then if we know ``n`` occurred, it is more likely that ``v`` occurred and that
144
- makes the chance of ``u`` and ``w`` dependent. This is the idea behind why
145
- a collider does no block a path if any descendant of the collider is "known".
146
-
147
- When two sets of nodes ``x`` and ``y`` are d-separated by a set ``z``,
148
- it means that given the outcomes of the nodes in ``z``, the probabilities
149
- of outcomes of the nodes in ``x`` are independent of the outcomes of the
150
- nodes in ``y`` and vice versa.
151
-
152
- Examples
153
- --------
154
- A Hidden Markov Model with 5 observed states and 5 hidden states
155
- where the hidden states have causal relationships resulting in
156
- a path results in the following causal network. We check that
157
- early states along the path are separated from late state in
158
- the path by the d-separator of the middle hidden state.
159
- Thus if we condition on the middle hidden state, the early
160
- state probabilities are independent of the late state outcomes.
161
-
162
- >>> G = nx.DiGraph()
163
- >>> G.add_edges_from(
164
- ... [
165
- ... ("H1", "H2"),
166
- ... ("H2", "H3"),
167
- ... ("H3", "H4"),
168
- ... ("H4", "H5"),
169
- ... ("H1", "O1"),
170
- ... ("H2", "O2"),
171
- ... ("H3", "O3"),
172
- ... ("H4", "O4"),
173
- ... ("H5", "O5"),
174
- ... ]
175
- ... )
176
- >>> x, y, z = ({"H1", "O1"}, {"H5", "O5"}, {"H3"})
177
- >>> nx.is_d_separator(G, x, y, z)
178
- True
179
- >>> nx.is_minimal_d_separator(G, x, y, z)
180
- True
181
- >>> nx.is_minimal_d_separator(G, x, y, z | {"O3"})
182
- False
183
- >>> z = nx.find_minimal_d_separator(G, x | y, {"O2", "O3", "O4"})
184
- >>> z == {"H2", "H4"}
185
- True
186
-
187
- If no minimal_d_separator exists, `None` is returned
188
-
189
- >>> other_z = nx.find_minimal_d_separator(G, x | y, {"H2", "H3"})
190
- >>> other_z is None
191
- True
192
-
193
-
194
- References
195
- ----------
196
-
197
- .. [1] Pearl, J. (2009). Causality. Cambridge: Cambridge University Press.
198
-
199
- .. [2] Darwiche, A. (2009). Modeling and reasoning with Bayesian networks.
200
- Cambridge: Cambridge University Press.
201
-
202
- .. [3] Shachter, Ross D. "Bayes-ball: The rational pastime (for
203
- determining irrelevance and requisite information in belief networks
204
- and influence diagrams)." In Proceedings of the Fourteenth Conference
205
- on Uncertainty in Artificial Intelligence (UAI), (pp. 480–487). 1998.
206
-
207
- .. [4] Koller, D., & Friedman, N. (2009).
208
- Probabilistic graphical models: principles and techniques. The MIT Press.
209
-
210
- .. [5] https://en.wikipedia.org/wiki/Causal_Markov_condition
211
-
212
- .. [6] https://en.wikipedia.org/wiki/Berkson%27s_paradox
213
-
214
- """
215
-
216
- from collections import deque
217
- from itertools import chain
218
-
219
- import networkx as nx
220
- from networkx.utils import UnionFind, not_implemented_for
221
-
222
- __all__ = [
223
- "is_d_separator",
224
- "is_minimal_d_separator",
225
- "find_minimal_d_separator",
226
- ]
227
-
228
-
229
- @not_implemented_for("undirected")
230
- @nx._dispatchable
231
- def is_d_separator(G, x, y, z):
232
- """Return whether node sets `x` and `y` are d-separated by `z`.
233
-
234
- Parameters
235
- ----------
236
- G : nx.DiGraph
237
- A NetworkX DAG.
238
-
239
- x : node or set of nodes
240
- First node or set of nodes in `G`.
241
-
242
- y : node or set of nodes
243
- Second node or set of nodes in `G`.
244
-
245
- z : node or set of nodes
246
- Potential separator (set of conditioning nodes in `G`). Can be empty set.
247
-
248
- Returns
249
- -------
250
- b : bool
251
- A boolean that is true if `x` is d-separated from `y` given `z` in `G`.
252
-
253
- Raises
254
- ------
255
- NetworkXError
256
- The *d-separation* test is commonly used on disjoint sets of
257
- nodes in acyclic directed graphs. Accordingly, the algorithm
258
- raises a :exc:`NetworkXError` if the node sets are not
259
- disjoint or if the input graph is not a DAG.
260
-
261
- NodeNotFound
262
- If any of the input nodes are not found in the graph,
263
- a :exc:`NodeNotFound` exception is raised
264
-
265
- Notes
266
- -----
267
- A d-separating set in a DAG is a set of nodes that
268
- blocks all paths between the two sets. Nodes in `z`
269
- block a path if they are part of the path and are not a collider,
270
- or a descendant of a collider. Also colliders that are not in `z`
271
- block a path. A collider structure along a path
272
- is ``... -> c <- ...`` where ``c`` is the collider node.
273
-
274
- https://en.wikipedia.org/wiki/Bayesian_network#d-separation
275
- """
276
- try:
277
- x = {x} if x in G else x
278
- y = {y} if y in G else y
279
- z = {z} if z in G else z
280
-
281
- intersection = x & y or x & z or y & z
282
- if intersection:
283
- raise nx.NetworkXError(
284
- f"The sets are not disjoint, with intersection {intersection}"
285
- )
286
-
287
- set_v = x | y | z
288
- if set_v - G.nodes:
289
- raise nx.NodeNotFound(f"The node(s) {set_v - G.nodes} are not found in G")
290
- except TypeError:
291
- raise nx.NodeNotFound("One of x, y, or z is not a node or a set of nodes in G")
292
-
293
- if not nx.is_directed_acyclic_graph(G):
294
- raise nx.NetworkXError("graph should be directed acyclic")
295
-
296
- # contains -> and <-> edges from starting node T
297
- forward_deque = deque([])
298
- forward_visited = set()
299
-
300
- # contains <- and - edges from starting node T
301
- backward_deque = deque(x)
302
- backward_visited = set()
303
-
304
- ancestors_or_z = set().union(*[nx.ancestors(G, node) for node in x]) | z | x
305
-
306
- while forward_deque or backward_deque:
307
- if backward_deque:
308
- node = backward_deque.popleft()
309
- backward_visited.add(node)
310
- if node in y:
311
- return False
312
- if node in z:
313
- continue
314
-
315
- # add <- edges to backward deque
316
- backward_deque.extend(G.pred[node].keys() - backward_visited)
317
- # add -> edges to forward deque
318
- forward_deque.extend(G.succ[node].keys() - forward_visited)
319
-
320
- if forward_deque:
321
- node = forward_deque.popleft()
322
- forward_visited.add(node)
323
- if node in y:
324
- return False
325
-
326
- # Consider if -> node <- is opened due to ancestor of node in z
327
- if node in ancestors_or_z:
328
- # add <- edges to backward deque
329
- backward_deque.extend(G.pred[node].keys() - backward_visited)
330
- if node not in z:
331
- # add -> edges to forward deque
332
- forward_deque.extend(G.succ[node].keys() - forward_visited)
333
-
334
- return True
335
-
336
-
337
- @not_implemented_for("undirected")
338
- @nx._dispatchable
339
- def find_minimal_d_separator(G, x, y, *, included=None, restricted=None):
340
- """Returns a minimal d-separating set between `x` and `y` if possible
341
-
342
- A d-separating set in a DAG is a set of nodes that blocks all
343
- paths between the two sets of nodes, `x` and `y`. This function
344
- constructs a d-separating set that is "minimal", meaning no nodes can
345
- be removed without it losing the d-separating property for `x` and `y`.
346
- If no d-separating sets exist for `x` and `y`, this returns `None`.
347
-
348
- In a DAG there may be more than one minimal d-separator between two
349
- sets of nodes. Minimal d-separators are not always unique. This function
350
- returns one minimal d-separator, or `None` if no d-separator exists.
351
-
352
- Uses the algorithm presented in [1]_. The complexity of the algorithm
353
- is :math:`O(m)`, where :math:`m` stands for the number of edges in
354
- the subgraph of G consisting of only the ancestors of `x` and `y`.
355
- For full details, see [1]_.
356
-
357
- Parameters
358
- ----------
359
- G : graph
360
- A networkx DAG.
361
- x : set | node
362
- A node or set of nodes in the graph.
363
- y : set | node
364
- A node or set of nodes in the graph.
365
- included : set | node | None
366
- A node or set of nodes which must be included in the found separating set,
367
- default is None, which means the empty set.
368
- restricted : set | node | None
369
- Restricted node or set of nodes to consider. Only these nodes can be in
370
- the found separating set, default is None meaning all nodes in ``G``.
371
-
372
- Returns
373
- -------
374
- z : set | None
375
- The minimal d-separating set, if at least one d-separating set exists,
376
- otherwise None.
377
-
378
- Raises
379
- ------
380
- NetworkXError
381
- Raises a :exc:`NetworkXError` if the input graph is not a DAG
382
- or if node sets `x`, `y`, and `included` are not disjoint.
383
-
384
- NodeNotFound
385
- If any of the input nodes are not found in the graph,
386
- a :exc:`NodeNotFound` exception is raised.
387
-
388
- References
389
- ----------
390
- .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding
391
- minimal d-separators in linear time and applications." In
392
- Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020.
393
- """
394
- if not nx.is_directed_acyclic_graph(G):
395
- raise nx.NetworkXError("graph should be directed acyclic")
396
-
397
- try:
398
- x = {x} if x in G else x
399
- y = {y} if y in G else y
400
-
401
- if included is None:
402
- included = set()
403
- elif included in G:
404
- included = {included}
405
-
406
- if restricted is None:
407
- restricted = set(G)
408
- elif restricted in G:
409
- restricted = {restricted}
410
-
411
- set_y = x | y | included | restricted
412
- if set_y - G.nodes:
413
- raise nx.NodeNotFound(f"The node(s) {set_y - G.nodes} are not found in G")
414
- except TypeError:
415
- raise nx.NodeNotFound(
416
- "One of x, y, included or restricted is not a node or set of nodes in G"
417
- )
418
-
419
- if not included <= restricted:
420
- raise nx.NetworkXError(
421
- f"Included nodes {included} must be in restricted nodes {restricted}"
422
- )
423
-
424
- intersection = x & y or x & included or y & included
425
- if intersection:
426
- raise nx.NetworkXError(
427
- f"The sets x, y, included are not disjoint. Overlap: {intersection}"
428
- )
429
-
430
- nodeset = x | y | included
431
- ancestors_x_y_included = nodeset.union(*[nx.ancestors(G, node) for node in nodeset])
432
-
433
- z_init = restricted & (ancestors_x_y_included - (x | y))
434
-
435
- x_closure = _reachable(G, x, ancestors_x_y_included, z_init)
436
- if x_closure & y:
437
- return None
438
-
439
- z_updated = z_init & (x_closure | included)
440
- y_closure = _reachable(G, y, ancestors_x_y_included, z_updated)
441
- return z_updated & (y_closure | included)
442
-
443
-
444
- @not_implemented_for("undirected")
445
- @nx._dispatchable
446
- def is_minimal_d_separator(G, x, y, z, *, included=None, restricted=None):
447
- """Determine if `z` is a minimal d-separator for `x` and `y`.
448
-
449
- A d-separator, `z`, in a DAG is a set of nodes that blocks
450
- all paths from nodes in set `x` to nodes in set `y`.
451
- A minimal d-separator is a d-separator `z` such that removing
452
- any subset of nodes makes it no longer a d-separator.
453
-
454
- Note: This function checks whether `z` is a d-separator AND is
455
- minimal. One can use the function `is_d_separator` to only check if
456
- `z` is a d-separator. See examples below.
457
-
458
- Parameters
459
- ----------
460
- G : nx.DiGraph
461
- A NetworkX DAG.
462
- x : node | set
463
- A node or set of nodes in the graph.
464
- y : node | set
465
- A node or set of nodes in the graph.
466
- z : node | set
467
- The node or set of nodes to check if it is a minimal d-separating set.
468
- The function :func:`is_d_separator` is called inside this function
469
- to verify that `z` is in fact a d-separator.
470
- included : set | node | None
471
- A node or set of nodes which must be included in the found separating set,
472
- default is ``None``, which means the empty set.
473
- restricted : set | node | None
474
- Restricted node or set of nodes to consider. Only these nodes can be in
475
- the found separating set, default is ``None`` meaning all nodes in ``G``.
476
-
477
- Returns
478
- -------
479
- bool
480
- Whether or not the set `z` is a minimal d-separator subject to
481
- `restricted` nodes and `included` node constraints.
482
-
483
- Examples
484
- --------
485
- >>> G = nx.path_graph([0, 1, 2, 3], create_using=nx.DiGraph)
486
- >>> G.add_node(4)
487
- >>> nx.is_minimal_d_separator(G, 0, 2, {1})
488
- True
489
- >>> # since {1} is the minimal d-separator, {1, 3, 4} is not minimal
490
- >>> nx.is_minimal_d_separator(G, 0, 2, {1, 3, 4})
491
- False
492
- >>> # alternatively, if we only want to check that {1, 3, 4} is a d-separator
493
- >>> nx.is_d_separator(G, 0, 2, {1, 3, 4})
494
- True
495
-
496
- Raises
497
- ------
498
- NetworkXError
499
- Raises a :exc:`NetworkXError` if the input graph is not a DAG.
500
-
501
- NodeNotFound
502
- If any of the input nodes are not found in the graph,
503
- a :exc:`NodeNotFound` exception is raised.
504
-
505
- References
506
- ----------
507
- .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding
508
- minimal d-separators in linear time and applications." In
509
- Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020.
510
-
511
- Notes
512
- -----
513
- This function works on verifying that a set is minimal and
514
- d-separating between two nodes. Uses criterion (a), (b), (c) on
515
- page 4 of [1]_. a) closure(`x`) and `y` are disjoint. b) `z` contains
516
- all nodes from `included` and is contained in the `restricted`
517
- nodes and in the union of ancestors of `x`, `y`, and `included`.
518
- c) the nodes in `z` not in `included` are contained in both
519
- closure(x) and closure(y). The closure of a set is the set of nodes
520
- connected to the set by a directed path in G.
521
-
522
- The complexity is :math:`O(m)`, where :math:`m` stands for the
523
- number of edges in the subgraph of G consisting of only the
524
- ancestors of `x` and `y`.
525
-
526
- For full details, see [1]_.
527
- """
528
- if not nx.is_directed_acyclic_graph(G):
529
- raise nx.NetworkXError("graph should be directed acyclic")
530
-
531
- try:
532
- x = {x} if x in G else x
533
- y = {y} if y in G else y
534
- z = {z} if z in G else z
535
-
536
- if included is None:
537
- included = set()
538
- elif included in G:
539
- included = {included}
540
-
541
- if restricted is None:
542
- restricted = set(G)
543
- elif restricted in G:
544
- restricted = {restricted}
545
-
546
- set_y = x | y | included | restricted
547
- if set_y - G.nodes:
548
- raise nx.NodeNotFound(f"The node(s) {set_y - G.nodes} are not found in G")
549
- except TypeError:
550
- raise nx.NodeNotFound(
551
- "One of x, y, z, included or restricted is not a node or set of nodes in G"
552
- )
553
-
554
- if not included <= z:
555
- raise nx.NetworkXError(
556
- f"Included nodes {included} must be in proposed separating set z {x}"
557
- )
558
- if not z <= restricted:
559
- raise nx.NetworkXError(
560
- f"Separating set {z} must be contained in restricted set {restricted}"
561
- )
562
-
563
- intersection = x.intersection(y) or x.intersection(z) or y.intersection(z)
564
- if intersection:
565
- raise nx.NetworkXError(
566
- f"The sets are not disjoint, with intersection {intersection}"
567
- )
568
-
569
- nodeset = x | y | included
570
- ancestors_x_y_included = nodeset.union(*[nx.ancestors(G, n) for n in nodeset])
571
-
572
- # criterion (a) -- check that z is actually a separator
573
- x_closure = _reachable(G, x, ancestors_x_y_included, z)
574
- if x_closure & y:
575
- return False
576
-
577
- # criterion (b) -- basic constraint; included and restricted already checked above
578
- if not (z <= ancestors_x_y_included):
579
- return False
580
-
581
- # criterion (c) -- check that z is minimal
582
- y_closure = _reachable(G, y, ancestors_x_y_included, z)
583
- if not ((z - included) <= (x_closure & y_closure)):
584
- return False
585
- return True
586
-
587
-
588
- @not_implemented_for("undirected")
589
- def _reachable(G, x, a, z):
590
- """Modified Bayes-Ball algorithm for finding d-connected nodes.
591
-
592
- Find all nodes in `a` that are d-connected to those in `x` by
593
- those in `z`. This is an implementation of the function
594
- `REACHABLE` in [1]_ (which is itself a modification of the
595
- Bayes-Ball algorithm [2]_) when restricted to DAGs.
596
-
597
- Parameters
598
- ----------
599
- G : nx.DiGraph
600
- A NetworkX DAG.
601
- x : node | set
602
- A node in the DAG, or a set of nodes.
603
- a : node | set
604
- A (set of) node(s) in the DAG containing the ancestors of `x`.
605
- z : node | set
606
- The node or set of nodes conditioned on when checking d-connectedness.
607
-
608
- Returns
609
- -------
610
- w : set
611
- The closure of `x` in `a` with respect to d-connectedness
612
- given `z`.
613
-
614
- References
615
- ----------
616
- .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding
617
- minimal d-separators in linear time and applications." In
618
- Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020.
619
-
620
- .. [2] Shachter, Ross D. "Bayes-ball: The rational pastime
621
- (for determining irrelevance and requisite information in
622
- belief networks and influence diagrams)." In Proceedings of the
623
- Fourteenth Conference on Uncertainty in Artificial Intelligence
624
- (UAI), (pp. 480–487). 1998.
625
- """
626
-
627
- def _pass(e, v, f, n):
628
- """Whether a ball entering node `v` along edge `e` passes to `n` along `f`.
629
-
630
- Boolean function defined on page 6 of [1]_.
631
-
632
- Parameters
633
- ----------
634
- e : bool
635
- Directed edge by which the ball got to node `v`; `True` iff directed into `v`.
636
- v : node
637
- Node where the ball is.
638
- f : bool
639
- Directed edge connecting nodes `v` and `n`; `True` iff directed `n`.
640
- n : node
641
- Checking whether the ball passes to this node.
642
-
643
- Returns
644
- -------
645
- b : bool
646
- Whether the ball passes or not.
647
-
648
- References
649
- ----------
650
- .. [1] van der Zander, Benito, and Maciej Liśkiewicz. "Finding
651
- minimal d-separators in linear time and applications." In
652
- Uncertainty in Artificial Intelligence, pp. 637-647. PMLR, 2020.
653
- """
654
- is_element_of_A = n in a
655
- # almost_definite_status = True # always true for DAGs; not so for RCGs
656
- collider_if_in_Z = v not in z or (e and not f)
657
- return is_element_of_A and collider_if_in_Z # and almost_definite_status
658
-
659
- queue = deque([])
660
- for node in x:
661
- if bool(G.pred[node]):
662
- queue.append((True, node))
663
- if bool(G.succ[node]):
664
- queue.append((False, node))
665
- processed = queue.copy()
666
-
667
- while any(queue):
668
- e, v = queue.popleft()
669
- preds = ((False, n) for n in G.pred[v])
670
- succs = ((True, n) for n in G.succ[v])
671
- f_n_pairs = chain(preds, succs)
672
- for f, n in f_n_pairs:
673
- if (f, n) not in processed and _pass(e, v, f, n):
674
- queue.append((f, n))
675
- processed.append((f, n))
676
-
677
- return {w for (_, w) in processed}