okstra 0.114.0 → 0.115.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 (326) hide show
  1. package/docs/kr/architecture.md +2 -2
  2. package/docs/kr/follow-ups/2026-07-10-final-report-option-3.md +51 -0
  3. package/package.json +1 -1
  4. package/runtime/BUILD.json +2 -2
  5. package/runtime/agents/workers/report-writer-worker.md +1 -0
  6. package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
  7. package/runtime/python/okstra_ctl/implementation_stage.py +46 -39
  8. package/runtime/python/okstra_ctl/report_views.py +151 -12
  9. package/runtime/python/okstra_ctl/run.py +24 -24
  10. package/runtime/python/okstra_ctl/worktree.py +1 -1
  11. package/runtime/python/okstra_token_usage/claude.py +58 -19
  12. package/runtime/python/okstra_token_usage/collect.py +3 -1
  13. package/runtime/python/okstra_vendor/__init__.py +3 -0
  14. package/runtime/schemas/final-report-v1.0.schema.json +20 -0
  15. package/runtime/templates/reports/final-report.template.md +14 -0
  16. package/runtime/templates/reports/i18n/en.json +23 -12
  17. package/runtime/templates/reports/i18n/ko.json +23 -12
  18. package/runtime/templates/reports/report.css +55 -0
  19. package/runtime/templates/reports/report.js +53 -1
  20. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
  21. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +0 -41
  22. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +0 -112
  23. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +0 -199
  24. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +0 -146
  25. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +0 -59
  26. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +0 -78
  27. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +0 -303
  28. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +0 -8
  29. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +0 -94
  30. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +0 -31
  31. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +0 -306
  32. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +0 -1014
  33. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +0 -274
  34. package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +0 -68
  35. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
  36. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +0 -81
  37. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +0 -143
  38. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +0 -122
  39. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +0 -174
  40. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +0 -107
  41. package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +0 -87
  42. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
  43. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +0 -125
  44. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +0 -192
  45. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +0 -84
  46. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +0 -33
  47. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +0 -240
  48. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +0 -334
  49. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +0 -407
  50. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +0 -218
  51. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +0 -327
  52. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +0 -138
  53. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +0 -409
  54. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +0 -35
  55. package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +0 -80
  56. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
  57. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +0 -923
  58. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +0 -354
  59. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +0 -274
  60. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +0 -259
  61. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +0 -147
  62. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +0 -43
  63. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +0 -144
  64. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +0 -73
  65. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +0 -186
  66. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +0 -277
  67. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +0 -122
  68. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +0 -345
  69. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +0 -220
  70. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +0 -344
  71. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +0 -87
  72. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +0 -140
  73. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +0 -82
  74. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +0 -110
  75. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +0 -302
  76. package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +0 -64
  77. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
  78. package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +0 -863
  79. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
  80. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +0 -147
  81. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +0 -157
  82. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +0 -85
  83. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +0 -106
  84. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +0 -91
  85. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +0 -241
  86. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +0 -138
  87. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +0 -76
  88. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +0 -264
  89. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +0 -152
  90. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +0 -340
  91. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +0 -139
  92. package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +0 -26
  93. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
  94. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +0 -70
  95. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +0 -248
  96. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +0 -138
  97. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +0 -55
  98. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +0 -193
  99. package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +0 -96
  100. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
  101. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +0 -421
  102. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +0 -309
  103. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +0 -249
  104. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +0 -502
  105. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +0 -488
  106. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +0 -323
  107. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +0 -280
  108. package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +0 -102
  109. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
  110. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
  111. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
  112. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
  113. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +0 -128
  114. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +0 -573
  115. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +0 -155
  116. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +0 -475
  117. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +0 -481
  118. package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
  119. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
  120. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
  121. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
  122. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
  123. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
  124. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +0 -719
  125. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +0 -103
  126. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +0 -490
  127. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +0 -64
  128. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +0 -212
  129. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +0 -202
  130. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +0 -1655
  131. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +0 -3118
  132. package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +0 -196
  133. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
  134. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +0 -77
  135. package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +0 -213
  136. package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +0 -544
  137. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
  138. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +0 -328
  139. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +0 -451
  140. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +0 -491
  141. package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +0 -55
  142. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
  143. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +0 -254
  144. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +0 -212
  145. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +0 -88
  146. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +0 -511
  147. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +0 -149
  148. package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +0 -983
  149. package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
  150. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +0 -23
  151. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +0 -154
  152. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +0 -144
  153. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +0 -109
  154. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +0 -136
  155. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +0 -129
  156. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +0 -300
  157. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +0 -678
  158. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +0 -80
  159. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +0 -266
  160. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +0 -85
  161. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +0 -171
  162. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +0 -984
  163. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +0 -340
  164. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +0 -835
  165. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +0 -831
  166. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +0 -85
  167. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +0 -299
  168. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +0 -115
  169. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +0 -58
  170. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +0 -314
  171. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +0 -872
  172. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +0 -163
  173. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +0 -46
  174. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +0 -24
  175. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +0 -26
  176. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +0 -615
  177. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +0 -459
  178. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +0 -556
  179. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +0 -179
  180. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +0 -62
  181. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +0 -15
  182. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +0 -140
  183. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +0 -60
  184. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +0 -27
  185. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +0 -274
  186. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +0 -556
  187. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +0 -57
  188. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +0 -37
  189. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +0 -88
  190. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +0 -149
  191. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +0 -1158
  192. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +0 -803
  193. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +0 -76
  194. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +0 -8
  195. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +0 -138
  196. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +0 -191
  197. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +0 -642
  198. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +0 -179
  199. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +0 -270
  200. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +0 -431
  201. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +0 -161
  202. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +0 -248
  203. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +0 -41
  204. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +0 -103
  205. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +0 -54
  206. package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +0 -157
  207. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
  208. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +0 -25
  209. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +0 -203
  210. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +0 -307
  211. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +0 -147
  212. package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +0 -131
  213. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
  214. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +0 -624
  215. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +0 -114
  216. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +0 -79
  217. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +0 -99
  218. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +0 -934
  219. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +0 -53
  220. package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +0 -174
  221. package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
  222. package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +0 -192
  223. package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +0 -476
  224. package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +0 -362
  225. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +0 -331
  226. package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +0 -110
  227. package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +0 -177
  228. package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +0 -1045
  229. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +0 -950
  230. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +0 -12
  231. package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +0 -349
  232. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +0 -459
  233. package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +0 -528
  234. package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +0 -1421
  235. package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +0 -131
  236. package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +0 -371
  237. package/runtime/python/okstra_vendor/networkx/conftest.py +0 -261
  238. package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
  239. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
  240. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
  241. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
  242. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
  243. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
  244. package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
  245. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +0 -237
  246. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +0 -229
  247. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +0 -285
  248. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +0 -631
  249. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +0 -146
  250. package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +0 -1582
  251. package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
  252. package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +0 -75
  253. package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +0 -642
  254. package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +0 -20
  255. package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +0 -362
  256. package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +0 -224
  257. package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +0 -189
  258. package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +0 -103
  259. package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +0 -39
  260. package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +0 -182
  261. package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +0 -488
  262. package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +0 -133
  263. package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +0 -221
  264. package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +0 -28
  265. package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +0 -144
  266. package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +0 -125
  267. package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +0 -264
  268. package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +0 -316
  269. package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +0 -30
  270. package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +0 -82
  271. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +0 -33
  272. package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +0 -495
  273. package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +0 -220
  274. package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +0 -49
  275. package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +0 -72
  276. package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +0 -92
  277. package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +0 -64
  278. package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +0 -195
  279. package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +0 -15
  280. package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
  281. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +0 -400
  282. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +0 -108
  283. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +0 -40
  284. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +0 -275
  285. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +0 -334
  286. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +0 -86
  287. package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +0 -70
  288. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
  289. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +0 -78
  290. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +0 -78
  291. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +0 -109
  292. package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +0 -48
  293. package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
  294. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +0 -354
  295. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +0 -318
  296. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +0 -612
  297. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +0 -744
  298. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +0 -181
  299. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +0 -1531
  300. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +0 -30
  301. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +0 -63
  302. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +0 -128
  303. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +0 -166
  304. package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +0 -1742
  305. package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
  306. package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +0 -248
  307. package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +0 -321
  308. package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +0 -531
  309. package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +0 -349
  310. package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +0 -281
  311. package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +0 -40
  312. package/runtime/python/okstra_vendor/networkx/tests/test_import.py +0 -11
  313. package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +0 -96
  314. package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +0 -349
  315. package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +0 -8
  316. package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
  317. package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +0 -11
  318. package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +0 -225
  319. package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +0 -263
  320. package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +0 -510
  321. package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +0 -131
  322. package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +0 -268
  323. package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +0 -393
  324. package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +0 -53
  325. package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +0 -63
  326. package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +0 -55
