okstra 0.130.4 → 0.131.1
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.
- package/README.md +0 -1
- package/docs/architecture.md +2 -2
- package/docs/cli.md +1 -1
- package/docs/for-ai/README.md +0 -2
- package/docs/for-ai/skills/okstra-run.md +13 -2
- package/docs/for-ai/skills/okstra-setup.md +4 -1
- package/docs/project-structure-overview.md +5 -4
- package/docs/task-process/implementation-planning.md +13 -0
- package/docs/task-process/implementation.md +17 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +7 -0
- package/runtime/bin/lib/okstra/usage.sh +4 -4
- package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
- package/runtime/prompts/lead/plan-body-verification.md +26 -5
- package/runtime/prompts/lead/report-writer.md +6 -2
- package/runtime/prompts/profiles/_common-contract.md +2 -1
- package/runtime/prompts/profiles/_implementation-deliverable.md +6 -1
- package/runtime/prompts/profiles/_implementation-executor.md +2 -2
- package/runtime/prompts/profiles/_implementation-verifier.md +33 -10
- package/runtime/prompts/profiles/final-verification.md +21 -6
- package/runtime/prompts/profiles/implementation-planning.md +16 -4
- package/runtime/python/okstra_ctl/codex_dispatch.py +31 -0
- package/runtime/python/okstra_ctl/conformance.py +49 -11
- package/runtime/python/okstra_ctl/report_finalize.py +52 -1
- package/runtime/python/okstra_ctl/run.py +15 -3
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +14 -6
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +19 -1
- package/runtime/python/okstra_vendor/__init__.py +0 -44
- package/runtime/schemas/final-report-v1.0.schema.json +99 -5
- package/runtime/skills/okstra-run/SKILL.md +11 -4
- package/runtime/skills/okstra-setup/SKILL.md +3 -2
- package/runtime/skills/okstra-setup/references/project-config.md +16 -7
- package/runtime/templates/reports/final-report.template.md +15 -9
- package/runtime/templates/reports/i18n/en.json +1 -0
- package/runtime/templates/reports/i18n/ko.json +1 -0
- package/runtime/validators/lib/fixtures.sh +6 -0
- package/runtime/validators/validate-run.py +2019 -96
- package/src/cli-registry.mjs +0 -7
- package/src/commands/lifecycle/doctor.mjs +0 -9
- package/src/lib/skill-catalog.mjs +0 -1
- package/docs/for-ai/skills/okstra-graphify.md +0 -64
- package/runtime/python/okstra_ctl/graphify_cmd.py +0 -225
- package/runtime/python/okstra_vendor/graphify/.vendored-version +0 -1
- package/runtime/python/okstra_vendor/graphify/__init__.py +0 -28
- package/runtime/python/okstra_vendor/graphify/__main__.py +0 -1371
- package/runtime/python/okstra_vendor/graphify/analyze.py +0 -540
- package/runtime/python/okstra_vendor/graphify/benchmark.py +0 -129
- package/runtime/python/okstra_vendor/graphify/build.py +0 -107
- package/runtime/python/okstra_vendor/graphify/cache.py +0 -169
- package/runtime/python/okstra_vendor/graphify/cluster.py +0 -137
- package/runtime/python/okstra_vendor/graphify/detect.py +0 -510
- package/runtime/python/okstra_vendor/graphify/export.py +0 -1014
- package/runtime/python/okstra_vendor/graphify/extract.py +0 -3277
- package/runtime/python/okstra_vendor/graphify/hooks.py +0 -220
- package/runtime/python/okstra_vendor/graphify/ingest.py +0 -297
- package/runtime/python/okstra_vendor/graphify/manifest.py +0 -4
- package/runtime/python/okstra_vendor/graphify/report.py +0 -175
- package/runtime/python/okstra_vendor/graphify/security.py +0 -203
- package/runtime/python/okstra_vendor/graphify/serve.py +0 -373
- package/runtime/python/okstra_vendor/graphify/skill-aider.md +0 -1184
- package/runtime/python/okstra_vendor/graphify/skill-claw.md +0 -1184
- package/runtime/python/okstra_vendor/graphify/skill-codex.md +0 -1242
- package/runtime/python/okstra_vendor/graphify/skill-copilot.md +0 -1268
- package/runtime/python/okstra_vendor/graphify/skill-droid.md +0 -1239
- package/runtime/python/okstra_vendor/graphify/skill-kiro.md +0 -1183
- package/runtime/python/okstra_vendor/graphify/skill-opencode.md +0 -1238
- package/runtime/python/okstra_vendor/graphify/skill-trae.md +0 -1208
- package/runtime/python/okstra_vendor/graphify/skill-vscode.md +0 -253
- package/runtime/python/okstra_vendor/graphify/skill-windows.md +0 -1245
- package/runtime/python/okstra_vendor/graphify/skill.md +0 -1319
- package/runtime/python/okstra_vendor/graphify/transcribe.py +0 -182
- package/runtime/python/okstra_vendor/graphify/validate.py +0 -72
- package/runtime/python/okstra_vendor/graphify/watch.py +0 -188
- package/runtime/python/okstra_vendor/graphify/wiki.py +0 -214
- package/runtime/python/okstra_vendor/networkx/__init__.py +0 -62
- package/runtime/python/okstra_vendor/networkx/algorithms/__init__.py +0 -134
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/__init__.py +0 -26
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clique.py +0 -259
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clustering_coefficient.py +0 -71
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/connectivity.py +0 -412
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/density.py +0 -396
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/distance_measures.py +0 -150
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/dominating_set.py +0 -149
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/kcomponents.py +0 -369
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/matching.py +0 -44
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/maxcut.py +0 -143
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/ramsey.py +0 -53
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/steinertree.py +0 -265
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/traveling_salesman.py +0 -1508
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/treewidth.py +0 -255
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/vertex_cover.py +0 -83
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/__init__.py +0 -5
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/connectivity.py +0 -122
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/correlation.py +0 -302
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/mixing.py +0 -255
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/neighbor_degree.py +0 -160
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/pairs.py +0 -127
- package/runtime/python/okstra_vendor/networkx/algorithms/asteroidal.py +0 -164
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/__init__.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/basic.py +0 -322
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/centrality.py +0 -290
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/cluster.py +0 -289
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/covering.py +0 -57
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/edgelist.py +0 -360
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/extendability.py +0 -105
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/generators.py +0 -603
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/link_analysis.py +0 -316
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matching.py +0 -590
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matrix.py +0 -232
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/projection.py +0 -526
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/redundancy.py +0 -112
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/spectral.py +0 -69
- package/runtime/python/okstra_vendor/networkx/algorithms/boundary.py +0 -168
- package/runtime/python/okstra_vendor/networkx/algorithms/bridges.py +0 -205
- package/runtime/python/okstra_vendor/networkx/algorithms/broadcasting.py +0 -164
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/__init__.py +0 -20
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness.py +0 -591
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness_subset.py +0 -236
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/closeness.py +0 -282
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness.py +0 -364
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness_subset.py +0 -227
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_closeness.py +0 -96
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/degree_alg.py +0 -150
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/dispersion.py +0 -107
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/eigenvector.py +0 -357
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/flow_matrix.py +0 -130
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/group.py +0 -787
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/harmonic.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/katz.py +0 -331
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/laplacian.py +0 -150
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/load.py +0 -200
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/percolation.py +0 -128
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/reaching.py +0 -209
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/second_order.py +0 -141
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/subgraph_alg.py +0 -361
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/trophic.py +0 -181
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/voterank_alg.py +0 -95
- package/runtime/python/okstra_vendor/networkx/algorithms/chains.py +0 -172
- package/runtime/python/okstra_vendor/networkx/algorithms/chordal.py +0 -443
- package/runtime/python/okstra_vendor/networkx/algorithms/clique.py +0 -818
- package/runtime/python/okstra_vendor/networkx/algorithms/cluster.py +0 -732
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/__init__.py +0 -4
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/equitable_coloring.py +0 -505
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/greedy_coloring.py +0 -565
- package/runtime/python/okstra_vendor/networkx/algorithms/communicability_alg.py +0 -163
- package/runtime/python/okstra_vendor/networkx/algorithms/community/__init__.py +0 -28
- package/runtime/python/okstra_vendor/networkx/algorithms/community/asyn_fluid.py +0 -153
- package/runtime/python/okstra_vendor/networkx/algorithms/community/bipartitions.py +0 -354
- package/runtime/python/okstra_vendor/networkx/algorithms/community/centrality.py +0 -171
- package/runtime/python/okstra_vendor/networkx/algorithms/community/community_utils.py +0 -30
- package/runtime/python/okstra_vendor/networkx/algorithms/community/divisive.py +0 -216
- package/runtime/python/okstra_vendor/networkx/algorithms/community/kclique.py +0 -79
- package/runtime/python/okstra_vendor/networkx/algorithms/community/label_propagation.py +0 -338
- package/runtime/python/okstra_vendor/networkx/algorithms/community/leiden.py +0 -162
- package/runtime/python/okstra_vendor/networkx/algorithms/community/local.py +0 -220
- package/runtime/python/okstra_vendor/networkx/algorithms/community/louvain.py +0 -384
- package/runtime/python/okstra_vendor/networkx/algorithms/community/lukes.py +0 -227
- package/runtime/python/okstra_vendor/networkx/algorithms/community/modularity_max.py +0 -452
- package/runtime/python/okstra_vendor/networkx/algorithms/community/quality.py +0 -347
- package/runtime/python/okstra_vendor/networkx/algorithms/components/__init__.py +0 -6
- package/runtime/python/okstra_vendor/networkx/algorithms/components/attracting.py +0 -115
- package/runtime/python/okstra_vendor/networkx/algorithms/components/biconnected.py +0 -394
- package/runtime/python/okstra_vendor/networkx/algorithms/components/connected.py +0 -282
- package/runtime/python/okstra_vendor/networkx/algorithms/components/semiconnected.py +0 -71
- package/runtime/python/okstra_vendor/networkx/algorithms/components/strongly_connected.py +0 -359
- package/runtime/python/okstra_vendor/networkx/algorithms/components/weakly_connected.py +0 -196
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/__init__.py +0 -11
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/connectivity.py +0 -811
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/cuts.py +0 -616
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/disjoint_paths.py +0 -408
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_augmentation.py +0 -1270
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_kcomponents.py +0 -592
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcomponents.py +0 -220
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcutsets.py +0 -235
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/stoerwagner.py +0 -152
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/utils.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/core.py +0 -588
- package/runtime/python/okstra_vendor/networkx/algorithms/covering.py +0 -142
- package/runtime/python/okstra_vendor/networkx/algorithms/cuts.py +0 -416
- package/runtime/python/okstra_vendor/networkx/algorithms/cycles.py +0 -1234
- package/runtime/python/okstra_vendor/networkx/algorithms/d_separation.py +0 -677
- package/runtime/python/okstra_vendor/networkx/algorithms/dag.py +0 -1392
- package/runtime/python/okstra_vendor/networkx/algorithms/distance_measures.py +0 -1095
- package/runtime/python/okstra_vendor/networkx/algorithms/distance_regular.py +0 -272
- package/runtime/python/okstra_vendor/networkx/algorithms/dominance.py +0 -142
- package/runtime/python/okstra_vendor/networkx/algorithms/dominating.py +0 -268
- package/runtime/python/okstra_vendor/networkx/algorithms/efficiency_measures.py +0 -167
- package/runtime/python/okstra_vendor/networkx/algorithms/euler.py +0 -470
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/__init__.py +0 -11
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/boykovkolmogorov.py +0 -370
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/capacityscaling.py +0 -407
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/dinitz_alg.py +0 -238
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/edmondskarp.py +0 -241
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/gomory_hu.py +0 -178
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/maxflow.py +0 -611
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/mincost.py +0 -356
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/networksimplex.py +0 -662
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/preflowpush.py +0 -425
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/shortestaugmentingpath.py +0 -300
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/utils.py +0 -194
- package/runtime/python/okstra_vendor/networkx/algorithms/graph_hashing.py +0 -435
- package/runtime/python/okstra_vendor/networkx/algorithms/graphical.py +0 -483
- package/runtime/python/okstra_vendor/networkx/algorithms/hierarchy.py +0 -57
- package/runtime/python/okstra_vendor/networkx/algorithms/hybrid.py +0 -196
- package/runtime/python/okstra_vendor/networkx/algorithms/isolate.py +0 -107
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/__init__.py +0 -7
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/ismags.py +0 -1306
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorph.py +0 -336
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorphvf2.py +0 -1262
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/matchhelpers.py +0 -352
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/temporalisomorphvf2.py +0 -308
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tree_isomorphism.py +0 -264
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2pp.py +0 -1102
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2userfunc.py +0 -192
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/__init__.py +0 -2
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/hits_alg.py +0 -337
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/pagerank_alg.py +0 -498
- package/runtime/python/okstra_vendor/networkx/algorithms/link_prediction.py +0 -687
- package/runtime/python/okstra_vendor/networkx/algorithms/lowest_common_ancestors.py +0 -280
- package/runtime/python/okstra_vendor/networkx/algorithms/matching.py +0 -1148
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/__init__.py +0 -27
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/contraction.py +0 -738
- package/runtime/python/okstra_vendor/networkx/algorithms/mis.py +0 -78
- package/runtime/python/okstra_vendor/networkx/algorithms/moral.py +0 -59
- package/runtime/python/okstra_vendor/networkx/algorithms/node_classification.py +0 -219
- package/runtime/python/okstra_vendor/networkx/algorithms/non_randomness.py +0 -155
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/__init__.py +0 -4
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/all.py +0 -324
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/binary.py +0 -468
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/product.py +0 -633
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/unary.py +0 -77
- package/runtime/python/okstra_vendor/networkx/algorithms/perfect_graph.py +0 -73
- package/runtime/python/okstra_vendor/networkx/algorithms/planar_drawing.py +0 -464
- package/runtime/python/okstra_vendor/networkx/algorithms/planarity.py +0 -1463
- package/runtime/python/okstra_vendor/networkx/algorithms/polynomials.py +0 -306
- package/runtime/python/okstra_vendor/networkx/algorithms/reciprocity.py +0 -98
- package/runtime/python/okstra_vendor/networkx/algorithms/regular.py +0 -167
- package/runtime/python/okstra_vendor/networkx/algorithms/richclub.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/__init__.py +0 -5
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/astar.py +0 -239
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/dense.py +0 -264
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/generic.py +0 -716
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/unweighted.py +0 -625
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/weighted.py +0 -2542
- package/runtime/python/okstra_vendor/networkx/algorithms/similarity.py +0 -2107
- package/runtime/python/okstra_vendor/networkx/algorithms/simple_paths.py +0 -966
- package/runtime/python/okstra_vendor/networkx/algorithms/smallworld.py +0 -404
- package/runtime/python/okstra_vendor/networkx/algorithms/smetric.py +0 -30
- package/runtime/python/okstra_vendor/networkx/algorithms/sparsifiers.py +0 -296
- package/runtime/python/okstra_vendor/networkx/algorithms/structuralholes.py +0 -374
- package/runtime/python/okstra_vendor/networkx/algorithms/summarization.py +0 -564
- package/runtime/python/okstra_vendor/networkx/algorithms/swap.py +0 -406
- package/runtime/python/okstra_vendor/networkx/algorithms/threshold.py +0 -981
- package/runtime/python/okstra_vendor/networkx/algorithms/time_dependent.py +0 -142
- package/runtime/python/okstra_vendor/networkx/algorithms/tournament.py +0 -406
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/__init__.py +0 -5
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/beamsearch.py +0 -90
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/breadth_first_search.py +0 -576
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/depth_first_search.py +0 -529
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgebfs.py +0 -185
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgedfs.py +0 -182
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/__init__.py +0 -7
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/branchings.py +0 -1042
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/coding.py +0 -413
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/decomposition.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/distance_measures.py +0 -219
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/mst.py +0 -1281
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/operations.py +0 -106
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/recognition.py +0 -273
- package/runtime/python/okstra_vendor/networkx/algorithms/triads.py +0 -500
- package/runtime/python/okstra_vendor/networkx/algorithms/vitality.py +0 -76
- package/runtime/python/okstra_vendor/networkx/algorithms/voronoi.py +0 -86
- package/runtime/python/okstra_vendor/networkx/algorithms/walks.py +0 -77
- package/runtime/python/okstra_vendor/networkx/algorithms/wiener.py +0 -278
- package/runtime/python/okstra_vendor/networkx/classes/__init__.py +0 -13
- package/runtime/python/okstra_vendor/networkx/classes/coreviews.py +0 -435
- package/runtime/python/okstra_vendor/networkx/classes/digraph.py +0 -1363
- package/runtime/python/okstra_vendor/networkx/classes/filters.py +0 -95
- package/runtime/python/okstra_vendor/networkx/classes/function.py +0 -1549
- package/runtime/python/okstra_vendor/networkx/classes/graph.py +0 -2082
- package/runtime/python/okstra_vendor/networkx/classes/graphviews.py +0 -269
- package/runtime/python/okstra_vendor/networkx/classes/multidigraph.py +0 -977
- package/runtime/python/okstra_vendor/networkx/classes/multigraph.py +0 -1294
- package/runtime/python/okstra_vendor/networkx/classes/reportviews.py +0 -1447
- package/runtime/python/okstra_vendor/networkx/convert.py +0 -502
- package/runtime/python/okstra_vendor/networkx/convert_matrix.py +0 -1314
- package/runtime/python/okstra_vendor/networkx/drawing/__init__.py +0 -7
- package/runtime/python/okstra_vendor/networkx/drawing/layout.py +0 -2036
- package/runtime/python/okstra_vendor/networkx/drawing/nx_agraph.py +0 -470
- package/runtime/python/okstra_vendor/networkx/drawing/nx_latex.py +0 -570
- package/runtime/python/okstra_vendor/networkx/drawing/nx_pydot.py +0 -361
- package/runtime/python/okstra_vendor/networkx/drawing/nx_pylab.py +0 -2978
- package/runtime/python/okstra_vendor/networkx/exception.py +0 -131
- package/runtime/python/okstra_vendor/networkx/generators/__init__.py +0 -34
- package/runtime/python/okstra_vendor/networkx/generators/atlas.dat.gz +0 -0
- package/runtime/python/okstra_vendor/networkx/generators/atlas.py +0 -227
- package/runtime/python/okstra_vendor/networkx/generators/classic.py +0 -1091
- package/runtime/python/okstra_vendor/networkx/generators/cographs.py +0 -68
- package/runtime/python/okstra_vendor/networkx/generators/community.py +0 -1070
- package/runtime/python/okstra_vendor/networkx/generators/degree_seq.py +0 -886
- package/runtime/python/okstra_vendor/networkx/generators/directed.py +0 -572
- package/runtime/python/okstra_vendor/networkx/generators/duplication.py +0 -174
- package/runtime/python/okstra_vendor/networkx/generators/ego.py +0 -66
- package/runtime/python/okstra_vendor/networkx/generators/expanders.py +0 -499
- package/runtime/python/okstra_vendor/networkx/generators/geometric.py +0 -1037
- package/runtime/python/okstra_vendor/networkx/generators/harary_graph.py +0 -163
- package/runtime/python/okstra_vendor/networkx/generators/internet_as_graphs.py +0 -443
- package/runtime/python/okstra_vendor/networkx/generators/intersection.py +0 -125
- package/runtime/python/okstra_vendor/networkx/generators/interval_graph.py +0 -70
- package/runtime/python/okstra_vendor/networkx/generators/joint_degree_seq.py +0 -664
- package/runtime/python/okstra_vendor/networkx/generators/lattice.py +0 -405
- package/runtime/python/okstra_vendor/networkx/generators/line.py +0 -501
- package/runtime/python/okstra_vendor/networkx/generators/mycielski.py +0 -110
- package/runtime/python/okstra_vendor/networkx/generators/nonisomorphic_trees.py +0 -259
- package/runtime/python/okstra_vendor/networkx/generators/random_clustered.py +0 -117
- package/runtime/python/okstra_vendor/networkx/generators/random_graphs.py +0 -1416
- package/runtime/python/okstra_vendor/networkx/generators/small.py +0 -1070
- package/runtime/python/okstra_vendor/networkx/generators/social.py +0 -554
- package/runtime/python/okstra_vendor/networkx/generators/spectral_graph_forge.py +0 -120
- package/runtime/python/okstra_vendor/networkx/generators/stochastic.py +0 -54
- package/runtime/python/okstra_vendor/networkx/generators/sudoku.py +0 -131
- package/runtime/python/okstra_vendor/networkx/generators/time_series.py +0 -74
- package/runtime/python/okstra_vendor/networkx/generators/trees.py +0 -1070
- package/runtime/python/okstra_vendor/networkx/generators/triads.py +0 -94
- package/runtime/python/okstra_vendor/networkx/lazy_imports.py +0 -188
- package/runtime/python/okstra_vendor/networkx/linalg/__init__.py +0 -13
- package/runtime/python/okstra_vendor/networkx/linalg/algebraicconnectivity.py +0 -650
- package/runtime/python/okstra_vendor/networkx/linalg/attrmatrix.py +0 -466
- package/runtime/python/okstra_vendor/networkx/linalg/bethehessianmatrix.py +0 -77
- package/runtime/python/okstra_vendor/networkx/linalg/graphmatrix.py +0 -168
- package/runtime/python/okstra_vendor/networkx/linalg/laplacianmatrix.py +0 -512
- package/runtime/python/okstra_vendor/networkx/linalg/modularitymatrix.py +0 -166
- package/runtime/python/okstra_vendor/networkx/linalg/spectrum.py +0 -186
- package/runtime/python/okstra_vendor/networkx/readwrite/__init__.py +0 -17
- package/runtime/python/okstra_vendor/networkx/readwrite/adjlist.py +0 -330
- package/runtime/python/okstra_vendor/networkx/readwrite/edgelist.py +0 -489
- package/runtime/python/okstra_vendor/networkx/readwrite/gexf.py +0 -1084
- package/runtime/python/okstra_vendor/networkx/readwrite/gml.py +0 -879
- package/runtime/python/okstra_vendor/networkx/readwrite/graph6.py +0 -427
- package/runtime/python/okstra_vendor/networkx/readwrite/graphml.py +0 -1053
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/__init__.py +0 -19
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/adjacency.py +0 -156
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/cytoscape.py +0 -190
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/node_link.py +0 -261
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tree.py +0 -137
- package/runtime/python/okstra_vendor/networkx/readwrite/leda.py +0 -108
- package/runtime/python/okstra_vendor/networkx/readwrite/multiline_adjlist.py +0 -393
- package/runtime/python/okstra_vendor/networkx/readwrite/p2g.py +0 -113
- package/runtime/python/okstra_vendor/networkx/readwrite/pajek.py +0 -286
- package/runtime/python/okstra_vendor/networkx/readwrite/sparse6.py +0 -379
- package/runtime/python/okstra_vendor/networkx/readwrite/text.py +0 -851
- package/runtime/python/okstra_vendor/networkx/relabel.py +0 -285
- package/runtime/python/okstra_vendor/networkx/utils/__init__.py +0 -8
- package/runtime/python/okstra_vendor/networkx/utils/backends.py +0 -2171
- package/runtime/python/okstra_vendor/networkx/utils/configs.py +0 -396
- package/runtime/python/okstra_vendor/networkx/utils/decorators.py +0 -1233
- package/runtime/python/okstra_vendor/networkx/utils/heaps.py +0 -338
- package/runtime/python/okstra_vendor/networkx/utils/mapped_queue.py +0 -297
- package/runtime/python/okstra_vendor/networkx/utils/misc.py +0 -703
- package/runtime/python/okstra_vendor/networkx/utils/random_sequence.py +0 -198
- package/runtime/python/okstra_vendor/networkx/utils/rcm.py +0 -159
- package/runtime/python/okstra_vendor/networkx/utils/union_find.py +0 -106
- package/runtime/skills/okstra-graphify/SKILL.md +0 -169
- package/src/commands/graphify.mjs +0 -32
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Shortest augmenting path algorithm for maximum flow problems.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from collections import deque
|
|
6
|
-
|
|
7
|
-
import networkx as nx
|
|
8
|
-
|
|
9
|
-
from .edmondskarp import edmonds_karp_core
|
|
10
|
-
from .utils import CurrentEdge, build_residual_network
|
|
11
|
-
|
|
12
|
-
__all__ = ["shortest_augmenting_path"]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def shortest_augmenting_path_impl(G, s, t, capacity, residual, two_phase, cutoff):
|
|
16
|
-
"""Implementation of the shortest augmenting path algorithm."""
|
|
17
|
-
if s not in G:
|
|
18
|
-
raise nx.NetworkXError(f"node {str(s)} not in graph")
|
|
19
|
-
if t not in G:
|
|
20
|
-
raise nx.NetworkXError(f"node {str(t)} not in graph")
|
|
21
|
-
if s == t:
|
|
22
|
-
raise nx.NetworkXError("source and sink are the same node")
|
|
23
|
-
|
|
24
|
-
if residual is None:
|
|
25
|
-
R = build_residual_network(G, capacity)
|
|
26
|
-
else:
|
|
27
|
-
R = residual
|
|
28
|
-
|
|
29
|
-
R_nodes = R.nodes
|
|
30
|
-
R_pred = R.pred
|
|
31
|
-
R_succ = R.succ
|
|
32
|
-
|
|
33
|
-
# Initialize/reset the residual network.
|
|
34
|
-
for u in R:
|
|
35
|
-
for e in R_succ[u].values():
|
|
36
|
-
e["flow"] = 0
|
|
37
|
-
|
|
38
|
-
# Initialize heights of the nodes.
|
|
39
|
-
heights = {t: 0}
|
|
40
|
-
q = deque([(t, 0)])
|
|
41
|
-
while q:
|
|
42
|
-
u, height = q.popleft()
|
|
43
|
-
height += 1
|
|
44
|
-
for v, attr in R_pred[u].items():
|
|
45
|
-
if v not in heights and attr["flow"] < attr["capacity"]:
|
|
46
|
-
heights[v] = height
|
|
47
|
-
q.append((v, height))
|
|
48
|
-
|
|
49
|
-
if s not in heights:
|
|
50
|
-
# t is not reachable from s in the residual network. The maximum flow
|
|
51
|
-
# must be zero.
|
|
52
|
-
R.graph["flow_value"] = 0
|
|
53
|
-
return R
|
|
54
|
-
|
|
55
|
-
n = len(G)
|
|
56
|
-
m = R.size() / 2
|
|
57
|
-
|
|
58
|
-
# Initialize heights and 'current edge' data structures of the nodes.
|
|
59
|
-
for u in R:
|
|
60
|
-
R_nodes[u]["height"] = heights[u] if u in heights else n
|
|
61
|
-
R_nodes[u]["curr_edge"] = CurrentEdge(R_succ[u])
|
|
62
|
-
|
|
63
|
-
# Initialize counts of nodes in each level.
|
|
64
|
-
counts = [0] * (2 * n - 1)
|
|
65
|
-
for u in R:
|
|
66
|
-
counts[R_nodes[u]["height"]] += 1
|
|
67
|
-
|
|
68
|
-
inf = R.graph["inf"]
|
|
69
|
-
|
|
70
|
-
def augment(path):
|
|
71
|
-
"""Augment flow along a path from s to t."""
|
|
72
|
-
# Determine the path residual capacity.
|
|
73
|
-
flow = inf
|
|
74
|
-
it = iter(path)
|
|
75
|
-
u = next(it)
|
|
76
|
-
for v in it:
|
|
77
|
-
attr = R_succ[u][v]
|
|
78
|
-
flow = min(flow, attr["capacity"] - attr["flow"])
|
|
79
|
-
u = v
|
|
80
|
-
if flow * 2 > inf:
|
|
81
|
-
raise nx.NetworkXUnbounded("Infinite capacity path, flow unbounded above.")
|
|
82
|
-
# Augment flow along the path.
|
|
83
|
-
it = iter(path)
|
|
84
|
-
u = next(it)
|
|
85
|
-
for v in it:
|
|
86
|
-
R_succ[u][v]["flow"] += flow
|
|
87
|
-
R_succ[v][u]["flow"] -= flow
|
|
88
|
-
u = v
|
|
89
|
-
return flow
|
|
90
|
-
|
|
91
|
-
def relabel(u):
|
|
92
|
-
"""Relabel a node to create an admissible edge."""
|
|
93
|
-
height = n - 1
|
|
94
|
-
for v, attr in R_succ[u].items():
|
|
95
|
-
if attr["flow"] < attr["capacity"]:
|
|
96
|
-
height = min(height, R_nodes[v]["height"])
|
|
97
|
-
return height + 1
|
|
98
|
-
|
|
99
|
-
if cutoff is None:
|
|
100
|
-
cutoff = float("inf")
|
|
101
|
-
|
|
102
|
-
# Phase 1: Look for shortest augmenting paths using depth-first search.
|
|
103
|
-
|
|
104
|
-
flow_value = 0
|
|
105
|
-
path = [s]
|
|
106
|
-
u = s
|
|
107
|
-
d = n if not two_phase else int(min(m**0.5, 2 * n ** (2.0 / 3)))
|
|
108
|
-
done = R_nodes[s]["height"] >= d
|
|
109
|
-
while not done:
|
|
110
|
-
height = R_nodes[u]["height"]
|
|
111
|
-
curr_edge = R_nodes[u]["curr_edge"]
|
|
112
|
-
# Depth-first search for the next node on the path to t.
|
|
113
|
-
while True:
|
|
114
|
-
v, attr = curr_edge.get()
|
|
115
|
-
if height == R_nodes[v]["height"] + 1 and attr["flow"] < attr["capacity"]:
|
|
116
|
-
# Advance to the next node following an admissible edge.
|
|
117
|
-
path.append(v)
|
|
118
|
-
u = v
|
|
119
|
-
break
|
|
120
|
-
try:
|
|
121
|
-
curr_edge.move_to_next()
|
|
122
|
-
except StopIteration:
|
|
123
|
-
counts[height] -= 1
|
|
124
|
-
if counts[height] == 0:
|
|
125
|
-
# Gap heuristic: If relabeling causes a level to become
|
|
126
|
-
# empty, a minimum cut has been identified. The algorithm
|
|
127
|
-
# can now be terminated.
|
|
128
|
-
R.graph["flow_value"] = flow_value
|
|
129
|
-
return R
|
|
130
|
-
height = relabel(u)
|
|
131
|
-
if u == s and height >= d:
|
|
132
|
-
if not two_phase:
|
|
133
|
-
# t is disconnected from s in the residual network. No
|
|
134
|
-
# more augmenting paths exist.
|
|
135
|
-
R.graph["flow_value"] = flow_value
|
|
136
|
-
return R
|
|
137
|
-
else:
|
|
138
|
-
# t is at least d steps away from s. End of phase 1.
|
|
139
|
-
done = True
|
|
140
|
-
break
|
|
141
|
-
counts[height] += 1
|
|
142
|
-
R_nodes[u]["height"] = height
|
|
143
|
-
if u != s:
|
|
144
|
-
# After relabeling, the last edge on the path is no longer
|
|
145
|
-
# admissible. Retreat one step to look for an alternative.
|
|
146
|
-
path.pop()
|
|
147
|
-
u = path[-1]
|
|
148
|
-
break
|
|
149
|
-
if u == t:
|
|
150
|
-
# t is reached. Augment flow along the path and reset it for a new
|
|
151
|
-
# depth-first search.
|
|
152
|
-
flow_value += augment(path)
|
|
153
|
-
if flow_value >= cutoff:
|
|
154
|
-
R.graph["flow_value"] = flow_value
|
|
155
|
-
return R
|
|
156
|
-
path = [s]
|
|
157
|
-
u = s
|
|
158
|
-
|
|
159
|
-
# Phase 2: Look for shortest augmenting paths using breadth-first search.
|
|
160
|
-
flow_value += edmonds_karp_core(R, s, t, cutoff - flow_value)
|
|
161
|
-
|
|
162
|
-
R.graph["flow_value"] = flow_value
|
|
163
|
-
return R
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True)
|
|
167
|
-
def shortest_augmenting_path(
|
|
168
|
-
G,
|
|
169
|
-
s,
|
|
170
|
-
t,
|
|
171
|
-
capacity="capacity",
|
|
172
|
-
residual=None,
|
|
173
|
-
value_only=False,
|
|
174
|
-
two_phase=False,
|
|
175
|
-
cutoff=None,
|
|
176
|
-
):
|
|
177
|
-
r"""Find a maximum single-commodity flow using the shortest augmenting path
|
|
178
|
-
algorithm.
|
|
179
|
-
|
|
180
|
-
This function returns the residual network resulting after computing
|
|
181
|
-
the maximum flow. See below for details about the conventions
|
|
182
|
-
NetworkX uses for defining residual networks.
|
|
183
|
-
|
|
184
|
-
This algorithm has a running time of $O(n^2 m)$ for $n$ nodes and $m$
|
|
185
|
-
edges.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
Parameters
|
|
189
|
-
----------
|
|
190
|
-
G : NetworkX graph
|
|
191
|
-
Edges of the graph are expected to have an attribute called
|
|
192
|
-
'capacity'. If this attribute is not present, the edge is
|
|
193
|
-
considered to have infinite capacity.
|
|
194
|
-
|
|
195
|
-
s : node
|
|
196
|
-
Source node for the flow.
|
|
197
|
-
|
|
198
|
-
t : node
|
|
199
|
-
Sink node for the flow.
|
|
200
|
-
|
|
201
|
-
capacity : string
|
|
202
|
-
Edges of the graph G are expected to have an attribute capacity
|
|
203
|
-
that indicates how much flow the edge can support. If this
|
|
204
|
-
attribute is not present, the edge is considered to have
|
|
205
|
-
infinite capacity. Default value: 'capacity'.
|
|
206
|
-
|
|
207
|
-
residual : NetworkX graph
|
|
208
|
-
Residual network on which the algorithm is to be executed. If None, a
|
|
209
|
-
new residual network is created. Default value: None.
|
|
210
|
-
|
|
211
|
-
value_only : bool
|
|
212
|
-
If True compute only the value of the maximum flow. This parameter
|
|
213
|
-
will be ignored by this algorithm because it is not applicable.
|
|
214
|
-
|
|
215
|
-
two_phase : bool
|
|
216
|
-
If True, a two-phase variant is used. The two-phase variant improves
|
|
217
|
-
the running time on unit-capacity networks from $O(nm)$ to
|
|
218
|
-
$O(\min(n^{2/3}, m^{1/2}) m)$. Default value: False.
|
|
219
|
-
|
|
220
|
-
cutoff : integer, float
|
|
221
|
-
If specified, the algorithm will terminate when the flow value reaches
|
|
222
|
-
or exceeds the cutoff. In this case, it may be unable to immediately
|
|
223
|
-
determine a minimum cut. Default value: None.
|
|
224
|
-
|
|
225
|
-
Returns
|
|
226
|
-
-------
|
|
227
|
-
R : NetworkX DiGraph
|
|
228
|
-
Residual network after computing the maximum flow.
|
|
229
|
-
|
|
230
|
-
Raises
|
|
231
|
-
------
|
|
232
|
-
NetworkXError
|
|
233
|
-
The algorithm does not support MultiGraph and MultiDiGraph. If
|
|
234
|
-
the input graph is an instance of one of these two classes, a
|
|
235
|
-
NetworkXError is raised.
|
|
236
|
-
|
|
237
|
-
NetworkXUnbounded
|
|
238
|
-
If the graph has a path of infinite capacity, the value of a
|
|
239
|
-
feasible flow on the graph is unbounded above and the function
|
|
240
|
-
raises a NetworkXUnbounded.
|
|
241
|
-
|
|
242
|
-
See also
|
|
243
|
-
--------
|
|
244
|
-
:meth:`maximum_flow`
|
|
245
|
-
:meth:`minimum_cut`
|
|
246
|
-
:meth:`edmonds_karp`
|
|
247
|
-
:meth:`preflow_push`
|
|
248
|
-
|
|
249
|
-
Notes
|
|
250
|
-
-----
|
|
251
|
-
The residual network :samp:`R` from an input graph :samp:`G` has the
|
|
252
|
-
same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair
|
|
253
|
-
of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a
|
|
254
|
-
self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists
|
|
255
|
-
in :samp:`G`.
|
|
256
|
-
|
|
257
|
-
For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']`
|
|
258
|
-
is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists
|
|
259
|
-
in :samp:`G` or zero otherwise. If the capacity is infinite,
|
|
260
|
-
:samp:`R[u][v]['capacity']` will have a high arbitrary finite value
|
|
261
|
-
that does not affect the solution of the problem. This value is stored in
|
|
262
|
-
:samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`,
|
|
263
|
-
:samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and
|
|
264
|
-
satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`.
|
|
265
|
-
|
|
266
|
-
The flow value, defined as the total flow into :samp:`t`, the sink, is
|
|
267
|
-
stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not
|
|
268
|
-
specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such
|
|
269
|
-
that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum
|
|
270
|
-
:samp:`s`-:samp:`t` cut.
|
|
271
|
-
|
|
272
|
-
Examples
|
|
273
|
-
--------
|
|
274
|
-
>>> from networkx.algorithms.flow import shortest_augmenting_path
|
|
275
|
-
|
|
276
|
-
The functions that implement flow algorithms and output a residual
|
|
277
|
-
network, such as this one, are not imported to the base NetworkX
|
|
278
|
-
namespace, so you have to explicitly import them from the flow package.
|
|
279
|
-
|
|
280
|
-
>>> G = nx.DiGraph()
|
|
281
|
-
>>> G.add_edge("x", "a", capacity=3.0)
|
|
282
|
-
>>> G.add_edge("x", "b", capacity=1.0)
|
|
283
|
-
>>> G.add_edge("a", "c", capacity=3.0)
|
|
284
|
-
>>> G.add_edge("b", "c", capacity=5.0)
|
|
285
|
-
>>> G.add_edge("b", "d", capacity=4.0)
|
|
286
|
-
>>> G.add_edge("d", "e", capacity=2.0)
|
|
287
|
-
>>> G.add_edge("c", "y", capacity=2.0)
|
|
288
|
-
>>> G.add_edge("e", "y", capacity=3.0)
|
|
289
|
-
>>> R = shortest_augmenting_path(G, "x", "y")
|
|
290
|
-
>>> flow_value = nx.maximum_flow_value(G, "x", "y")
|
|
291
|
-
>>> flow_value
|
|
292
|
-
3.0
|
|
293
|
-
>>> flow_value == R.graph["flow_value"]
|
|
294
|
-
True
|
|
295
|
-
|
|
296
|
-
"""
|
|
297
|
-
R = shortest_augmenting_path_impl(G, s, t, capacity, residual, two_phase, cutoff)
|
|
298
|
-
R.graph["algorithm"] = "shortest_augmenting_path"
|
|
299
|
-
nx._clear_cache(R)
|
|
300
|
-
return R
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Utility classes and functions for network flow algorithms.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from collections import deque
|
|
6
|
-
|
|
7
|
-
import networkx as nx
|
|
8
|
-
|
|
9
|
-
__all__ = [
|
|
10
|
-
"CurrentEdge",
|
|
11
|
-
"Level",
|
|
12
|
-
"GlobalRelabelThreshold",
|
|
13
|
-
"build_residual_network",
|
|
14
|
-
"detect_unboundedness",
|
|
15
|
-
"build_flow_dict",
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class CurrentEdge:
|
|
20
|
-
"""Mechanism for iterating over out-edges incident to a node in a circular
|
|
21
|
-
manner. StopIteration exception is raised when wraparound occurs.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
__slots__ = ("_edges", "_it", "_curr")
|
|
25
|
-
|
|
26
|
-
def __init__(self, edges):
|
|
27
|
-
self._edges = edges
|
|
28
|
-
if self._edges:
|
|
29
|
-
self._rewind()
|
|
30
|
-
|
|
31
|
-
def get(self):
|
|
32
|
-
return self._curr
|
|
33
|
-
|
|
34
|
-
def move_to_next(self):
|
|
35
|
-
try:
|
|
36
|
-
self._curr = next(self._it)
|
|
37
|
-
except StopIteration:
|
|
38
|
-
self._rewind()
|
|
39
|
-
raise
|
|
40
|
-
|
|
41
|
-
def _rewind(self):
|
|
42
|
-
self._it = iter(self._edges.items())
|
|
43
|
-
self._curr = next(self._it)
|
|
44
|
-
|
|
45
|
-
def __eq__(self, other):
|
|
46
|
-
return (getattr(self, "_curr", None), self._edges) == (
|
|
47
|
-
(getattr(other, "_curr", None), other._edges)
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class Level:
|
|
52
|
-
"""Active and inactive nodes in a level."""
|
|
53
|
-
|
|
54
|
-
__slots__ = ("active", "inactive")
|
|
55
|
-
|
|
56
|
-
def __init__(self):
|
|
57
|
-
self.active = set()
|
|
58
|
-
self.inactive = set()
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class GlobalRelabelThreshold:
|
|
62
|
-
"""Measurement of work before the global relabeling heuristic should be
|
|
63
|
-
applied.
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
def __init__(self, n, m, freq):
|
|
67
|
-
self._threshold = (n + m) / freq if freq else float("inf")
|
|
68
|
-
self._work = 0
|
|
69
|
-
|
|
70
|
-
def add_work(self, work):
|
|
71
|
-
self._work += work
|
|
72
|
-
|
|
73
|
-
def is_reached(self):
|
|
74
|
-
return self._work >= self._threshold
|
|
75
|
-
|
|
76
|
-
def clear_work(self):
|
|
77
|
-
self._work = 0
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@nx._dispatchable(edge_attrs={"capacity": float("inf")}, returns_graph=True)
|
|
81
|
-
def build_residual_network(G, capacity):
|
|
82
|
-
"""Build a residual network and initialize a zero flow.
|
|
83
|
-
|
|
84
|
-
The residual network :samp:`R` from an input graph :samp:`G` has the
|
|
85
|
-
same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair
|
|
86
|
-
of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a
|
|
87
|
-
self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists
|
|
88
|
-
in :samp:`G`.
|
|
89
|
-
|
|
90
|
-
For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']`
|
|
91
|
-
is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists
|
|
92
|
-
in :samp:`G` or zero otherwise. If the capacity is infinite,
|
|
93
|
-
:samp:`R[u][v]['capacity']` will have a high arbitrary finite value
|
|
94
|
-
that does not affect the solution of the problem. This value is stored in
|
|
95
|
-
:samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`,
|
|
96
|
-
:samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and
|
|
97
|
-
satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`.
|
|
98
|
-
|
|
99
|
-
The flow value, defined as the total flow into :samp:`t`, the sink, is
|
|
100
|
-
stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not
|
|
101
|
-
specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such
|
|
102
|
-
that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum
|
|
103
|
-
:samp:`s`-:samp:`t` cut.
|
|
104
|
-
|
|
105
|
-
"""
|
|
106
|
-
if G.is_multigraph():
|
|
107
|
-
raise nx.NetworkXError("MultiGraph and MultiDiGraph not supported (yet).")
|
|
108
|
-
|
|
109
|
-
R = nx.DiGraph()
|
|
110
|
-
R.__networkx_cache__ = None # Disable caching
|
|
111
|
-
R.add_nodes_from(G)
|
|
112
|
-
|
|
113
|
-
inf = float("inf")
|
|
114
|
-
# Extract edges with positive capacities. Self loops excluded.
|
|
115
|
-
edge_list = [
|
|
116
|
-
(u, v, attr)
|
|
117
|
-
for u, v, attr in G.edges(data=True)
|
|
118
|
-
if u != v and attr.get(capacity, inf) > 0
|
|
119
|
-
]
|
|
120
|
-
# Simulate infinity with three times the sum of the finite edge capacities
|
|
121
|
-
# or any positive value if the sum is zero. This allows the
|
|
122
|
-
# infinite-capacity edges to be distinguished for unboundedness detection
|
|
123
|
-
# and directly participate in residual capacity calculation. If the maximum
|
|
124
|
-
# flow is finite, these edges cannot appear in the minimum cut and thus
|
|
125
|
-
# guarantee correctness. Since the residual capacity of an
|
|
126
|
-
# infinite-capacity edge is always at least 2/3 of inf, while that of an
|
|
127
|
-
# finite-capacity edge is at most 1/3 of inf, if an operation moves more
|
|
128
|
-
# than 1/3 of inf units of flow to t, there must be an infinite-capacity
|
|
129
|
-
# s-t path in G.
|
|
130
|
-
inf = (
|
|
131
|
-
3
|
|
132
|
-
* sum(
|
|
133
|
-
attr[capacity]
|
|
134
|
-
for u, v, attr in edge_list
|
|
135
|
-
if capacity in attr and attr[capacity] != inf
|
|
136
|
-
)
|
|
137
|
-
or 1
|
|
138
|
-
)
|
|
139
|
-
if G.is_directed():
|
|
140
|
-
for u, v, attr in edge_list:
|
|
141
|
-
r = min(attr.get(capacity, inf), inf)
|
|
142
|
-
if not R.has_edge(u, v):
|
|
143
|
-
# Both (u, v) and (v, u) must be present in the residual
|
|
144
|
-
# network.
|
|
145
|
-
R.add_edge(u, v, capacity=r)
|
|
146
|
-
R.add_edge(v, u, capacity=0)
|
|
147
|
-
else:
|
|
148
|
-
# The edge (u, v) was added when (v, u) was visited.
|
|
149
|
-
R[u][v]["capacity"] = r
|
|
150
|
-
else:
|
|
151
|
-
for u, v, attr in edge_list:
|
|
152
|
-
# Add a pair of edges with equal residual capacities.
|
|
153
|
-
r = min(attr.get(capacity, inf), inf)
|
|
154
|
-
R.add_edge(u, v, capacity=r)
|
|
155
|
-
R.add_edge(v, u, capacity=r)
|
|
156
|
-
|
|
157
|
-
# Record the value simulating infinity.
|
|
158
|
-
R.graph["inf"] = inf
|
|
159
|
-
|
|
160
|
-
return R
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
@nx._dispatchable(
|
|
164
|
-
graphs="R",
|
|
165
|
-
preserve_edge_attrs={"R": {"capacity": float("inf")}},
|
|
166
|
-
preserve_graph_attrs=True,
|
|
167
|
-
)
|
|
168
|
-
def detect_unboundedness(R, s, t):
|
|
169
|
-
"""Detect an infinite-capacity s-t path in R."""
|
|
170
|
-
q = deque([s])
|
|
171
|
-
seen = {s}
|
|
172
|
-
inf = R.graph["inf"]
|
|
173
|
-
while q:
|
|
174
|
-
u = q.popleft()
|
|
175
|
-
for v, attr in R[u].items():
|
|
176
|
-
if attr["capacity"] == inf and v not in seen:
|
|
177
|
-
if v == t:
|
|
178
|
-
raise nx.NetworkXUnbounded(
|
|
179
|
-
"Infinite capacity path, flow unbounded above."
|
|
180
|
-
)
|
|
181
|
-
seen.add(v)
|
|
182
|
-
q.append(v)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
@nx._dispatchable(graphs={"G": 0, "R": 1}, preserve_edge_attrs={"R": {"flow": None}})
|
|
186
|
-
def build_flow_dict(G, R):
|
|
187
|
-
"""Build a flow dictionary from a residual network."""
|
|
188
|
-
flow_dict = {}
|
|
189
|
-
for u in G:
|
|
190
|
-
flow_dict[u] = {v: 0 for v in G[u]}
|
|
191
|
-
flow_dict[u].update(
|
|
192
|
-
(v, attr["flow"]) for v, attr in R[u].items() if attr["flow"] > 0
|
|
193
|
-
)
|
|
194
|
-
return flow_dict
|