@@ -1,3118 +0,0 @@
1
- import itertools as it
2
-
3
- import pytest
4
-
5
- import networkx as nx
6
- from networkx import vf2pp_is_isomorphic, vf2pp_isomorphism
7
- from networkx.algorithms.isomorphism.vf2pp import (
8
- _consistent_PT,
9
- _cut_PT,
10
- _feasibility,
11
- _find_candidates,
12
- _find_candidates_Di,
13
- _GraphParameters,
14
- _initialize_parameters,
15
- _matching_order,
16
- _restore_Tinout,
17
- _restore_Tinout_Di,
18
- _StateParameters,
19
- _update_Tinout,
20
- )
21
-
22
- labels_same = ["blue"]
23
-
24
- labels_many = [
25
- "white",
26
- "red",
27
- "blue",
28
- "green",
29
- "orange",
30
- "black",
31
- "purple",
32
- "yellow",
33
- "brown",
34
- "cyan",
35
- "solarized",
36
- "pink",
37
- "none",
38
- ]
39
-
40
-
41
- class TestNodeOrdering:
42
- def test_empty_graph(self):
43
- G1 = nx.Graph()
44
- G2 = nx.Graph()
45
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
46
- assert len(set(_matching_order(gparams))) == 0
47
-
48
- def test_single_node(self):
49
- G1 = nx.Graph()
50
- G2 = nx.Graph()
51
- G1.add_node(1)
52
- G2.add_node(1)
53
-
54
- nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels_many))), "label")
55
- nx.set_node_attributes(
56
- G2,
57
- dict(zip(G2, it.cycle(labels_many))),
58
- "label",
59
- )
60
- l1, l2 = (
61
- nx.get_node_attributes(G1, "label"),
62
- nx.get_node_attributes(G2, "label"),
63
- )
64
-
65
- gparams = _GraphParameters(
66
- G1,
67
- G2,
68
- l1,
69
- l2,
70
- nx.utils.groups(l1),
71
- nx.utils.groups(l2),
72
- nx.utils.groups(dict(G2.degree())),
73
- )
74
- m = _matching_order(gparams)
75
- assert m == [1]
76
-
77
- def test_matching_order(self):
78
- labels = [
79
- "blue",
80
- "blue",
81
- "red",
82
- "red",
83
- "red",
84
- "red",
85
- "green",
86
- "green",
87
- "green",
88
- "yellow",
89
- "purple",
90
- "purple",
91
- "blue",
92
- "blue",
93
- ]
94
- G1 = nx.Graph(
95
- [
96
- (0, 1),
97
- (0, 2),
98
- (1, 2),
99
- (2, 5),
100
- (2, 4),
101
- (1, 3),
102
- (1, 4),
103
- (3, 6),
104
- (4, 6),
105
- (6, 7),
106
- (7, 8),
107
- (9, 10),
108
- (9, 11),
109
- (11, 12),
110
- (11, 13),
111
- (12, 13),
112
- (10, 13),
113
- ]
114
- )
115
- G2 = G1.copy()
116
- nx.set_node_attributes(G1, dict(zip(G1, it.cycle(labels))), "label")
117
- nx.set_node_attributes(
118
- G2,
119
- dict(zip(G2, it.cycle(labels))),
120
- "label",
121
- )
122
- l1, l2 = (
123
- nx.get_node_attributes(G1, "label"),
124
- nx.get_node_attributes(G2, "label"),
125
- )
126
- gparams = _GraphParameters(
127
- G1,
128
- G2,
129
- l1,
130
- l2,
131
- nx.utils.groups(l1),
132
- nx.utils.groups(l2),
133
- nx.utils.groups(dict(G2.degree())),
134
- )
135
-
136
- expected = [9, 11, 10, 13, 12, 1, 2, 4, 0, 3, 6, 5, 7, 8]
137
- assert _matching_order(gparams) == expected
138
-
139
- def test_matching_order_all_branches(self):
140
- G1 = nx.Graph(
141
- [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 4), (3, 4)]
142
- )
143
- G1.add_node(5)
144
- G2 = G1.copy()
145
-
146
- G1.nodes[0]["label"] = "black"
147
- G1.nodes[1]["label"] = "blue"
148
- G1.nodes[2]["label"] = "blue"
149
- G1.nodes[3]["label"] = "red"
150
- G1.nodes[4]["label"] = "red"
151
- G1.nodes[5]["label"] = "blue"
152
-
153
- G2.nodes[0]["label"] = "black"
154
- G2.nodes[1]["label"] = "blue"
155
- G2.nodes[2]["label"] = "blue"
156
- G2.nodes[3]["label"] = "red"
157
- G2.nodes[4]["label"] = "red"
158
- G2.nodes[5]["label"] = "blue"
159
-
160
- l1, l2 = (
161
- nx.get_node_attributes(G1, "label"),
162
- nx.get_node_attributes(G2, "label"),
163
- )
164
- gparams = _GraphParameters(
165
- G1,
166
- G2,
167
- l1,
168
- l2,
169
- nx.utils.groups(l1),
170
- nx.utils.groups(l2),
171
- nx.utils.groups(dict(G2.degree())),
172
- )
173
-
174
- expected = [0, 4, 1, 3, 2, 5]
175
- assert _matching_order(gparams) == expected
176
-
177
-
178
- class TestGraphCandidateSelection:
179
- G1_edges = [
180
- (1, 2),
181
- (1, 4),
182
- (1, 5),
183
- (2, 3),
184
- (2, 4),
185
- (3, 4),
186
- (4, 5),
187
- (1, 6),
188
- (6, 7),
189
- (6, 8),
190
- (8, 9),
191
- (7, 9),
192
- ]
193
- mapped = {
194
- 0: "x",
195
- 1: "a",
196
- 2: "b",
197
- 3: "c",
198
- 4: "d",
199
- 5: "e",
200
- 6: "f",
201
- 7: "g",
202
- 8: "h",
203
- 9: "i",
204
- }
205
-
206
- def test_no_covered_neighbors_no_labels(self):
207
- G1 = nx.Graph()
208
- G1.add_edges_from(self.G1_edges)
209
- G1.add_node(0)
210
- G2 = nx.relabel_nodes(G1, self.mapped)
211
-
212
- G1_degree = dict(G1.degree)
213
- l1 = dict(G1.nodes(data="label", default=-1))
214
- l2 = dict(G2.nodes(data="label", default=-1))
215
- gparams = _GraphParameters(
216
- G1,
217
- G2,
218
- l1,
219
- l2,
220
- nx.utils.groups(l1),
221
- nx.utils.groups(l2),
222
- nx.utils.groups(dict(G2.degree())),
223
- )
224
-
225
- m = {9: self.mapped[9], 1: self.mapped[1]}
226
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
227
-
228
- T1 = {7, 8, 2, 4, 5}
229
- T1_tilde = {0, 3, 6}
230
- T2 = {"g", "h", "b", "d", "e"}
231
- T2_tilde = {"x", "c", "f"}
232
-
233
- sparams = _StateParameters(
234
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
235
- )
236
-
237
- u = 3
238
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
239
- assert candidates == {self.mapped[u]}
240
-
241
- u = 0
242
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
243
- assert candidates == {self.mapped[u]}
244
-
245
- m.pop(9)
246
- m_rev.pop(self.mapped[9])
247
-
248
- T1 = {2, 4, 5, 6}
249
- T1_tilde = {0, 3, 7, 8, 9}
250
- T2 = {"g", "h", "b", "d", "e", "f"}
251
- T2_tilde = {"x", "c", "g", "h", "i"}
252
-
253
- sparams = _StateParameters(
254
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
255
- )
256
-
257
- u = 7
258
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
259
- assert candidates == {
260
- self.mapped[u],
261
- self.mapped[8],
262
- self.mapped[3],
263
- self.mapped[9],
264
- }
265
-
266
- def test_no_covered_neighbors_with_labels(self):
267
- G1 = nx.Graph()
268
- G1.add_edges_from(self.G1_edges)
269
- G1.add_node(0)
270
- G2 = nx.relabel_nodes(G1, self.mapped)
271
-
272
- G1_degree = dict(G1.degree)
273
- nx.set_node_attributes(
274
- G1,
275
- dict(zip(G1, it.cycle(labels_many))),
276
- "label",
277
- )
278
- nx.set_node_attributes(
279
- G2,
280
- dict(
281
- zip(
282
- [self.mapped[n] for n in G1],
283
- it.cycle(labels_many),
284
- )
285
- ),
286
- "label",
287
- )
288
- l1 = dict(G1.nodes(data="label", default=-1))
289
- l2 = dict(G2.nodes(data="label", default=-1))
290
- gparams = _GraphParameters(
291
- G1,
292
- G2,
293
- l1,
294
- l2,
295
- nx.utils.groups(l1),
296
- nx.utils.groups(l2),
297
- nx.utils.groups(dict(G2.degree())),
298
- )
299
-
300
- m = {9: self.mapped[9], 1: self.mapped[1]}
301
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
302
-
303
- T1 = {7, 8, 2, 4, 5, 6}
304
- T1_tilde = {0, 3}
305
- T2 = {"g", "h", "b", "d", "e", "f"}
306
- T2_tilde = {"x", "c"}
307
-
308
- sparams = _StateParameters(
309
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
310
- )
311
-
312
- u = 3
313
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
314
- assert candidates == {self.mapped[u]}
315
-
316
- u = 0
317
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
318
- assert candidates == {self.mapped[u]}
319
-
320
- # Change label of disconnected node
321
- G1.nodes[u]["label"] = "blue"
322
- l1 = dict(G1.nodes(data="label", default=-1))
323
- l2 = dict(G2.nodes(data="label", default=-1))
324
- gparams = _GraphParameters(
325
- G1,
326
- G2,
327
- l1,
328
- l2,
329
- nx.utils.groups(l1),
330
- nx.utils.groups(l2),
331
- nx.utils.groups(dict(G2.degree())),
332
- )
333
-
334
- # No candidate
335
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
336
- assert candidates == set()
337
-
338
- m.pop(9)
339
- m_rev.pop(self.mapped[9])
340
-
341
- T1 = {2, 4, 5, 6}
342
- T1_tilde = {0, 3, 7, 8, 9}
343
- T2 = {"b", "d", "e", "f"}
344
- T2_tilde = {"x", "c", "g", "h", "i"}
345
-
346
- sparams = _StateParameters(
347
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
348
- )
349
-
350
- u = 7
351
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
352
- assert candidates == {self.mapped[u]}
353
-
354
- G1.nodes[8]["label"] = G1.nodes[7]["label"]
355
- G2.nodes[self.mapped[8]]["label"] = G1.nodes[7]["label"]
356
- l1 = dict(G1.nodes(data="label", default=-1))
357
- l2 = dict(G2.nodes(data="label", default=-1))
358
- gparams = _GraphParameters(
359
- G1,
360
- G2,
361
- l1,
362
- l2,
363
- nx.utils.groups(l1),
364
- nx.utils.groups(l2),
365
- nx.utils.groups(dict(G2.degree())),
366
- )
367
-
368
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
369
- assert candidates == {self.mapped[u], self.mapped[8]}
370
-
371
- def test_covered_neighbors_no_labels(self):
372
- G1 = nx.Graph()
373
- G1.add_edges_from(self.G1_edges)
374
- G1.add_node(0)
375
- G2 = nx.relabel_nodes(G1, self.mapped)
376
-
377
- G1_degree = dict(G1.degree)
378
- l1 = dict(G1.nodes(data=None, default=-1))
379
- l2 = dict(G2.nodes(data=None, default=-1))
380
- gparams = _GraphParameters(
381
- G1,
382
- G2,
383
- l1,
384
- l2,
385
- nx.utils.groups(l1),
386
- nx.utils.groups(l2),
387
- nx.utils.groups(dict(G2.degree())),
388
- )
389
-
390
- m = {9: self.mapped[9], 1: self.mapped[1]}
391
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
392
-
393
- T1 = {7, 8, 2, 4, 5, 6}
394
- T1_tilde = {0, 3}
395
- T2 = {"g", "h", "b", "d", "e", "f"}
396
- T2_tilde = {"x", "c"}
397
-
398
- sparams = _StateParameters(
399
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
400
- )
401
-
402
- u = 5
403
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
404
- assert candidates == {self.mapped[u]}
405
-
406
- u = 6
407
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
408
- assert candidates == {self.mapped[u], self.mapped[2]}
409
-
410
- def test_covered_neighbors_with_labels(self):
411
- G1 = nx.Graph()
412
- G1.add_edges_from(self.G1_edges)
413
- G1.add_node(0)
414
- G2 = nx.relabel_nodes(G1, self.mapped)
415
-
416
- G1_degree = dict(G1.degree)
417
- nx.set_node_attributes(
418
- G1,
419
- dict(zip(G1, it.cycle(labels_many))),
420
- "label",
421
- )
422
- nx.set_node_attributes(
423
- G2,
424
- dict(
425
- zip(
426
- [self.mapped[n] for n in G1],
427
- it.cycle(labels_many),
428
- )
429
- ),
430
- "label",
431
- )
432
- l1 = dict(G1.nodes(data="label", default=-1))
433
- l2 = dict(G2.nodes(data="label", default=-1))
434
- gparams = _GraphParameters(
435
- G1,
436
- G2,
437
- l1,
438
- l2,
439
- nx.utils.groups(l1),
440
- nx.utils.groups(l2),
441
- nx.utils.groups(dict(G2.degree())),
442
- )
443
-
444
- m = {9: self.mapped[9], 1: self.mapped[1]}
445
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
446
-
447
- T1 = {7, 8, 2, 4, 5, 6}
448
- T1_tilde = {0, 3}
449
- T2 = {"g", "h", "b", "d", "e", "f"}
450
- T2_tilde = {"x", "c"}
451
-
452
- sparams = _StateParameters(
453
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
454
- )
455
-
456
- u = 5
457
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
458
- assert candidates == {self.mapped[u]}
459
-
460
- u = 6
461
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
462
- assert candidates == {self.mapped[u]}
463
-
464
- # Assign to 2, the same label as 6
465
- G1.nodes[2]["label"] = G1.nodes[u]["label"]
466
- G2.nodes[self.mapped[2]]["label"] = G1.nodes[u]["label"]
467
- l1 = dict(G1.nodes(data="label", default=-1))
468
- l2 = dict(G2.nodes(data="label", default=-1))
469
- gparams = _GraphParameters(
470
- G1,
471
- G2,
472
- l1,
473
- l2,
474
- nx.utils.groups(l1),
475
- nx.utils.groups(l2),
476
- nx.utils.groups(dict(G2.degree())),
477
- )
478
-
479
- candidates = _find_candidates(u, gparams, sparams, G1_degree)
480
- assert candidates == {self.mapped[u], self.mapped[2]}
481
-
482
-
483
- class TestDiGraphCandidateSelection:
484
- G1_edges = [
485
- (1, 2),
486
- (1, 4),
487
- (5, 1),
488
- (2, 3),
489
- (4, 2),
490
- (3, 4),
491
- (4, 5),
492
- (1, 6),
493
- (6, 7),
494
- (6, 8),
495
- (8, 9),
496
- (7, 9),
497
- ]
498
- mapped = {
499
- 0: "x",
500
- 1: "a",
501
- 2: "b",
502
- 3: "c",
503
- 4: "d",
504
- 5: "e",
505
- 6: "f",
506
- 7: "g",
507
- 8: "h",
508
- 9: "i",
509
- }
510
-
511
- def test_no_covered_neighbors_no_labels(self):
512
- G1 = nx.DiGraph()
513
- G1.add_edges_from(self.G1_edges)
514
- G1.add_node(0)
515
- G2 = nx.relabel_nodes(G1, self.mapped)
516
-
517
- G1_degree = {
518
- n: (in_degree, out_degree)
519
- for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree)
520
- }
521
-
522
- l1 = dict(G1.nodes(data="label", default=-1))
523
- l2 = dict(G2.nodes(data="label", default=-1))
524
- gparams = _GraphParameters(
525
- G1,
526
- G2,
527
- l1,
528
- l2,
529
- nx.utils.groups(l1),
530
- nx.utils.groups(l2),
531
- nx.utils.groups(
532
- {
533
- node: (in_degree, out_degree)
534
- for (node, in_degree), (_, out_degree) in zip(
535
- G2.in_degree(), G2.out_degree()
536
- )
537
- }
538
- ),
539
- )
540
-
541
- m = {9: self.mapped[9], 1: self.mapped[1]}
542
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
543
-
544
- T1_out = {2, 4, 6}
545
- T1_in = {5, 7, 8}
546
- T1_tilde = {0, 3}
547
- T2_out = {"b", "d", "f"}
548
- T2_in = {"e", "g", "h"}
549
- T2_tilde = {"x", "c"}
550
-
551
- sparams = _StateParameters(
552
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
553
- )
554
-
555
- u = 3
556
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
557
- assert candidates == {self.mapped[u]}
558
-
559
- u = 0
560
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
561
- assert candidates == {self.mapped[u]}
562
-
563
- m.pop(9)
564
- m_rev.pop(self.mapped[9])
565
-
566
- T1_out = {2, 4, 6}
567
- T1_in = {5}
568
- T1_tilde = {0, 3, 7, 8, 9}
569
- T2_out = {"b", "d", "f"}
570
- T2_in = {"e"}
571
- T2_tilde = {"x", "c", "g", "h", "i"}
572
-
573
- sparams = _StateParameters(
574
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
575
- )
576
-
577
- u = 7
578
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
579
- assert candidates == {self.mapped[u], self.mapped[8], self.mapped[3]}
580
-
581
- def test_no_covered_neighbors_with_labels(self):
582
- G1 = nx.DiGraph()
583
- G1.add_edges_from(self.G1_edges)
584
- G1.add_node(0)
585
- G2 = nx.relabel_nodes(G1, self.mapped)
586
-
587
- G1_degree = {
588
- n: (in_degree, out_degree)
589
- for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree)
590
- }
591
- nx.set_node_attributes(
592
- G1,
593
- dict(zip(G1, it.cycle(labels_many))),
594
- "label",
595
- )
596
- nx.set_node_attributes(
597
- G2,
598
- dict(
599
- zip(
600
- [self.mapped[n] for n in G1],
601
- it.cycle(labels_many),
602
- )
603
- ),
604
- "label",
605
- )
606
- l1 = dict(G1.nodes(data="label", default=-1))
607
- l2 = dict(G2.nodes(data="label", default=-1))
608
- gparams = _GraphParameters(
609
- G1,
610
- G2,
611
- l1,
612
- l2,
613
- nx.utils.groups(l1),
614
- nx.utils.groups(l2),
615
- nx.utils.groups(
616
- {
617
- node: (in_degree, out_degree)
618
- for (node, in_degree), (_, out_degree) in zip(
619
- G2.in_degree(), G2.out_degree()
620
- )
621
- }
622
- ),
623
- )
624
-
625
- m = {9: self.mapped[9], 1: self.mapped[1]}
626
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
627
-
628
- T1_out = {2, 4, 6}
629
- T1_in = {5, 7, 8}
630
- T1_tilde = {0, 3}
631
- T2_out = {"b", "d", "f"}
632
- T2_in = {"e", "g", "h"}
633
- T2_tilde = {"x", "c"}
634
-
635
- sparams = _StateParameters(
636
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
637
- )
638
-
639
- u = 3
640
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
641
- assert candidates == {self.mapped[u]}
642
-
643
- u = 0
644
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
645
- assert candidates == {self.mapped[u]}
646
-
647
- # Change label of disconnected node
648
- G1.nodes[u]["label"] = "blue"
649
- l1 = dict(G1.nodes(data="label", default=-1))
650
- l2 = dict(G2.nodes(data="label", default=-1))
651
- gparams = _GraphParameters(
652
- G1,
653
- G2,
654
- l1,
655
- l2,
656
- nx.utils.groups(l1),
657
- nx.utils.groups(l2),
658
- nx.utils.groups(
659
- {
660
- node: (in_degree, out_degree)
661
- for (node, in_degree), (_, out_degree) in zip(
662
- G2.in_degree(), G2.out_degree()
663
- )
664
- }
665
- ),
666
- )
667
-
668
- # No candidate
669
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
670
- assert candidates == set()
671
-
672
- m.pop(9)
673
- m_rev.pop(self.mapped[9])
674
-
675
- T1_out = {2, 4, 6}
676
- T1_in = {5}
677
- T1_tilde = {0, 3, 7, 8, 9}
678
- T2_out = {"b", "d", "f"}
679
- T2_in = {"e"}
680
- T2_tilde = {"x", "c", "g", "h", "i"}
681
-
682
- sparams = _StateParameters(
683
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
684
- )
685
-
686
- u = 7
687
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
688
- assert candidates == {self.mapped[u]}
689
-
690
- G1.nodes[8]["label"] = G1.nodes[7]["label"]
691
- G2.nodes[self.mapped[8]]["label"] = G1.nodes[7]["label"]
692
- l1 = dict(G1.nodes(data="label", default=-1))
693
- l2 = dict(G2.nodes(data="label", default=-1))
694
- gparams = _GraphParameters(
695
- G1,
696
- G2,
697
- l1,
698
- l2,
699
- nx.utils.groups(l1),
700
- nx.utils.groups(l2),
701
- nx.utils.groups(
702
- {
703
- node: (in_degree, out_degree)
704
- for (node, in_degree), (_, out_degree) in zip(
705
- G2.in_degree(), G2.out_degree()
706
- )
707
- }
708
- ),
709
- )
710
-
711
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
712
- assert candidates == {self.mapped[u], self.mapped[8]}
713
-
714
- def test_covered_neighbors_no_labels(self):
715
- G1 = nx.DiGraph()
716
- G1.add_edges_from(self.G1_edges)
717
- G1.add_node(0)
718
- G2 = nx.relabel_nodes(G1, self.mapped)
719
-
720
- G1_degree = {
721
- n: (in_degree, out_degree)
722
- for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree)
723
- }
724
-
725
- l1 = dict(G1.nodes(data=None, default=-1))
726
- l2 = dict(G2.nodes(data=None, default=-1))
727
- gparams = _GraphParameters(
728
- G1,
729
- G2,
730
- l1,
731
- l2,
732
- nx.utils.groups(l1),
733
- nx.utils.groups(l2),
734
- nx.utils.groups(
735
- {
736
- node: (in_degree, out_degree)
737
- for (node, in_degree), (_, out_degree) in zip(
738
- G2.in_degree(), G2.out_degree()
739
- )
740
- }
741
- ),
742
- )
743
-
744
- m = {9: self.mapped[9], 1: self.mapped[1]}
745
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
746
-
747
- T1_out = {2, 4, 6}
748
- T1_in = {5, 7, 8}
749
- T1_tilde = {0, 3}
750
- T2_out = {"b", "d", "f"}
751
- T2_in = {"e", "g", "h"}
752
- T2_tilde = {"x", "c"}
753
-
754
- sparams = _StateParameters(
755
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
756
- )
757
-
758
- u = 5
759
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
760
- assert candidates == {self.mapped[u]}
761
-
762
- u = 6
763
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
764
- assert candidates == {self.mapped[u]}
765
-
766
- # Change the direction of an edge to make the degree orientation same as first candidate of u.
767
- G1.remove_edge(4, 2)
768
- G1.add_edge(2, 4)
769
- G2.remove_edge("d", "b")
770
- G2.add_edge("b", "d")
771
-
772
- gparams = _GraphParameters(
773
- G1,
774
- G2,
775
- l1,
776
- l2,
777
- nx.utils.groups(l1),
778
- nx.utils.groups(l2),
779
- nx.utils.groups(
780
- {
781
- node: (in_degree, out_degree)
782
- for (node, in_degree), (_, out_degree) in zip(
783
- G2.in_degree(), G2.out_degree()
784
- )
785
- }
786
- ),
787
- )
788
-
789
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
790
- assert candidates == {self.mapped[u], self.mapped[2]}
791
-
792
- def test_covered_neighbors_with_labels(self):
793
- G1 = nx.DiGraph()
794
- G1.add_edges_from(self.G1_edges)
795
- G1.add_node(0)
796
- G2 = nx.relabel_nodes(G1, self.mapped)
797
-
798
- G1.remove_edge(4, 2)
799
- G1.add_edge(2, 4)
800
- G2.remove_edge("d", "b")
801
- G2.add_edge("b", "d")
802
-
803
- G1_degree = {
804
- n: (in_degree, out_degree)
805
- for (n, in_degree), (_, out_degree) in zip(G1.in_degree, G1.out_degree)
806
- }
807
-
808
- nx.set_node_attributes(
809
- G1,
810
- dict(zip(G1, it.cycle(labels_many))),
811
- "label",
812
- )
813
- nx.set_node_attributes(
814
- G2,
815
- dict(
816
- zip(
817
- [self.mapped[n] for n in G1],
818
- it.cycle(labels_many),
819
- )
820
- ),
821
- "label",
822
- )
823
- l1 = dict(G1.nodes(data="label", default=-1))
824
- l2 = dict(G2.nodes(data="label", default=-1))
825
- gparams = _GraphParameters(
826
- G1,
827
- G2,
828
- l1,
829
- l2,
830
- nx.utils.groups(l1),
831
- nx.utils.groups(l2),
832
- nx.utils.groups(
833
- {
834
- node: (in_degree, out_degree)
835
- for (node, in_degree), (_, out_degree) in zip(
836
- G2.in_degree(), G2.out_degree()
837
- )
838
- }
839
- ),
840
- )
841
-
842
- m = {9: self.mapped[9], 1: self.mapped[1]}
843
- m_rev = {self.mapped[9]: 9, self.mapped[1]: 1}
844
-
845
- T1_out = {2, 4, 6}
846
- T1_in = {5, 7, 8}
847
- T1_tilde = {0, 3}
848
- T2_out = {"b", "d", "f"}
849
- T2_in = {"e", "g", "h"}
850
- T2_tilde = {"x", "c"}
851
-
852
- sparams = _StateParameters(
853
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
854
- )
855
-
856
- u = 5
857
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
858
- assert candidates == {self.mapped[u]}
859
-
860
- u = 6
861
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
862
- assert candidates == {self.mapped[u]}
863
-
864
- # Assign to 2, the same label as 6
865
- G1.nodes[2]["label"] = G1.nodes[u]["label"]
866
- G2.nodes[self.mapped[2]]["label"] = G1.nodes[u]["label"]
867
- l1 = dict(G1.nodes(data="label", default=-1))
868
- l2 = dict(G2.nodes(data="label", default=-1))
869
- gparams = _GraphParameters(
870
- G1,
871
- G2,
872
- l1,
873
- l2,
874
- nx.utils.groups(l1),
875
- nx.utils.groups(l2),
876
- nx.utils.groups(
877
- {
878
- node: (in_degree, out_degree)
879
- for (node, in_degree), (_, out_degree) in zip(
880
- G2.in_degree(), G2.out_degree()
881
- )
882
- }
883
- ),
884
- )
885
-
886
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
887
- assert candidates == {self.mapped[u], self.mapped[2]}
888
-
889
- # Change the direction of an edge to make the degree orientation same as first candidate of u.
890
- G1.remove_edge(2, 4)
891
- G1.add_edge(4, 2)
892
- G2.remove_edge("b", "d")
893
- G2.add_edge("d", "b")
894
-
895
- gparams = _GraphParameters(
896
- G1,
897
- G2,
898
- l1,
899
- l2,
900
- nx.utils.groups(l1),
901
- nx.utils.groups(l2),
902
- nx.utils.groups(
903
- {
904
- node: (in_degree, out_degree)
905
- for (node, in_degree), (_, out_degree) in zip(
906
- G2.in_degree(), G2.out_degree()
907
- )
908
- }
909
- ),
910
- )
911
-
912
- candidates = _find_candidates_Di(u, gparams, sparams, G1_degree)
913
- assert candidates == {self.mapped[u]}
914
-
915
- def test_same_in_out_degrees_no_candidate(self):
916
- g1 = nx.DiGraph([(4, 1), (4, 2), (3, 4), (5, 4), (6, 4)])
917
- g2 = nx.DiGraph([(1, 4), (2, 4), (3, 4), (4, 5), (4, 6)])
918
-
919
- l1 = dict(g1.nodes(data=None, default=-1))
920
- l2 = dict(g2.nodes(data=None, default=-1))
921
- gparams = _GraphParameters(
922
- g1,
923
- g2,
924
- l1,
925
- l2,
926
- nx.utils.groups(l1),
927
- nx.utils.groups(l2),
928
- nx.utils.groups(
929
- {
930
- node: (in_degree, out_degree)
931
- for (node, in_degree), (_, out_degree) in zip(
932
- g2.in_degree(), g2.out_degree()
933
- )
934
- }
935
- ),
936
- )
937
-
938
- g1_degree = {
939
- n: (in_degree, out_degree)
940
- for (n, in_degree), (_, out_degree) in zip(g1.in_degree, g1.out_degree)
941
- }
942
-
943
- m = {1: 1, 2: 2, 3: 3}
944
- m_rev = m.copy()
945
-
946
- T1_out = {4}
947
- T1_in = {4}
948
- T1_tilde = {5, 6}
949
- T2_out = {4}
950
- T2_in = {4}
951
- T2_tilde = {5, 6}
952
-
953
- sparams = _StateParameters(
954
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
955
- )
956
-
957
- u = 4
958
- # despite the same in and out degree, there's no candidate for u=4
959
- candidates = _find_candidates_Di(u, gparams, sparams, g1_degree)
960
- assert candidates == set()
961
- # Notice how the regular candidate selection method returns wrong result.
962
- assert _find_candidates(u, gparams, sparams, g1_degree) == {4}
963
-
964
-
965
- class TestGraphISOFeasibility:
966
- def test_const_covered_neighbors(self):
967
- G1 = nx.Graph([(0, 1), (1, 2), (3, 0), (3, 2)])
968
- G2 = nx.Graph([("a", "b"), ("b", "c"), ("k", "a"), ("k", "c")])
969
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
970
- sparams = _StateParameters(
971
- {0: "a", 1: "b", 2: "c"},
972
- {"a": 0, "b": 1, "c": 2},
973
- None,
974
- None,
975
- None,
976
- None,
977
- None,
978
- None,
979
- None,
980
- None,
981
- )
982
- u, v = 3, "k"
983
- assert _consistent_PT(u, v, gparams, sparams)
984
-
985
- def test_const_no_covered_neighbors(self):
986
- G1 = nx.Graph([(0, 1), (1, 2), (3, 4), (3, 5)])
987
- G2 = nx.Graph([("a", "b"), ("b", "c"), ("k", "w"), ("k", "z")])
988
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
989
- sparams = _StateParameters(
990
- {0: "a", 1: "b", 2: "c"},
991
- {"a": 0, "b": 1, "c": 2},
992
- None,
993
- None,
994
- None,
995
- None,
996
- None,
997
- None,
998
- None,
999
- None,
1000
- )
1001
- u, v = 3, "k"
1002
- assert _consistent_PT(u, v, gparams, sparams)
1003
-
1004
- def test_const_mixed_covered_uncovered_neighbors(self):
1005
- G1 = nx.Graph([(0, 1), (1, 2), (3, 0), (3, 2), (3, 4), (3, 5)])
1006
- G2 = nx.Graph(
1007
- [("a", "b"), ("b", "c"), ("k", "a"), ("k", "c"), ("k", "w"), ("k", "z")]
1008
- )
1009
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
1010
- sparams = _StateParameters(
1011
- {0: "a", 1: "b", 2: "c"},
1012
- {"a": 0, "b": 1, "c": 2},
1013
- None,
1014
- None,
1015
- None,
1016
- None,
1017
- None,
1018
- None,
1019
- None,
1020
- None,
1021
- )
1022
- u, v = 3, "k"
1023
- assert _consistent_PT(u, v, gparams, sparams)
1024
-
1025
- def test_const_fail_cases(self):
1026
- G1 = nx.Graph(
1027
- [
1028
- (0, 1),
1029
- (1, 2),
1030
- (10, 0),
1031
- (10, 3),
1032
- (10, 4),
1033
- (10, 5),
1034
- (10, 6),
1035
- (4, 1),
1036
- (5, 3),
1037
- ]
1038
- )
1039
- G2 = nx.Graph(
1040
- [
1041
- ("a", "b"),
1042
- ("b", "c"),
1043
- ("k", "a"),
1044
- ("k", "d"),
1045
- ("k", "e"),
1046
- ("k", "f"),
1047
- ("k", "g"),
1048
- ("e", "b"),
1049
- ("f", "d"),
1050
- ]
1051
- )
1052
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
1053
- sparams = _StateParameters(
1054
- {0: "a", 1: "b", 2: "c", 3: "d"},
1055
- {"a": 0, "b": 1, "c": 2, "d": 3},
1056
- None,
1057
- None,
1058
- None,
1059
- None,
1060
- None,
1061
- None,
1062
- None,
1063
- None,
1064
- )
1065
- u, v = 10, "k"
1066
- assert _consistent_PT(u, v, gparams, sparams)
1067
-
1068
- # Delete one uncovered neighbor of u. Notice how it still passes the test.
1069
- # Two reasons for this:
1070
- # 1. If u, v had different degrees from the beginning, they wouldn't
1071
- # be selected as candidates in the first place.
1072
- # 2. Even if they are selected, consistency is basically 1-look-ahead,
1073
- # meaning that we take into consideration the relation of the
1074
- # candidates with their mapped neighbors. The node we deleted is
1075
- # not a covered neighbor.
1076
- # Such nodes will be checked by the cut_PT function, which is
1077
- # basically the 2-look-ahead, checking the relation of the
1078
- # candidates with T1, T2 (in which belongs the node we just deleted).
1079
- G1.remove_node(6)
1080
- assert _consistent_PT(u, v, gparams, sparams)
1081
-
1082
- # Add one more covered neighbor of u in G1
1083
- G1.add_edge(u, 2)
1084
- assert not _consistent_PT(u, v, gparams, sparams)
1085
-
1086
- # Compensate in G2
1087
- G2.add_edge(v, "c")
1088
- assert _consistent_PT(u, v, gparams, sparams)
1089
-
1090
- # Add one more covered neighbor of v in G2
1091
- G2.add_edge(v, "x")
1092
- G1.add_node(7)
1093
- sparams.mapping.update({7: "x"})
1094
- sparams.reverse_mapping.update({"x": 7})
1095
- assert not _consistent_PT(u, v, gparams, sparams)
1096
-
1097
- # Compendate in G1
1098
- G1.add_edge(u, 7)
1099
- assert _consistent_PT(u, v, gparams, sparams)
1100
-
1101
- @pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
1102
- def test_cut_inconsistent_labels(self, graph_type):
1103
- G1 = graph_type(
1104
- [
1105
- (0, 1),
1106
- (1, 2),
1107
- (10, 0),
1108
- (10, 3),
1109
- (10, 4),
1110
- (10, 5),
1111
- (10, 6),
1112
- (4, 1),
1113
- (5, 3),
1114
- ]
1115
- )
1116
- G2 = graph_type(
1117
- [
1118
- ("a", "b"),
1119
- ("b", "c"),
1120
- ("k", "a"),
1121
- ("k", "d"),
1122
- ("k", "e"),
1123
- ("k", "f"),
1124
- ("k", "g"),
1125
- ("e", "b"),
1126
- ("f", "d"),
1127
- ]
1128
- )
1129
-
1130
- l1 = {n: "blue" for n in G1.nodes()}
1131
- l2 = {n: "blue" for n in G2.nodes()}
1132
- l1.update({6: "green"}) # Change the label of one neighbor of u
1133
-
1134
- gparams = _GraphParameters(
1135
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1136
- )
1137
- sparams = _StateParameters(
1138
- {0: "a", 1: "b", 2: "c", 3: "d"},
1139
- {"a": 0, "b": 1, "c": 2, "d": 3},
1140
- None,
1141
- None,
1142
- None,
1143
- None,
1144
- None,
1145
- None,
1146
- None,
1147
- None,
1148
- )
1149
-
1150
- u, v = 10, "k"
1151
- assert _cut_PT(u, v, gparams, sparams)
1152
-
1153
- def test_cut_consistent_labels(self):
1154
- G1 = nx.Graph(
1155
- [
1156
- (0, 1),
1157
- (1, 2),
1158
- (10, 0),
1159
- (10, 3),
1160
- (10, 4),
1161
- (10, 5),
1162
- (10, 6),
1163
- (4, 1),
1164
- (5, 3),
1165
- ]
1166
- )
1167
- G2 = nx.Graph(
1168
- [
1169
- ("a", "b"),
1170
- ("b", "c"),
1171
- ("k", "a"),
1172
- ("k", "d"),
1173
- ("k", "e"),
1174
- ("k", "f"),
1175
- ("k", "g"),
1176
- ("e", "b"),
1177
- ("f", "d"),
1178
- ]
1179
- )
1180
-
1181
- l1 = {n: "blue" for n in G1.nodes()}
1182
- l2 = {n: "blue" for n in G2.nodes()}
1183
-
1184
- gparams = _GraphParameters(
1185
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1186
- )
1187
- sparams = _StateParameters(
1188
- {0: "a", 1: "b", 2: "c", 3: "d"},
1189
- {"a": 0, "b": 1, "c": 2, "d": 3},
1190
- {4, 5},
1191
- None,
1192
- {6},
1193
- None,
1194
- {"e", "f"},
1195
- None,
1196
- {"g"},
1197
- None,
1198
- )
1199
-
1200
- u, v = 10, "k"
1201
- assert not _cut_PT(u, v, gparams, sparams)
1202
-
1203
- def test_cut_same_labels(self):
1204
- G1 = nx.Graph(
1205
- [
1206
- (0, 1),
1207
- (1, 2),
1208
- (10, 0),
1209
- (10, 3),
1210
- (10, 4),
1211
- (10, 5),
1212
- (10, 6),
1213
- (4, 1),
1214
- (5, 3),
1215
- ]
1216
- )
1217
- mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"}
1218
- G2 = nx.relabel_nodes(G1, mapped)
1219
- l1 = {n: "blue" for n in G1.nodes()}
1220
- l2 = {n: "blue" for n in G2.nodes()}
1221
-
1222
- gparams = _GraphParameters(
1223
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1224
- )
1225
- sparams = _StateParameters(
1226
- {0: "a", 1: "b", 2: "c", 3: "d"},
1227
- {"a": 0, "b": 1, "c": 2, "d": 3},
1228
- {4, 5},
1229
- None,
1230
- {6},
1231
- None,
1232
- {"e", "f"},
1233
- None,
1234
- {"g"},
1235
- None,
1236
- )
1237
-
1238
- u, v = 10, "k"
1239
- assert not _cut_PT(u, v, gparams, sparams)
1240
-
1241
- # Change intersection between G1[u] and T1, so it's not the same as the
1242
- # one between G2[v] and T2
1243
- G1.remove_edge(u, 4)
1244
- assert _cut_PT(u, v, gparams, sparams)
1245
-
1246
- # Compensate in G2
1247
- G2.remove_edge(v, mapped[4])
1248
- assert not _cut_PT(u, v, gparams, sparams)
1249
-
1250
- # Change intersection between G2[v] and T2_tilde, so it's not the same
1251
- # as the one between G1[u] and T1_tilde
1252
- G2.remove_edge(v, mapped[6])
1253
- assert _cut_PT(u, v, gparams, sparams)
1254
-
1255
- # Compensate in G1
1256
- G1.remove_edge(u, 6)
1257
- assert not _cut_PT(u, v, gparams, sparams)
1258
-
1259
- # Add disconnected nodes, which will form the new Ti_out
1260
- G1.add_nodes_from([6, 7, 8])
1261
- G2.add_nodes_from(["g", "y", "z"])
1262
- sparams.T1_tilde.update({6, 7, 8})
1263
- sparams.T2_tilde.update({"g", "y", "z"})
1264
-
1265
- l1 = {n: "blue" for n in G1.nodes()}
1266
- l2 = {n: "blue" for n in G2.nodes()}
1267
- gparams = _GraphParameters(
1268
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1269
- )
1270
-
1271
- assert not _cut_PT(u, v, gparams, sparams)
1272
-
1273
- # Add some new nodes to the mapping
1274
- sparams.mapping.update({6: "g", 7: "y"})
1275
- sparams.reverse_mapping.update({"g": 6, "y": 7})
1276
-
1277
- # Add more nodes to T1, T2.
1278
- G1.add_edges_from([(6, 20), (7, 20), (6, 21)])
1279
- G2.add_edges_from([("g", "i"), ("g", "j"), ("y", "j")])
1280
-
1281
- sparams.mapping.update({20: "j", 21: "i"})
1282
- sparams.reverse_mapping.update({"j": 20, "i": 21})
1283
- sparams.T1.update({20, 21})
1284
- sparams.T2.update({"i", "j"})
1285
- sparams.T1_tilde.difference_update({6, 7})
1286
- sparams.T2_tilde.difference_update({"g", "y"})
1287
-
1288
- assert not _cut_PT(u, v, gparams, sparams)
1289
-
1290
- # Add nodes from the new T1 and T2, as neighbors of u and v respectively
1291
- G1.add_edges_from([(u, 20), (u, 21)])
1292
- G2.add_edges_from([(v, "i"), (v, "j")])
1293
- l1 = {n: "blue" for n in G1.nodes()}
1294
- l2 = {n: "blue" for n in G2.nodes()}
1295
- gparams = _GraphParameters(
1296
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1297
- )
1298
-
1299
- assert not _cut_PT(u, v, gparams, sparams)
1300
-
1301
- # Change the edges, maintaining the G1[u]-T1 intersection
1302
- G1.remove_edge(u, 20)
1303
- G1.add_edge(u, 4)
1304
- assert not _cut_PT(u, v, gparams, sparams)
1305
-
1306
- # Connect u to 8 which is still in T1_tilde
1307
- G1.add_edge(u, 8)
1308
- assert _cut_PT(u, v, gparams, sparams)
1309
-
1310
- # Same for v and z, so that inters(G1[u], T1out) == inters(G2[v], T2out)
1311
- G2.add_edge(v, "z")
1312
- assert not _cut_PT(u, v, gparams, sparams)
1313
-
1314
- def test_cut_different_labels(self):
1315
- G1 = nx.Graph(
1316
- [
1317
- (0, 1),
1318
- (1, 2),
1319
- (1, 14),
1320
- (0, 4),
1321
- (1, 5),
1322
- (2, 6),
1323
- (3, 7),
1324
- (3, 6),
1325
- (4, 10),
1326
- (4, 9),
1327
- (6, 10),
1328
- (20, 9),
1329
- (20, 15),
1330
- (20, 12),
1331
- (20, 11),
1332
- (12, 13),
1333
- (11, 13),
1334
- (20, 8),
1335
- (20, 3),
1336
- (20, 5),
1337
- (20, 0),
1338
- ]
1339
- )
1340
- mapped = {
1341
- 0: "a",
1342
- 1: "b",
1343
- 2: "c",
1344
- 3: "d",
1345
- 4: "e",
1346
- 5: "f",
1347
- 6: "g",
1348
- 7: "h",
1349
- 8: "i",
1350
- 9: "j",
1351
- 10: "k",
1352
- 11: "l",
1353
- 12: "m",
1354
- 13: "n",
1355
- 14: "o",
1356
- 15: "p",
1357
- 20: "x",
1358
- }
1359
- G2 = nx.relabel_nodes(G1, mapped)
1360
-
1361
- l1 = {n: "none" for n in G1.nodes()}
1362
- l2 = {}
1363
-
1364
- l1.update(
1365
- {
1366
- 9: "blue",
1367
- 15: "blue",
1368
- 12: "blue",
1369
- 11: "green",
1370
- 3: "green",
1371
- 8: "red",
1372
- 0: "red",
1373
- 5: "yellow",
1374
- }
1375
- )
1376
- l2.update({mapped[n]: l for n, l in l1.items()})
1377
-
1378
- gparams = _GraphParameters(
1379
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1380
- )
1381
- sparams = _StateParameters(
1382
- {0: "a", 1: "b", 2: "c", 3: "d"},
1383
- {"a": 0, "b": 1, "c": 2, "d": 3},
1384
- {4, 5, 6, 7, 14},
1385
- None,
1386
- {9, 10, 15, 12, 11, 13, 8},
1387
- None,
1388
- {"e", "f", "g", "h", "o"},
1389
- None,
1390
- {"j", "k", "l", "m", "n", "i", "p"},
1391
- None,
1392
- )
1393
-
1394
- u, v = 20, "x"
1395
- assert not _cut_PT(u, v, gparams, sparams)
1396
-
1397
- # Change the orientation of the labels on neighbors of u compared to
1398
- # neighbors of v. Leave the structure intact
1399
- l1.update({9: "red"})
1400
- assert _cut_PT(u, v, gparams, sparams)
1401
-
1402
- # compensate in G2
1403
- l2.update({mapped[9]: "red"})
1404
- assert not _cut_PT(u, v, gparams, sparams)
1405
-
1406
- # Change the intersection of G1[u] and T1
1407
- G1.add_edge(u, 4)
1408
- assert _cut_PT(u, v, gparams, sparams)
1409
-
1410
- # Same for G2[v] and T2
1411
- G2.add_edge(v, mapped[4])
1412
- assert not _cut_PT(u, v, gparams, sparams)
1413
-
1414
- # Change the intersection of G2[v] and T2_tilde
1415
- G2.remove_edge(v, mapped[8])
1416
- assert _cut_PT(u, v, gparams, sparams)
1417
-
1418
- # Same for G1[u] and T1_tilde
1419
- G1.remove_edge(u, 8)
1420
- assert not _cut_PT(u, v, gparams, sparams)
1421
-
1422
- # Place 8 and mapped[8] in T1 and T2 respectively, by connecting it to covered nodes
1423
- G1.add_edge(8, 3)
1424
- G2.add_edge(mapped[8], mapped[3])
1425
- sparams.T1.add(8)
1426
- sparams.T2.add(mapped[8])
1427
- sparams.T1_tilde.remove(8)
1428
- sparams.T2_tilde.remove(mapped[8])
1429
-
1430
- assert not _cut_PT(u, v, gparams, sparams)
1431
-
1432
- # Remove neighbor of u from T1
1433
- G1.remove_node(5)
1434
- l1.pop(5)
1435
- sparams.T1.remove(5)
1436
- assert _cut_PT(u, v, gparams, sparams)
1437
-
1438
- # Same in G2
1439
- G2.remove_node(mapped[5])
1440
- l2.pop(mapped[5])
1441
- sparams.T2.remove(mapped[5])
1442
- assert not _cut_PT(u, v, gparams, sparams)
1443
-
1444
- def test_feasibility_same_labels(self):
1445
- G1 = nx.Graph(
1446
- [
1447
- (0, 1),
1448
- (1, 2),
1449
- (1, 14),
1450
- (0, 4),
1451
- (1, 5),
1452
- (2, 6),
1453
- (3, 7),
1454
- (3, 6),
1455
- (4, 10),
1456
- (4, 9),
1457
- (6, 10),
1458
- (20, 9),
1459
- (20, 15),
1460
- (20, 12),
1461
- (20, 11),
1462
- (12, 13),
1463
- (11, 13),
1464
- (20, 8),
1465
- (20, 2),
1466
- (20, 5),
1467
- (20, 0),
1468
- ]
1469
- )
1470
- mapped = {
1471
- 0: "a",
1472
- 1: "b",
1473
- 2: "c",
1474
- 3: "d",
1475
- 4: "e",
1476
- 5: "f",
1477
- 6: "g",
1478
- 7: "h",
1479
- 8: "i",
1480
- 9: "j",
1481
- 10: "k",
1482
- 11: "l",
1483
- 12: "m",
1484
- 13: "n",
1485
- 14: "o",
1486
- 15: "p",
1487
- 20: "x",
1488
- }
1489
- G2 = nx.relabel_nodes(G1, mapped)
1490
-
1491
- l1 = {n: "blue" for n in G1.nodes()}
1492
- l2 = {mapped[n]: "blue" for n in G1.nodes()}
1493
-
1494
- gparams = _GraphParameters(
1495
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1496
- )
1497
- sparams = _StateParameters(
1498
- {0: "a", 1: "b", 2: "c", 3: "d"},
1499
- {"a": 0, "b": 1, "c": 2, "d": 3},
1500
- {4, 5, 6, 7, 14},
1501
- None,
1502
- {9, 10, 15, 12, 11, 13, 8},
1503
- None,
1504
- {"e", "f", "g", "h", "o"},
1505
- None,
1506
- {"j", "k", "l", "m", "n", "i", "p"},
1507
- None,
1508
- )
1509
-
1510
- u, v = 20, "x"
1511
- assert not _cut_PT(u, v, gparams, sparams)
1512
-
1513
- # Change structure in G2 such that, ONLY consistency is harmed
1514
- G2.remove_edge(mapped[20], mapped[2])
1515
- G2.add_edge(mapped[20], mapped[3])
1516
-
1517
- # Consistency check fails, while the cutting rules are satisfied!
1518
- assert not _cut_PT(u, v, gparams, sparams)
1519
- assert not _consistent_PT(u, v, gparams, sparams)
1520
-
1521
- # Compensate in G1 and make it consistent
1522
- G1.remove_edge(20, 2)
1523
- G1.add_edge(20, 3)
1524
- assert not _cut_PT(u, v, gparams, sparams)
1525
- assert _consistent_PT(u, v, gparams, sparams)
1526
-
1527
- # ONLY fail the cutting check
1528
- G2.add_edge(v, mapped[10])
1529
- assert _cut_PT(u, v, gparams, sparams)
1530
- assert _consistent_PT(u, v, gparams, sparams)
1531
-
1532
- def test_feasibility_different_labels(self):
1533
- G1 = nx.Graph(
1534
- [
1535
- (0, 1),
1536
- (1, 2),
1537
- (1, 14),
1538
- (0, 4),
1539
- (1, 5),
1540
- (2, 6),
1541
- (3, 7),
1542
- (3, 6),
1543
- (4, 10),
1544
- (4, 9),
1545
- (6, 10),
1546
- (20, 9),
1547
- (20, 15),
1548
- (20, 12),
1549
- (20, 11),
1550
- (12, 13),
1551
- (11, 13),
1552
- (20, 8),
1553
- (20, 2),
1554
- (20, 5),
1555
- (20, 0),
1556
- ]
1557
- )
1558
- mapped = {
1559
- 0: "a",
1560
- 1: "b",
1561
- 2: "c",
1562
- 3: "d",
1563
- 4: "e",
1564
- 5: "f",
1565
- 6: "g",
1566
- 7: "h",
1567
- 8: "i",
1568
- 9: "j",
1569
- 10: "k",
1570
- 11: "l",
1571
- 12: "m",
1572
- 13: "n",
1573
- 14: "o",
1574
- 15: "p",
1575
- 20: "x",
1576
- }
1577
- G2 = nx.relabel_nodes(G1, mapped)
1578
-
1579
- l1 = {n: "none" for n in G1.nodes()}
1580
- l2 = {}
1581
-
1582
- l1.update(
1583
- {
1584
- 9: "blue",
1585
- 15: "blue",
1586
- 12: "blue",
1587
- 11: "green",
1588
- 2: "green",
1589
- 8: "red",
1590
- 0: "red",
1591
- 5: "yellow",
1592
- }
1593
- )
1594
- l2.update({mapped[n]: l for n, l in l1.items()})
1595
-
1596
- gparams = _GraphParameters(
1597
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1598
- )
1599
- sparams = _StateParameters(
1600
- {0: "a", 1: "b", 2: "c", 3: "d"},
1601
- {"a": 0, "b": 1, "c": 2, "d": 3},
1602
- {4, 5, 6, 7, 14},
1603
- None,
1604
- {9, 10, 15, 12, 11, 13, 8},
1605
- None,
1606
- {"e", "f", "g", "h", "o"},
1607
- None,
1608
- {"j", "k", "l", "m", "n", "i", "p"},
1609
- None,
1610
- )
1611
-
1612
- u, v = 20, "x"
1613
- assert not _cut_PT(u, v, gparams, sparams)
1614
-
1615
- # Change structure in G2 such that, ONLY consistency is harmed
1616
- G2.remove_edge(mapped[20], mapped[2])
1617
- G2.add_edge(mapped[20], mapped[3])
1618
- l2.update({mapped[3]: "green"})
1619
-
1620
- # Consistency check fails, while the cutting rules are satisfied!
1621
- assert not _cut_PT(u, v, gparams, sparams)
1622
- assert not _consistent_PT(u, v, gparams, sparams)
1623
-
1624
- # Compensate in G1 and make it consistent
1625
- G1.remove_edge(20, 2)
1626
- G1.add_edge(20, 3)
1627
- l1.update({3: "green"})
1628
- assert not _cut_PT(u, v, gparams, sparams)
1629
- assert _consistent_PT(u, v, gparams, sparams)
1630
-
1631
- # ONLY fail the cutting check
1632
- l1.update({5: "red"})
1633
- assert _cut_PT(u, v, gparams, sparams)
1634
- assert _consistent_PT(u, v, gparams, sparams)
1635
-
1636
-
1637
- class TestMultiGraphISOFeasibility:
1638
- def test_const_covered_neighbors(self):
1639
- G1 = nx.MultiGraph(
1640
- [(0, 1), (0, 1), (1, 2), (3, 0), (3, 0), (3, 0), (3, 2), (3, 2)]
1641
- )
1642
- G2 = nx.MultiGraph(
1643
- [
1644
- ("a", "b"),
1645
- ("a", "b"),
1646
- ("b", "c"),
1647
- ("k", "a"),
1648
- ("k", "a"),
1649
- ("k", "a"),
1650
- ("k", "c"),
1651
- ("k", "c"),
1652
- ]
1653
- )
1654
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
1655
- sparams = _StateParameters(
1656
- {0: "a", 1: "b", 2: "c"},
1657
- {"a": 0, "b": 1, "c": 2},
1658
- None,
1659
- None,
1660
- None,
1661
- None,
1662
- None,
1663
- None,
1664
- None,
1665
- None,
1666
- )
1667
- u, v = 3, "k"
1668
- assert _consistent_PT(u, v, gparams, sparams)
1669
-
1670
- def test_const_no_covered_neighbors(self):
1671
- G1 = nx.MultiGraph([(0, 1), (0, 1), (1, 2), (3, 4), (3, 4), (3, 5)])
1672
- G2 = nx.MultiGraph([("a", "b"), ("b", "c"), ("k", "w"), ("k", "w"), ("k", "z")])
1673
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
1674
- sparams = _StateParameters(
1675
- {0: "a", 1: "b", 2: "c"},
1676
- {"a": 0, "b": 1, "c": 2},
1677
- None,
1678
- None,
1679
- None,
1680
- None,
1681
- None,
1682
- None,
1683
- None,
1684
- None,
1685
- )
1686
- u, v = 3, "k"
1687
- assert _consistent_PT(u, v, gparams, sparams)
1688
-
1689
- def test_const_mixed_covered_uncovered_neighbors(self):
1690
- G1 = nx.MultiGraph(
1691
- [(0, 1), (1, 2), (3, 0), (3, 0), (3, 0), (3, 2), (3, 2), (3, 4), (3, 5)]
1692
- )
1693
- G2 = nx.MultiGraph(
1694
- [
1695
- ("a", "b"),
1696
- ("b", "c"),
1697
- ("k", "a"),
1698
- ("k", "a"),
1699
- ("k", "a"),
1700
- ("k", "c"),
1701
- ("k", "c"),
1702
- ("k", "w"),
1703
- ("k", "z"),
1704
- ]
1705
- )
1706
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
1707
- sparams = _StateParameters(
1708
- {0: "a", 1: "b", 2: "c"},
1709
- {"a": 0, "b": 1, "c": 2},
1710
- None,
1711
- None,
1712
- None,
1713
- None,
1714
- None,
1715
- None,
1716
- None,
1717
- None,
1718
- )
1719
- u, v = 3, "k"
1720
- assert _consistent_PT(u, v, gparams, sparams)
1721
-
1722
- def test_const_fail_cases(self):
1723
- G1 = nx.MultiGraph(
1724
- [
1725
- (0, 1),
1726
- (1, 2),
1727
- (10, 0),
1728
- (10, 0),
1729
- (10, 0),
1730
- (10, 3),
1731
- (10, 3),
1732
- (10, 4),
1733
- (10, 5),
1734
- (10, 6),
1735
- (10, 6),
1736
- (4, 1),
1737
- (5, 3),
1738
- ]
1739
- )
1740
- mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"}
1741
- G2 = nx.relabel_nodes(G1, mapped)
1742
-
1743
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
1744
- sparams = _StateParameters(
1745
- {0: "a", 1: "b", 2: "c", 3: "d"},
1746
- {"a": 0, "b": 1, "c": 2, "d": 3},
1747
- None,
1748
- None,
1749
- None,
1750
- None,
1751
- None,
1752
- None,
1753
- None,
1754
- None,
1755
- )
1756
- u, v = 10, "k"
1757
- assert _consistent_PT(u, v, gparams, sparams)
1758
-
1759
- # Delete one uncovered neighbor of u. Notice how it still passes the test.
1760
- # Two reasons for this:
1761
- # 1. If u, v had different degrees from the beginning, they wouldn't be
1762
- # selected as candidates in the first place.
1763
- # 2. Even if they are selected, consistency is basically 1-look-ahead,
1764
- # meaning that we take into consideration the relation of the candidates
1765
- # with their mapped neighbors. The node we deleted is not a covered
1766
- # neighbor. Such nodes will be checked by the cut_PT function, which
1767
- # is basically the 2-look-ahead, checking the relation of the candidates
1768
- # with T1, T2 (in which belongs the node we just deleted).
1769
- G1.remove_node(6)
1770
- assert _consistent_PT(u, v, gparams, sparams)
1771
-
1772
- # Add one more covered neighbor of u in G1
1773
- G1.add_edge(u, 2)
1774
- assert not _consistent_PT(u, v, gparams, sparams)
1775
-
1776
- # Compensate in G2
1777
- G2.add_edge(v, "c")
1778
- assert _consistent_PT(u, v, gparams, sparams)
1779
-
1780
- # Add one more covered neighbor of v in G2
1781
- G2.add_edge(v, "x")
1782
- G1.add_node(7)
1783
- sparams.mapping.update({7: "x"})
1784
- sparams.reverse_mapping.update({"x": 7})
1785
- assert not _consistent_PT(u, v, gparams, sparams)
1786
-
1787
- # Compendate in G1
1788
- G1.add_edge(u, 7)
1789
- assert _consistent_PT(u, v, gparams, sparams)
1790
-
1791
- # Delete an edge between u and a covered neighbor
1792
- G1.remove_edges_from([(u, 0), (u, 0)])
1793
- assert not _consistent_PT(u, v, gparams, sparams)
1794
-
1795
- # Compensate in G2
1796
- G2.remove_edges_from([(v, mapped[0]), (v, mapped[0])])
1797
- assert _consistent_PT(u, v, gparams, sparams)
1798
-
1799
- # Remove an edge between v and a covered neighbor
1800
- G2.remove_edge(v, mapped[3])
1801
- assert not _consistent_PT(u, v, gparams, sparams)
1802
-
1803
- # Compensate in G1
1804
- G1.remove_edge(u, 3)
1805
- assert _consistent_PT(u, v, gparams, sparams)
1806
-
1807
- def test_cut_same_labels(self):
1808
- G1 = nx.MultiGraph(
1809
- [
1810
- (0, 1),
1811
- (1, 2),
1812
- (10, 0),
1813
- (10, 0),
1814
- (10, 0),
1815
- (10, 3),
1816
- (10, 3),
1817
- (10, 4),
1818
- (10, 4),
1819
- (10, 5),
1820
- (10, 5),
1821
- (10, 5),
1822
- (10, 5),
1823
- (10, 6),
1824
- (10, 6),
1825
- (4, 1),
1826
- (5, 3),
1827
- ]
1828
- )
1829
- mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"}
1830
- G2 = nx.relabel_nodes(G1, mapped)
1831
- l1 = {n: "blue" for n in G1.nodes()}
1832
- l2 = {n: "blue" for n in G2.nodes()}
1833
-
1834
- gparams = _GraphParameters(
1835
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1836
- )
1837
- sparams = _StateParameters(
1838
- {0: "a", 1: "b", 2: "c", 3: "d"},
1839
- {"a": 0, "b": 1, "c": 2, "d": 3},
1840
- {4, 5},
1841
- None,
1842
- {6},
1843
- None,
1844
- {"e", "f"},
1845
- None,
1846
- {"g"},
1847
- None,
1848
- )
1849
-
1850
- u, v = 10, "k"
1851
- assert not _cut_PT(u, v, gparams, sparams)
1852
-
1853
- # Remove one of the multiple edges between u and a neighbor
1854
- G1.remove_edge(u, 4)
1855
- assert _cut_PT(u, v, gparams, sparams)
1856
-
1857
- # Compensate in G2
1858
- G1.remove_edge(u, 4)
1859
- G2.remove_edges_from([(v, mapped[4]), (v, mapped[4])])
1860
- assert not _cut_PT(u, v, gparams, sparams)
1861
-
1862
- # Change intersection between G2[v] and T2_tilde, so it's not the same
1863
- # as the one between G1[u] and T1_tilde
1864
- G2.remove_edge(v, mapped[6])
1865
- assert _cut_PT(u, v, gparams, sparams)
1866
-
1867
- # Compensate in G1
1868
- G1.remove_edge(u, 6)
1869
- assert not _cut_PT(u, v, gparams, sparams)
1870
-
1871
- # Add more edges between u and neighbor which belongs in T1_tilde
1872
- G1.add_edges_from([(u, 5), (u, 5), (u, 5)])
1873
- assert _cut_PT(u, v, gparams, sparams)
1874
-
1875
- # Compensate in G2
1876
- G2.add_edges_from([(v, mapped[5]), (v, mapped[5]), (v, mapped[5])])
1877
- assert not _cut_PT(u, v, gparams, sparams)
1878
-
1879
- # Add disconnected nodes, which will form the new Ti_out
1880
- G1.add_nodes_from([6, 7, 8])
1881
- G2.add_nodes_from(["g", "y", "z"])
1882
- G1.add_edges_from([(u, 6), (u, 6), (u, 6), (u, 8)])
1883
- G2.add_edges_from([(v, "g"), (v, "g"), (v, "g"), (v, "z")])
1884
-
1885
- sparams.T1_tilde.update({6, 7, 8})
1886
- sparams.T2_tilde.update({"g", "y", "z"})
1887
-
1888
- l1 = {n: "blue" for n in G1.nodes()}
1889
- l2 = {n: "blue" for n in G2.nodes()}
1890
- gparams = _GraphParameters(
1891
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1892
- )
1893
-
1894
- assert not _cut_PT(u, v, gparams, sparams)
1895
-
1896
- # Add some new nodes to the mapping
1897
- sparams.mapping.update({6: "g", 7: "y"})
1898
- sparams.reverse_mapping.update({"g": 6, "y": 7})
1899
-
1900
- # Add more nodes to T1, T2.
1901
- G1.add_edges_from([(6, 20), (7, 20), (6, 21)])
1902
- G2.add_edges_from([("g", "i"), ("g", "j"), ("y", "j")])
1903
-
1904
- sparams.T1.update({20, 21})
1905
- sparams.T2.update({"i", "j"})
1906
- sparams.T1_tilde.difference_update({6, 7})
1907
- sparams.T2_tilde.difference_update({"g", "y"})
1908
-
1909
- assert not _cut_PT(u, v, gparams, sparams)
1910
-
1911
- # Remove some edges
1912
- G2.remove_edge(v, "g")
1913
- assert _cut_PT(u, v, gparams, sparams)
1914
-
1915
- G1.remove_edge(u, 6)
1916
- G1.add_edge(u, 8)
1917
- G2.add_edge(v, "z")
1918
- assert not _cut_PT(u, v, gparams, sparams)
1919
-
1920
- # Add nodes from the new T1 and T2, as neighbors of u and v respectively
1921
- G1.add_edges_from([(u, 20), (u, 20), (u, 20), (u, 21)])
1922
- G2.add_edges_from([(v, "i"), (v, "i"), (v, "i"), (v, "j")])
1923
- l1 = {n: "blue" for n in G1.nodes()}
1924
- l2 = {n: "blue" for n in G2.nodes()}
1925
- gparams = _GraphParameters(
1926
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
1927
- )
1928
-
1929
- assert not _cut_PT(u, v, gparams, sparams)
1930
-
1931
- # Change the edges
1932
- G1.remove_edge(u, 20)
1933
- G1.add_edge(u, 4)
1934
- assert _cut_PT(u, v, gparams, sparams)
1935
-
1936
- G2.remove_edge(v, "i")
1937
- G2.add_edge(v, mapped[4])
1938
- assert not _cut_PT(u, v, gparams, sparams)
1939
-
1940
- def test_cut_different_labels(self):
1941
- G1 = nx.MultiGraph(
1942
- [
1943
- (0, 1),
1944
- (0, 1),
1945
- (1, 2),
1946
- (1, 2),
1947
- (1, 14),
1948
- (0, 4),
1949
- (1, 5),
1950
- (2, 6),
1951
- (3, 7),
1952
- (3, 6),
1953
- (4, 10),
1954
- (4, 9),
1955
- (6, 10),
1956
- (20, 9),
1957
- (20, 9),
1958
- (20, 9),
1959
- (20, 15),
1960
- (20, 15),
1961
- (20, 12),
1962
- (20, 11),
1963
- (20, 11),
1964
- (20, 11),
1965
- (12, 13),
1966
- (11, 13),
1967
- (20, 8),
1968
- (20, 8),
1969
- (20, 3),
1970
- (20, 3),
1971
- (20, 5),
1972
- (20, 5),
1973
- (20, 5),
1974
- (20, 0),
1975
- (20, 0),
1976
- (20, 0),
1977
- ]
1978
- )
1979
- mapped = {
1980
- 0: "a",
1981
- 1: "b",
1982
- 2: "c",
1983
- 3: "d",
1984
- 4: "e",
1985
- 5: "f",
1986
- 6: "g",
1987
- 7: "h",
1988
- 8: "i",
1989
- 9: "j",
1990
- 10: "k",
1991
- 11: "l",
1992
- 12: "m",
1993
- 13: "n",
1994
- 14: "o",
1995
- 15: "p",
1996
- 20: "x",
1997
- }
1998
- G2 = nx.relabel_nodes(G1, mapped)
1999
-
2000
- l1 = {n: "none" for n in G1.nodes()}
2001
- l2 = {}
2002
-
2003
- l1.update(
2004
- {
2005
- 9: "blue",
2006
- 15: "blue",
2007
- 12: "blue",
2008
- 11: "green",
2009
- 3: "green",
2010
- 8: "red",
2011
- 0: "red",
2012
- 5: "yellow",
2013
- }
2014
- )
2015
- l2.update({mapped[n]: l for n, l in l1.items()})
2016
-
2017
- gparams = _GraphParameters(
2018
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2019
- )
2020
- sparams = _StateParameters(
2021
- {0: "a", 1: "b", 2: "c", 3: "d"},
2022
- {"a": 0, "b": 1, "c": 2, "d": 3},
2023
- {4, 5, 6, 7, 14},
2024
- None,
2025
- {9, 10, 15, 12, 11, 13, 8},
2026
- None,
2027
- {"e", "f", "g", "h", "o"},
2028
- None,
2029
- {"j", "k", "l", "m", "n", "i", "p"},
2030
- None,
2031
- )
2032
-
2033
- u, v = 20, "x"
2034
- assert not _cut_PT(u, v, gparams, sparams)
2035
-
2036
- # Change the orientation of the labels on neighbors of u compared to
2037
- # neighbors of v. Leave the structure intact
2038
- l1.update({9: "red"})
2039
- assert _cut_PT(u, v, gparams, sparams)
2040
-
2041
- # compensate in G2
2042
- l2.update({mapped[9]: "red"})
2043
- assert not _cut_PT(u, v, gparams, sparams)
2044
-
2045
- # Change the intersection of G1[u] and T1
2046
- G1.add_edge(u, 4)
2047
- assert _cut_PT(u, v, gparams, sparams)
2048
-
2049
- # Same for G2[v] and T2
2050
- G2.add_edge(v, mapped[4])
2051
- assert not _cut_PT(u, v, gparams, sparams)
2052
-
2053
- # Delete one from the multiple edges
2054
- G2.remove_edge(v, mapped[8])
2055
- assert _cut_PT(u, v, gparams, sparams)
2056
-
2057
- # Same for G1[u] and T1_tilde
2058
- G1.remove_edge(u, 8)
2059
- assert not _cut_PT(u, v, gparams, sparams)
2060
-
2061
- # Place 8 and mapped[8] in T1 and T2 respectively, by connecting it to covered nodes
2062
- G1.add_edges_from([(8, 3), (8, 3), (8, u)])
2063
- G2.add_edges_from([(mapped[8], mapped[3]), (mapped[8], mapped[3])])
2064
- sparams.T1.add(8)
2065
- sparams.T2.add(mapped[8])
2066
- sparams.T1_tilde.remove(8)
2067
- sparams.T2_tilde.remove(mapped[8])
2068
-
2069
- assert _cut_PT(u, v, gparams, sparams)
2070
-
2071
- # Fix uneven edges
2072
- G1.remove_edge(8, u)
2073
- assert not _cut_PT(u, v, gparams, sparams)
2074
-
2075
- # Remove neighbor of u from T1
2076
- G1.remove_node(5)
2077
- l1.pop(5)
2078
- sparams.T1.remove(5)
2079
- assert _cut_PT(u, v, gparams, sparams)
2080
-
2081
- # Same in G2
2082
- G2.remove_node(mapped[5])
2083
- l2.pop(mapped[5])
2084
- sparams.T2.remove(mapped[5])
2085
- assert not _cut_PT(u, v, gparams, sparams)
2086
-
2087
- def test_feasibility_same_labels(self):
2088
- G1 = nx.MultiGraph(
2089
- [
2090
- (0, 1),
2091
- (0, 1),
2092
- (1, 2),
2093
- (1, 2),
2094
- (1, 14),
2095
- (0, 4),
2096
- (1, 5),
2097
- (2, 6),
2098
- (3, 7),
2099
- (3, 6),
2100
- (4, 10),
2101
- (4, 9),
2102
- (6, 10),
2103
- (20, 9),
2104
- (20, 9),
2105
- (20, 9),
2106
- (20, 15),
2107
- (20, 15),
2108
- (20, 12),
2109
- (20, 11),
2110
- (20, 11),
2111
- (20, 11),
2112
- (12, 13),
2113
- (11, 13),
2114
- (20, 8),
2115
- (20, 8),
2116
- (20, 3),
2117
- (20, 3),
2118
- (20, 5),
2119
- (20, 5),
2120
- (20, 5),
2121
- (20, 0),
2122
- (20, 0),
2123
- (20, 0),
2124
- ]
2125
- )
2126
- mapped = {
2127
- 0: "a",
2128
- 1: "b",
2129
- 2: "c",
2130
- 3: "d",
2131
- 4: "e",
2132
- 5: "f",
2133
- 6: "g",
2134
- 7: "h",
2135
- 8: "i",
2136
- 9: "j",
2137
- 10: "k",
2138
- 11: "l",
2139
- 12: "m",
2140
- 13: "n",
2141
- 14: "o",
2142
- 15: "p",
2143
- 20: "x",
2144
- }
2145
- G2 = nx.relabel_nodes(G1, mapped)
2146
- l1 = {n: "blue" for n in G1.nodes()}
2147
- l2 = {mapped[n]: "blue" for n in G1.nodes()}
2148
-
2149
- gparams = _GraphParameters(
2150
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2151
- )
2152
- sparams = _StateParameters(
2153
- {0: "a", 1: "b", 2: "c", 3: "d"},
2154
- {"a": 0, "b": 1, "c": 2, "d": 3},
2155
- {4, 5, 6, 7, 14},
2156
- None,
2157
- {9, 10, 15, 12, 11, 13, 8},
2158
- None,
2159
- {"e", "f", "g", "h", "o"},
2160
- None,
2161
- {"j", "k", "l", "m", "n", "i", "p"},
2162
- None,
2163
- )
2164
-
2165
- u, v = 20, "x"
2166
- assert not _cut_PT(u, v, gparams, sparams)
2167
-
2168
- # Change structure in G2 such that, ONLY consistency is harmed
2169
- G2.remove_edges_from([(mapped[20], mapped[3]), (mapped[20], mapped[3])])
2170
- G2.add_edges_from([(mapped[20], mapped[2]), (mapped[20], mapped[2])])
2171
-
2172
- # Consistency check fails, while the cutting rules are satisfied!
2173
- assert not _cut_PT(u, v, gparams, sparams)
2174
- assert not _consistent_PT(u, v, gparams, sparams)
2175
-
2176
- # Compensate in G1 and make it consistent
2177
- G1.remove_edges_from([(20, 3), (20, 3)])
2178
- G1.add_edges_from([(20, 2), (20, 2)])
2179
- assert not _cut_PT(u, v, gparams, sparams)
2180
- assert _consistent_PT(u, v, gparams, sparams)
2181
-
2182
- # ONLY fail the cutting check
2183
- G2.add_edges_from([(v, mapped[10])] * 5)
2184
- assert _cut_PT(u, v, gparams, sparams)
2185
- assert _consistent_PT(u, v, gparams, sparams)
2186
-
2187
- # Pass all tests
2188
- G1.add_edges_from([(u, 10)] * 5)
2189
- assert not _cut_PT(u, v, gparams, sparams)
2190
- assert _consistent_PT(u, v, gparams, sparams)
2191
-
2192
- def test_feasibility_different_labels(self):
2193
- G1 = nx.MultiGraph(
2194
- [
2195
- (0, 1),
2196
- (0, 1),
2197
- (1, 2),
2198
- (1, 2),
2199
- (1, 14),
2200
- (0, 4),
2201
- (1, 5),
2202
- (2, 6),
2203
- (3, 7),
2204
- (3, 6),
2205
- (4, 10),
2206
- (4, 9),
2207
- (6, 10),
2208
- (20, 9),
2209
- (20, 9),
2210
- (20, 9),
2211
- (20, 15),
2212
- (20, 15),
2213
- (20, 12),
2214
- (20, 11),
2215
- (20, 11),
2216
- (20, 11),
2217
- (12, 13),
2218
- (11, 13),
2219
- (20, 8),
2220
- (20, 8),
2221
- (20, 2),
2222
- (20, 2),
2223
- (20, 5),
2224
- (20, 5),
2225
- (20, 5),
2226
- (20, 0),
2227
- (20, 0),
2228
- (20, 0),
2229
- ]
2230
- )
2231
- mapped = {
2232
- 0: "a",
2233
- 1: "b",
2234
- 2: "c",
2235
- 3: "d",
2236
- 4: "e",
2237
- 5: "f",
2238
- 6: "g",
2239
- 7: "h",
2240
- 8: "i",
2241
- 9: "j",
2242
- 10: "k",
2243
- 11: "l",
2244
- 12: "m",
2245
- 13: "n",
2246
- 14: "o",
2247
- 15: "p",
2248
- 20: "x",
2249
- }
2250
- G2 = nx.relabel_nodes(G1, mapped)
2251
- l1 = {n: "none" for n in G1.nodes()}
2252
- l2 = {}
2253
-
2254
- l1.update(
2255
- {
2256
- 9: "blue",
2257
- 15: "blue",
2258
- 12: "blue",
2259
- 11: "green",
2260
- 2: "green",
2261
- 8: "red",
2262
- 0: "red",
2263
- 5: "yellow",
2264
- }
2265
- )
2266
- l2.update({mapped[n]: l for n, l in l1.items()})
2267
-
2268
- gparams = _GraphParameters(
2269
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2270
- )
2271
- sparams = _StateParameters(
2272
- {0: "a", 1: "b", 2: "c", 3: "d"},
2273
- {"a": 0, "b": 1, "c": 2, "d": 3},
2274
- {4, 5, 6, 7, 14},
2275
- None,
2276
- {9, 10, 15, 12, 11, 13, 8},
2277
- None,
2278
- {"e", "f", "g", "h", "o"},
2279
- None,
2280
- {"j", "k", "l", "m", "n", "i", "p"},
2281
- None,
2282
- )
2283
-
2284
- u, v = 20, "x"
2285
- assert not _cut_PT(u, v, gparams, sparams)
2286
-
2287
- # Change structure in G2 such that, ONLY consistency is harmed
2288
- G2.remove_edges_from([(mapped[20], mapped[2]), (mapped[20], mapped[2])])
2289
- G2.add_edges_from([(mapped[20], mapped[3]), (mapped[20], mapped[3])])
2290
- l2.update({mapped[3]: "green"})
2291
-
2292
- # Consistency check fails, while the cutting rules are satisfied!
2293
- assert not _cut_PT(u, v, gparams, sparams)
2294
- assert not _consistent_PT(u, v, gparams, sparams)
2295
-
2296
- # Compensate in G1 and make it consistent
2297
- G1.remove_edges_from([(20, 2), (20, 2)])
2298
- G1.add_edges_from([(20, 3), (20, 3)])
2299
- l1.update({3: "green"})
2300
- assert not _cut_PT(u, v, gparams, sparams)
2301
- assert _consistent_PT(u, v, gparams, sparams)
2302
-
2303
- # ONLY fail the cutting check
2304
- l1.update({5: "red"})
2305
- assert _cut_PT(u, v, gparams, sparams)
2306
- assert _consistent_PT(u, v, gparams, sparams)
2307
-
2308
-
2309
- class TestDiGraphISOFeasibility:
2310
- def test_const_covered_neighbors(self):
2311
- G1 = nx.DiGraph([(0, 1), (1, 2), (0, 3), (2, 3)])
2312
- G2 = nx.DiGraph([("a", "b"), ("b", "c"), ("a", "k"), ("c", "k")])
2313
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
2314
- sparams = _StateParameters(
2315
- {0: "a", 1: "b", 2: "c"},
2316
- {"a": 0, "b": 1, "c": 2},
2317
- None,
2318
- None,
2319
- None,
2320
- None,
2321
- None,
2322
- None,
2323
- None,
2324
- None,
2325
- )
2326
- u, v = 3, "k"
2327
- assert _consistent_PT(u, v, gparams, sparams)
2328
-
2329
- def test_const_no_covered_neighbors(self):
2330
- G1 = nx.DiGraph([(0, 1), (1, 2), (3, 4), (3, 5)])
2331
- G2 = nx.DiGraph([("a", "b"), ("b", "c"), ("k", "w"), ("k", "z")])
2332
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
2333
- sparams = _StateParameters(
2334
- {0: "a", 1: "b", 2: "c"},
2335
- {"a": 0, "b": 1, "c": 2},
2336
- None,
2337
- None,
2338
- None,
2339
- None,
2340
- None,
2341
- None,
2342
- None,
2343
- None,
2344
- )
2345
- u, v = 3, "k"
2346
- assert _consistent_PT(u, v, gparams, sparams)
2347
-
2348
- def test_const_mixed_covered_uncovered_neighbors(self):
2349
- G1 = nx.DiGraph([(0, 1), (1, 2), (3, 0), (3, 2), (3, 4), (3, 5)])
2350
- G2 = nx.DiGraph(
2351
- [("a", "b"), ("b", "c"), ("k", "a"), ("k", "c"), ("k", "w"), ("k", "z")]
2352
- )
2353
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
2354
- sparams = _StateParameters(
2355
- {0: "a", 1: "b", 2: "c"},
2356
- {"a": 0, "b": 1, "c": 2},
2357
- None,
2358
- None,
2359
- None,
2360
- None,
2361
- None,
2362
- None,
2363
- None,
2364
- None,
2365
- )
2366
- u, v = 3, "k"
2367
- assert _consistent_PT(u, v, gparams, sparams)
2368
-
2369
- def test_const_fail_cases(self):
2370
- G1 = nx.DiGraph(
2371
- [
2372
- (0, 1),
2373
- (2, 1),
2374
- (10, 0),
2375
- (10, 3),
2376
- (10, 4),
2377
- (5, 10),
2378
- (10, 6),
2379
- (1, 4),
2380
- (5, 3),
2381
- ]
2382
- )
2383
- G2 = nx.DiGraph(
2384
- [
2385
- ("a", "b"),
2386
- ("c", "b"),
2387
- ("k", "a"),
2388
- ("k", "d"),
2389
- ("k", "e"),
2390
- ("f", "k"),
2391
- ("k", "g"),
2392
- ("b", "e"),
2393
- ("f", "d"),
2394
- ]
2395
- )
2396
- gparams = _GraphParameters(G1, G2, None, None, None, None, None)
2397
- sparams = _StateParameters(
2398
- {0: "a", 1: "b", 2: "c", 3: "d"},
2399
- {"a": 0, "b": 1, "c": 2, "d": 3},
2400
- None,
2401
- None,
2402
- None,
2403
- None,
2404
- None,
2405
- None,
2406
- None,
2407
- None,
2408
- )
2409
- u, v = 10, "k"
2410
- assert _consistent_PT(u, v, gparams, sparams)
2411
-
2412
- # Delete one uncovered neighbor of u. Notice how it still passes the
2413
- # test. Two reasons for this:
2414
- # 1. If u, v had different degrees from the beginning, they wouldn't
2415
- # be selected as candidates in the first place.
2416
- # 2. Even if they are selected, consistency is basically
2417
- # 1-look-ahead, meaning that we take into consideration the
2418
- # relation of the candidates with their mapped neighbors.
2419
- # The node we deleted is not a covered neighbor.
2420
- # Such nodes will be checked by the cut_PT function, which is
2421
- # basically the 2-look-ahead, checking the relation of the
2422
- # candidates with T1, T2 (in which belongs the node we just deleted).
2423
- G1.remove_node(6)
2424
- assert _consistent_PT(u, v, gparams, sparams)
2425
-
2426
- # Add one more covered neighbor of u in G1
2427
- G1.add_edge(u, 2)
2428
- assert not _consistent_PT(u, v, gparams, sparams)
2429
-
2430
- # Compensate in G2
2431
- G2.add_edge(v, "c")
2432
- assert _consistent_PT(u, v, gparams, sparams)
2433
-
2434
- # Add one more covered neighbor of v in G2
2435
- G2.add_edge(v, "x")
2436
- G1.add_node(7)
2437
- sparams.mapping.update({7: "x"})
2438
- sparams.reverse_mapping.update({"x": 7})
2439
- assert not _consistent_PT(u, v, gparams, sparams)
2440
-
2441
- # Compensate in G1
2442
- G1.add_edge(u, 7)
2443
- assert _consistent_PT(u, v, gparams, sparams)
2444
-
2445
- def test_cut_inconsistent_labels(self):
2446
- G1 = nx.DiGraph(
2447
- [
2448
- (0, 1),
2449
- (2, 1),
2450
- (10, 0),
2451
- (10, 3),
2452
- (10, 4),
2453
- (5, 10),
2454
- (10, 6),
2455
- (1, 4),
2456
- (5, 3),
2457
- ]
2458
- )
2459
- G2 = nx.DiGraph(
2460
- [
2461
- ("a", "b"),
2462
- ("c", "b"),
2463
- ("k", "a"),
2464
- ("k", "d"),
2465
- ("k", "e"),
2466
- ("f", "k"),
2467
- ("k", "g"),
2468
- ("b", "e"),
2469
- ("f", "d"),
2470
- ]
2471
- )
2472
-
2473
- l1 = {n: "blue" for n in G1.nodes()}
2474
- l2 = {n: "blue" for n in G2.nodes()}
2475
- l1.update({5: "green"}) # Change the label of one neighbor of u
2476
-
2477
- gparams = _GraphParameters(
2478
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2479
- )
2480
- sparams = _StateParameters(
2481
- {0: "a", 1: "b", 2: "c", 3: "d"},
2482
- {"a": 0, "b": 1, "c": 2, "d": 3},
2483
- None,
2484
- None,
2485
- None,
2486
- None,
2487
- None,
2488
- None,
2489
- None,
2490
- None,
2491
- )
2492
-
2493
- u, v = 10, "k"
2494
- assert _cut_PT(u, v, gparams, sparams)
2495
-
2496
- def test_cut_consistent_labels(self):
2497
- G1 = nx.DiGraph(
2498
- [
2499
- (0, 1),
2500
- (2, 1),
2501
- (10, 0),
2502
- (10, 3),
2503
- (10, 4),
2504
- (5, 10),
2505
- (10, 6),
2506
- (1, 4),
2507
- (5, 3),
2508
- ]
2509
- )
2510
- G2 = nx.DiGraph(
2511
- [
2512
- ("a", "b"),
2513
- ("c", "b"),
2514
- ("k", "a"),
2515
- ("k", "d"),
2516
- ("k", "e"),
2517
- ("f", "k"),
2518
- ("k", "g"),
2519
- ("b", "e"),
2520
- ("f", "d"),
2521
- ]
2522
- )
2523
-
2524
- l1 = {n: "blue" for n in G1.nodes()}
2525
- l2 = {n: "blue" for n in G2.nodes()}
2526
-
2527
- gparams = _GraphParameters(
2528
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2529
- )
2530
- sparams = _StateParameters(
2531
- {0: "a", 1: "b", 2: "c", 3: "d"},
2532
- {"a": 0, "b": 1, "c": 2, "d": 3},
2533
- {4},
2534
- {5, 10},
2535
- {6},
2536
- None,
2537
- {"e"},
2538
- {"f", "k"},
2539
- {"g"},
2540
- None,
2541
- )
2542
-
2543
- u, v = 10, "k"
2544
- assert not _cut_PT(u, v, gparams, sparams)
2545
-
2546
- def test_cut_same_labels(self):
2547
- G1 = nx.DiGraph(
2548
- [
2549
- (0, 1),
2550
- (2, 1),
2551
- (10, 0),
2552
- (10, 3),
2553
- (10, 4),
2554
- (5, 10),
2555
- (10, 6),
2556
- (1, 4),
2557
- (5, 3),
2558
- ]
2559
- )
2560
- mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 10: "k"}
2561
- G2 = nx.relabel_nodes(G1, mapped)
2562
- l1 = {n: "blue" for n in G1.nodes()}
2563
- l2 = {n: "blue" for n in G2.nodes()}
2564
-
2565
- gparams = _GraphParameters(
2566
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2567
- )
2568
- sparams = _StateParameters(
2569
- {0: "a", 1: "b", 2: "c", 3: "d"},
2570
- {"a": 0, "b": 1, "c": 2, "d": 3},
2571
- {4},
2572
- {5, 10},
2573
- {6},
2574
- None,
2575
- {"e"},
2576
- {"f", "k"},
2577
- {"g"},
2578
- None,
2579
- )
2580
-
2581
- u, v = 10, "k"
2582
- assert not _cut_PT(u, v, gparams, sparams)
2583
-
2584
- # Change intersection between G1[u] and T1_out, so it's not the same as
2585
- # the one between G2[v] and T2_out
2586
- G1.remove_edge(u, 4)
2587
- assert _cut_PT(u, v, gparams, sparams)
2588
-
2589
- # Compensate in G2
2590
- G2.remove_edge(v, mapped[4])
2591
- assert not _cut_PT(u, v, gparams, sparams)
2592
-
2593
- # Change intersection between G1[u] and T1_in, so it's not the same as
2594
- # the one between G2[v] and T2_in
2595
- G1.remove_edge(5, u)
2596
- assert _cut_PT(u, v, gparams, sparams)
2597
-
2598
- # Compensate in G2
2599
- G2.remove_edge(mapped[5], v)
2600
- assert not _cut_PT(u, v, gparams, sparams)
2601
-
2602
- # Change intersection between G2[v] and T2_tilde, so it's not the same
2603
- # as the one between G1[u] and T1_tilde
2604
- G2.remove_edge(v, mapped[6])
2605
- assert _cut_PT(u, v, gparams, sparams)
2606
-
2607
- # Compensate in G1
2608
- G1.remove_edge(u, 6)
2609
- assert not _cut_PT(u, v, gparams, sparams)
2610
-
2611
- # Add disconnected nodes, which will form the new Ti_tilde
2612
- G1.add_nodes_from([6, 7, 8])
2613
- G2.add_nodes_from(["g", "y", "z"])
2614
- sparams.T1_tilde.update({6, 7, 8})
2615
- sparams.T2_tilde.update({"g", "y", "z"})
2616
-
2617
- l1 = {n: "blue" for n in G1.nodes()}
2618
- l2 = {n: "blue" for n in G2.nodes()}
2619
- gparams = _GraphParameters(
2620
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2621
- )
2622
-
2623
- assert not _cut_PT(u, v, gparams, sparams)
2624
-
2625
- def test_cut_different_labels(self):
2626
- G1 = nx.DiGraph(
2627
- [
2628
- (0, 1),
2629
- (1, 2),
2630
- (14, 1),
2631
- (0, 4),
2632
- (1, 5),
2633
- (2, 6),
2634
- (3, 7),
2635
- (3, 6),
2636
- (10, 4),
2637
- (4, 9),
2638
- (6, 10),
2639
- (20, 9),
2640
- (20, 15),
2641
- (20, 12),
2642
- (20, 11),
2643
- (12, 13),
2644
- (11, 13),
2645
- (20, 8),
2646
- (20, 3),
2647
- (20, 5),
2648
- (0, 20),
2649
- ]
2650
- )
2651
- mapped = {
2652
- 0: "a",
2653
- 1: "b",
2654
- 2: "c",
2655
- 3: "d",
2656
- 4: "e",
2657
- 5: "f",
2658
- 6: "g",
2659
- 7: "h",
2660
- 8: "i",
2661
- 9: "j",
2662
- 10: "k",
2663
- 11: "l",
2664
- 12: "m",
2665
- 13: "n",
2666
- 14: "o",
2667
- 15: "p",
2668
- 20: "x",
2669
- }
2670
- G2 = nx.relabel_nodes(G1, mapped)
2671
-
2672
- l1 = {n: "none" for n in G1.nodes()}
2673
- l2 = {}
2674
-
2675
- l1.update(
2676
- {
2677
- 9: "blue",
2678
- 15: "blue",
2679
- 12: "blue",
2680
- 11: "green",
2681
- 3: "green",
2682
- 8: "red",
2683
- 0: "red",
2684
- 5: "yellow",
2685
- }
2686
- )
2687
- l2.update({mapped[n]: l for n, l in l1.items()})
2688
-
2689
- gparams = _GraphParameters(
2690
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2691
- )
2692
- sparams = _StateParameters(
2693
- {0: "a", 1: "b", 2: "c", 3: "d"},
2694
- {"a": 0, "b": 1, "c": 2, "d": 3},
2695
- {4, 5, 6, 7, 20},
2696
- {14, 20},
2697
- {9, 10, 15, 12, 11, 13, 8},
2698
- None,
2699
- {"e", "f", "g", "x"},
2700
- {"o", "x"},
2701
- {"j", "k", "l", "m", "n", "i", "p"},
2702
- None,
2703
- )
2704
-
2705
- u, v = 20, "x"
2706
- assert not _cut_PT(u, v, gparams, sparams)
2707
-
2708
- # Change the orientation of the labels on neighbors of u compared to
2709
- # neighbors of v. Leave the structure intact
2710
- l1.update({9: "red"})
2711
- assert _cut_PT(u, v, gparams, sparams)
2712
-
2713
- # compensate in G2
2714
- l2.update({mapped[9]: "red"})
2715
- assert not _cut_PT(u, v, gparams, sparams)
2716
-
2717
- # Change the intersection of G1[u] and T1_out
2718
- G1.add_edge(u, 4)
2719
- assert _cut_PT(u, v, gparams, sparams)
2720
-
2721
- # Same for G2[v] and T2_out
2722
- G2.add_edge(v, mapped[4])
2723
- assert not _cut_PT(u, v, gparams, sparams)
2724
-
2725
- # Change the intersection of G1[u] and T1_in
2726
- G1.add_edge(u, 14)
2727
- assert _cut_PT(u, v, gparams, sparams)
2728
-
2729
- # Same for G2[v] and T2_in
2730
- G2.add_edge(v, mapped[14])
2731
- assert not _cut_PT(u, v, gparams, sparams)
2732
-
2733
- # Change the intersection of G2[v] and T2_tilde
2734
- G2.remove_edge(v, mapped[8])
2735
- assert _cut_PT(u, v, gparams, sparams)
2736
-
2737
- # Same for G1[u] and T1_tilde
2738
- G1.remove_edge(u, 8)
2739
- assert not _cut_PT(u, v, gparams, sparams)
2740
-
2741
- # Place 8 and mapped[8] in T1 and T2 respectively, by connecting it to covered nodes
2742
- G1.add_edge(8, 3)
2743
- G2.add_edge(mapped[8], mapped[3])
2744
- sparams.T1.add(8)
2745
- sparams.T2.add(mapped[8])
2746
- sparams.T1_tilde.remove(8)
2747
- sparams.T2_tilde.remove(mapped[8])
2748
-
2749
- assert not _cut_PT(u, v, gparams, sparams)
2750
-
2751
- # Remove neighbor of u from T1
2752
- G1.remove_node(5)
2753
- l1.pop(5)
2754
- sparams.T1.remove(5)
2755
- assert _cut_PT(u, v, gparams, sparams)
2756
-
2757
- # Same in G2
2758
- G2.remove_node(mapped[5])
2759
- l2.pop(mapped[5])
2760
- sparams.T2.remove(mapped[5])
2761
- assert not _cut_PT(u, v, gparams, sparams)
2762
-
2763
- def test_predecessor_T1_in_fail(self):
2764
- G1 = nx.DiGraph(
2765
- [(0, 1), (0, 3), (4, 0), (1, 5), (5, 2), (3, 6), (4, 6), (6, 5)]
2766
- )
2767
- mapped = {0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g"}
2768
- G2 = nx.relabel_nodes(G1, mapped)
2769
- l1 = {n: "blue" for n in G1.nodes()}
2770
- l2 = {n: "blue" for n in G2.nodes()}
2771
-
2772
- gparams = _GraphParameters(
2773
- G1, G2, l1, l2, nx.utils.groups(l1), nx.utils.groups(l2), None
2774
- )
2775
- sparams = _StateParameters(
2776
- {0: "a", 1: "b", 2: "c"},
2777
- {"a": 0, "b": 1, "c": 2},
2778
- {3, 5},
2779
- {4, 5},
2780
- {6},
2781
- None,
2782
- {"d", "f"},
2783
- {"f"}, # mapped[4] is missing from T2_in
2784
- {"g"},
2785
- None,
2786
- )
2787
-
2788
- u, v = 6, "g"
2789
- assert _cut_PT(u, v, gparams, sparams)
2790
-
2791
- sparams.T2_in.add("e")
2792
- assert not _cut_PT(u, v, gparams, sparams)
2793
-
2794
-
2795
- class TestGraphTinoutUpdating:
2796
- edges = [
2797
- (1, 3),
2798
- (2, 3),
2799
- (3, 4),
2800
- (4, 9),
2801
- (4, 5),
2802
- (3, 9),
2803
- (5, 8),
2804
- (5, 7),
2805
- (8, 7),
2806
- (6, 7),
2807
- ]
2808
- mapped = {
2809
- 0: "x",
2810
- 1: "a",
2811
- 2: "b",
2812
- 3: "c",
2813
- 4: "d",
2814
- 5: "e",
2815
- 6: "f",
2816
- 7: "g",
2817
- 8: "h",
2818
- 9: "i",
2819
- }
2820
- G1 = nx.Graph()
2821
- G1.add_edges_from(edges)
2822
- G1.add_node(0)
2823
- G2 = nx.relabel_nodes(G1, mapping=mapped)
2824
-
2825
- def test_updating(self):
2826
- G2_degree = dict(self.G2.degree)
2827
- gparams, sparams = _initialize_parameters(self.G1, self.G2, G2_degree)
2828
- m, m_rev, T1, _, T1_tilde, _, T2, _, T2_tilde, _ = sparams
2829
-
2830
- # Add node to the mapping
2831
- m[4] = self.mapped[4]
2832
- m_rev[self.mapped[4]] = 4
2833
- _update_Tinout(4, self.mapped[4], gparams, sparams)
2834
-
2835
- assert T1 == {3, 5, 9}
2836
- assert T2 == {"c", "i", "e"}
2837
- assert T1_tilde == {0, 1, 2, 6, 7, 8}
2838
- assert T2_tilde == {"x", "a", "b", "f", "g", "h"}
2839
-
2840
- # Add node to the mapping
2841
- m[5] = self.mapped[5]
2842
- m_rev.update({self.mapped[5]: 5})
2843
- _update_Tinout(5, self.mapped[5], gparams, sparams)
2844
-
2845
- assert T1 == {3, 9, 8, 7}
2846
- assert T2 == {"c", "i", "h", "g"}
2847
- assert T1_tilde == {0, 1, 2, 6}
2848
- assert T2_tilde == {"x", "a", "b", "f"}
2849
-
2850
- # Add node to the mapping
2851
- m[6] = self.mapped[6]
2852
- m_rev.update({self.mapped[6]: 6})
2853
- _update_Tinout(6, self.mapped[6], gparams, sparams)
2854
-
2855
- assert T1 == {3, 9, 8, 7}
2856
- assert T2 == {"c", "i", "h", "g"}
2857
- assert T1_tilde == {0, 1, 2}
2858
- assert T2_tilde == {"x", "a", "b"}
2859
-
2860
- # Add node to the mapping
2861
- m[3] = self.mapped[3]
2862
- m_rev.update({self.mapped[3]: 3})
2863
- _update_Tinout(3, self.mapped[3], gparams, sparams)
2864
-
2865
- assert T1 == {1, 2, 9, 8, 7}
2866
- assert T2 == {"a", "b", "i", "h", "g"}
2867
- assert T1_tilde == {0}
2868
- assert T2_tilde == {"x"}
2869
-
2870
- # Add node to the mapping
2871
- m[0] = self.mapped[0]
2872
- m_rev.update({self.mapped[0]: 0})
2873
- _update_Tinout(0, self.mapped[0], gparams, sparams)
2874
-
2875
- assert T1 == {1, 2, 9, 8, 7}
2876
- assert T2 == {"a", "b", "i", "h", "g"}
2877
- assert T1_tilde == set()
2878
- assert T2_tilde == set()
2879
-
2880
- def test_restoring(self):
2881
- m = {0: "x", 3: "c", 4: "d", 5: "e", 6: "f"}
2882
- m_rev = {"x": 0, "c": 3, "d": 4, "e": 5, "f": 6}
2883
-
2884
- T1 = {1, 2, 7, 9, 8}
2885
- T2 = {"a", "b", "g", "i", "h"}
2886
- T1_tilde = set()
2887
- T2_tilde = set()
2888
-
2889
- gparams = _GraphParameters(self.G1, self.G2, {}, {}, {}, {}, {})
2890
- sparams = _StateParameters(
2891
- m, m_rev, T1, None, T1_tilde, None, T2, None, T2_tilde, None
2892
- )
2893
-
2894
- # Remove a node from the mapping
2895
- m.pop(0)
2896
- m_rev.pop("x")
2897
- _restore_Tinout(0, self.mapped[0], gparams, sparams)
2898
-
2899
- assert T1 == {1, 2, 7, 9, 8}
2900
- assert T2 == {"a", "b", "g", "i", "h"}
2901
- assert T1_tilde == {0}
2902
- assert T2_tilde == {"x"}
2903
-
2904
- # Remove a node from the mapping
2905
- m.pop(6)
2906
- m_rev.pop("f")
2907
- _restore_Tinout(6, self.mapped[6], gparams, sparams)
2908
-
2909
- assert T1 == {1, 2, 7, 9, 8}
2910
- assert T2 == {"a", "b", "g", "i", "h"}
2911
- assert T1_tilde == {0, 6}
2912
- assert T2_tilde == {"x", "f"}
2913
-
2914
- # Remove a node from the mapping
2915
- m.pop(3)
2916
- m_rev.pop("c")
2917
- _restore_Tinout(3, self.mapped[3], gparams, sparams)
2918
-
2919
- assert T1 == {7, 9, 8, 3}
2920
- assert T2 == {"g", "i", "h", "c"}
2921
- assert T1_tilde == {0, 6, 1, 2}
2922
- assert T2_tilde == {"x", "f", "a", "b"}
2923
-
2924
- # Remove a node from the mapping
2925
- m.pop(5)
2926
- m_rev.pop("e")
2927
- _restore_Tinout(5, self.mapped[5], gparams, sparams)
2928
-
2929
- assert T1 == {9, 3, 5}
2930
- assert T2 == {"i", "c", "e"}
2931
- assert T1_tilde == {0, 6, 1, 2, 7, 8}
2932
- assert T2_tilde == {"x", "f", "a", "b", "g", "h"}
2933
-
2934
- # Remove a node from the mapping
2935
- m.pop(4)
2936
- m_rev.pop("d")
2937
- _restore_Tinout(4, self.mapped[4], gparams, sparams)
2938
-
2939
- assert T1 == set()
2940
- assert T2 == set()
2941
- assert T1_tilde == set(self.G1.nodes())
2942
- assert T2_tilde == set(self.G2.nodes())
2943
-
2944
-
2945
- class TestDiGraphTinoutUpdating:
2946
- edges = [
2947
- (1, 3),
2948
- (3, 2),
2949
- (3, 4),
2950
- (4, 9),
2951
- (4, 5),
2952
- (3, 9),
2953
- (5, 8),
2954
- (5, 7),
2955
- (8, 7),
2956
- (7, 6),
2957
- ]
2958
- mapped = {
2959
- 0: "x",
2960
- 1: "a",
2961
- 2: "b",
2962
- 3: "c",
2963
- 4: "d",
2964
- 5: "e",
2965
- 6: "f",
2966
- 7: "g",
2967
- 8: "h",
2968
- 9: "i",
2969
- }
2970
- G1 = nx.DiGraph(edges)
2971
- G1.add_node(0)
2972
- G2 = nx.relabel_nodes(G1, mapping=mapped)
2973
-
2974
- def test_updating(self):
2975
- G2_degree = {
2976
- n: (in_degree, out_degree)
2977
- for (n, in_degree), (_, out_degree) in zip(
2978
- self.G2.in_degree, self.G2.out_degree
2979
- )
2980
- }
2981
- gparams, sparams = _initialize_parameters(self.G1, self.G2, G2_degree)
2982
- m, m_rev, T1_out, T1_in, T1_tilde, _, T2_out, T2_in, T2_tilde, _ = sparams
2983
-
2984
- # Add node to the mapping
2985
- m[4] = self.mapped[4]
2986
- m_rev[self.mapped[4]] = 4
2987
- _update_Tinout(4, self.mapped[4], gparams, sparams)
2988
-
2989
- assert T1_out == {5, 9}
2990
- assert T1_in == {3}
2991
- assert T2_out == {"i", "e"}
2992
- assert T2_in == {"c"}
2993
- assert T1_tilde == {0, 1, 2, 6, 7, 8}
2994
- assert T2_tilde == {"x", "a", "b", "f", "g", "h"}
2995
-
2996
- # Add node to the mapping
2997
- m[5] = self.mapped[5]
2998
- m_rev[self.mapped[5]] = 5
2999
- _update_Tinout(5, self.mapped[5], gparams, sparams)
3000
-
3001
- assert T1_out == {9, 8, 7}
3002
- assert T1_in == {3}
3003
- assert T2_out == {"i", "g", "h"}
3004
- assert T2_in == {"c"}
3005
- assert T1_tilde == {0, 1, 2, 6}
3006
- assert T2_tilde == {"x", "a", "b", "f"}
3007
-
3008
- # Add node to the mapping
3009
- m[6] = self.mapped[6]
3010
- m_rev[self.mapped[6]] = 6
3011
- _update_Tinout(6, self.mapped[6], gparams, sparams)
3012
-
3013
- assert T1_out == {9, 8, 7}
3014
- assert T1_in == {3, 7}
3015
- assert T2_out == {"i", "g", "h"}
3016
- assert T2_in == {"c", "g"}
3017
- assert T1_tilde == {0, 1, 2}
3018
- assert T2_tilde == {"x", "a", "b"}
3019
-
3020
- # Add node to the mapping
3021
- m[3] = self.mapped[3]
3022
- m_rev[self.mapped[3]] = 3
3023
- _update_Tinout(3, self.mapped[3], gparams, sparams)
3024
-
3025
- assert T1_out == {9, 8, 7, 2}
3026
- assert T1_in == {7, 1}
3027
- assert T2_out == {"i", "g", "h", "b"}
3028
- assert T2_in == {"g", "a"}
3029
- assert T1_tilde == {0}
3030
- assert T2_tilde == {"x"}
3031
-
3032
- # Add node to the mapping
3033
- m[0] = self.mapped[0]
3034
- m_rev[self.mapped[0]] = 0
3035
- _update_Tinout(0, self.mapped[0], gparams, sparams)
3036
-
3037
- assert T1_out == {9, 8, 7, 2}
3038
- assert T1_in == {7, 1}
3039
- assert T2_out == {"i", "g", "h", "b"}
3040
- assert T2_in == {"g", "a"}
3041
- assert T1_tilde == set()
3042
- assert T2_tilde == set()
3043
-
3044
- def test_restoring(self):
3045
- m = {0: "x", 3: "c", 4: "d", 5: "e", 6: "f"}
3046
- m_rev = {"x": 0, "c": 3, "d": 4, "e": 5, "f": 6}
3047
-
3048
- T1_out = {2, 7, 9, 8}
3049
- T1_in = {1, 7}
3050
- T2_out = {"b", "g", "i", "h"}
3051
- T2_in = {"a", "g"}
3052
- T1_tilde = set()
3053
- T2_tilde = set()
3054
-
3055
- gparams = _GraphParameters(self.G1, self.G2, {}, {}, {}, {}, {})
3056
- sparams = _StateParameters(
3057
- m, m_rev, T1_out, T1_in, T1_tilde, None, T2_out, T2_in, T2_tilde, None
3058
- )
3059
-
3060
- # Remove a node from the mapping
3061
- m.pop(0)
3062
- m_rev.pop("x")
3063
- _restore_Tinout_Di(0, self.mapped[0], gparams, sparams)
3064
-
3065
- assert T1_out == {2, 7, 9, 8}
3066
- assert T1_in == {1, 7}
3067
- assert T2_out == {"b", "g", "i", "h"}
3068
- assert T2_in == {"a", "g"}
3069
- assert T1_tilde == {0}
3070
- assert T2_tilde == {"x"}
3071
-
3072
- # Remove a node from the mapping
3073
- m.pop(6)
3074
- m_rev.pop("f")
3075
- _restore_Tinout_Di(6, self.mapped[6], gparams, sparams)
3076
-
3077
- assert T1_out == {2, 9, 8, 7}
3078
- assert T1_in == {1}
3079
- assert T2_out == {"b", "i", "h", "g"}
3080
- assert T2_in == {"a"}
3081
- assert T1_tilde == {0, 6}
3082
- assert T2_tilde == {"x", "f"}
3083
-
3084
- # Remove a node from the mapping
3085
- m.pop(3)
3086
- m_rev.pop("c")
3087
- _restore_Tinout_Di(3, self.mapped[3], gparams, sparams)
3088
-
3089
- assert T1_out == {9, 8, 7}
3090
- assert T1_in == {3}
3091
- assert T2_out == {"i", "h", "g"}
3092
- assert T2_in == {"c"}
3093
- assert T1_tilde == {0, 6, 1, 2}
3094
- assert T2_tilde == {"x", "f", "a", "b"}
3095
-
3096
- # Remove a node from the mapping
3097
- m.pop(5)
3098
- m_rev.pop("e")
3099
- _restore_Tinout_Di(5, self.mapped[5], gparams, sparams)
3100
-
3101
- assert T1_out == {9, 5}
3102
- assert T1_in == {3}
3103
- assert T2_out == {"i", "e"}
3104
- assert T2_in == {"c"}
3105
- assert T1_tilde == {0, 6, 1, 2, 8, 7}
3106
- assert T2_tilde == {"x", "f", "a", "b", "h", "g"}
3107
-
3108
- # Remove a node from the mapping
3109
- m.pop(4)
3110
- m_rev.pop("d")
3111
- _restore_Tinout_Di(4, self.mapped[4], gparams, sparams)
3112
-
3113
- assert T1_out == set()
3114
- assert T1_in == set()
3115
- assert T2_out == set()
3116
- assert T2_in == set()
3117
- assert T1_tilde == set(self.G1.nodes())
3118
- assert T2_tilde == set(self.G2.nodes())