synkit 1.6.5__py3-none-win_amd64.whl

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 (636) hide show
  1. synkit/CRN/Benchmark/__init__.py +53 -0
  2. synkit/CRN/Benchmark/crosschecks.py +13 -0
  3. synkit/CRN/Benchmark/kegg.py +12 -0
  4. synkit/CRN/Benchmark/networks.py +13 -0
  5. synkit/CRN/Benchmark/scaling.py +13 -0
  6. synkit/CRN/Benchmark/validate.py +13 -0
  7. synkit/CRN/Construct/__init__.py +16 -0
  8. synkit/CRN/Construct/abstract.py +668 -0
  9. synkit/CRN/Construct/arity.py +36 -0
  10. synkit/CRN/Construct/builder.py +619 -0
  11. synkit/CRN/Construct/derivation.py +63 -0
  12. synkit/CRN/Construct/flattener.py +100 -0
  13. synkit/CRN/Construct/keys.py +14 -0
  14. synkit/CRN/Construct/mixtures.py +117 -0
  15. synkit/CRN/Construct/rdkit_worker.py +69 -0
  16. synkit/CRN/Construct/smiles.py +99 -0
  17. synkit/CRN/Construct/state.py +31 -0
  18. synkit/CRN/Construct/strategy.py +75 -0
  19. synkit/CRN/Construct/worker.py +42 -0
  20. synkit/CRN/IO/__init__.py +36 -0
  21. synkit/CRN/IO/sbml.py +925 -0
  22. synkit/CRN/Pathway/__init__.py +72 -0
  23. synkit/CRN/Pathway/_adapter.py +333 -0
  24. synkit/CRN/Pathway/pathfinder.py +500 -0
  25. synkit/CRN/Pathway/reachability.py +796 -0
  26. synkit/CRN/Pathway/realizability.py +1322 -0
  27. synkit/CRN/Petrinet/__init__.py +93 -0
  28. synkit/CRN/Petrinet/analyzer.py +486 -0
  29. synkit/CRN/Petrinet/minimal_semiflows.py +436 -0
  30. synkit/CRN/Petrinet/net.py +1041 -0
  31. synkit/CRN/Petrinet/persistence.py +97 -0
  32. synkit/CRN/Petrinet/semiflows.py +483 -0
  33. synkit/CRN/Petrinet/siphon_search.py +402 -0
  34. synkit/CRN/Petrinet/structure.py +286 -0
  35. synkit/CRN/Props/__init__.py +130 -0
  36. synkit/CRN/Props/_rank.py +29 -0
  37. synkit/CRN/Props/deficiency.py +953 -0
  38. synkit/CRN/Props/dynamics.py +832 -0
  39. synkit/CRN/Props/helper.py +151 -0
  40. synkit/CRN/Props/stoich.py +751 -0
  41. synkit/CRN/Props/thermo.py +584 -0
  42. synkit/CRN/Query/__init__.py +66 -0
  43. synkit/CRN/Query/cache.py +41 -0
  44. synkit/CRN/Query/kegg_api.py +99 -0
  45. synkit/CRN/Query/kegg_extract.py +714 -0
  46. synkit/CRN/Query/kegg_impute.py +707 -0
  47. synkit/CRN/Query/kegg_parse.py +480 -0
  48. synkit/CRN/Query/to_syncrn.py +290 -0
  49. synkit/CRN/README.md +234 -0
  50. synkit/CRN/Structure/__init__.py +12 -0
  51. synkit/CRN/Structure/_graph_io.py +713 -0
  52. synkit/CRN/Structure/_matrices.py +88 -0
  53. synkit/CRN/Structure/_parse.py +544 -0
  54. synkit/CRN/Structure/reaction.py +237 -0
  55. synkit/CRN/Structure/rule.py +55 -0
  56. synkit/CRN/Structure/species.py +46 -0
  57. synkit/CRN/Structure/syncrn.py +929 -0
  58. synkit/CRN/Symmetry/__init__.py +20 -0
  59. synkit/CRN/Symmetry/_common.py +1059 -0
  60. synkit/CRN/Symmetry/_ir.py +940 -0
  61. synkit/CRN/Symmetry/automorphism.py +472 -0
  62. synkit/CRN/Symmetry/canon.py +441 -0
  63. synkit/CRN/Symmetry/isomorphism.py +412 -0
  64. synkit/CRN/Symmetry/symmetry.py +61 -0
  65. synkit/CRN/Symmetry/wl_canon.py +967 -0
  66. synkit/CRN/Visualize/__init__.py +11 -0
  67. synkit/CRN/Visualize/labels.py +113 -0
  68. synkit/CRN/Visualize/layout.py +708 -0
  69. synkit/CRN/Visualize/palette.py +292 -0
  70. synkit/CRN/Visualize/validation.py +122 -0
  71. synkit/CRN/Visualize/vis.py +1152 -0
  72. synkit/CRN/__init__.py +233 -0
  73. synkit/CRN/_build.py +50 -0
  74. synkit/CRN/_native_build.py +175 -0
  75. synkit/CRN/analysis.py +629 -0
  76. synkit/CRN/backend.py +74 -0
  77. synkit/CRN/cpp/CMakeLists.txt +58 -0
  78. synkit/CRN/cpp/algebra.cpp +46 -0
  79. synkit/CRN/cpp/closure.cpp +29 -0
  80. synkit/CRN/cpp/exact.h +55 -0
  81. synkit/CRN/cpp/pathway.cpp +46 -0
  82. synkit/CRN/cpp/semiflows.cpp +209 -0
  83. synkit/CRN/cpp/structural.cpp +240 -0
  84. synkit/CRN/cpp/symmetry.cpp +45 -0
  85. synkit/CRN/cpp/write_manifest.cmake +28 -0
  86. synkit/CRN/kinds.py +137 -0
  87. synkit/CRN/lib/synkit_crn.dll +0 -0
  88. synkit/CRN/lib/synkit_crn.json +33 -0
  89. synkit/CRN/native.py +388 -0
  90. synkit/CRN/native_analysis.py +459 -0
  91. synkit/Chem/Cluster/__init__.py +0 -0
  92. synkit/Chem/Cluster/butina.py +140 -0
  93. synkit/Chem/Fingerprint/__init__.py +0 -0
  94. synkit/Chem/Fingerprint/fp_calculator.py +155 -0
  95. synkit/Chem/Fingerprint/smiles_featurizer.py +258 -0
  96. synkit/Chem/Fingerprint/transformation_fp.py +139 -0
  97. synkit/Chem/Mapper/README.rst +43 -0
  98. synkit/Chem/Mapper/__init__.py +255 -0
  99. synkit/Chem/Mapper/_compat.py +130 -0
  100. synkit/Chem/Mapper/adapters/__init__.py +1 -0
  101. synkit/Chem/Mapper/adapters/prediction.py +126 -0
  102. synkit/Chem/Mapper/adapters/template.py +412 -0
  103. synkit/Chem/Mapper/chem/__init__.py +52 -0
  104. synkit/Chem/Mapper/chem/aam.py +673 -0
  105. synkit/Chem/Mapper/chem/blind.py +160 -0
  106. synkit/Chem/Mapper/chem/its.py +309 -0
  107. synkit/Chem/Mapper/chem/smiles.py +564 -0
  108. synkit/Chem/Mapper/graph/__init__.py +66 -0
  109. synkit/Chem/Mapper/graph/automorphism.py +395 -0
  110. synkit/Chem/Mapper/graph/blockcut.py +98 -0
  111. synkit/Chem/Mapper/graph/labeled_graph.py +104 -0
  112. synkit/Chem/Mapper/graph/refine.py +176 -0
  113. synkit/Chem/Mapper/graph/synkit_adapter.py +110 -0
  114. synkit/Chem/Mapper/io/__init__.py +13 -0
  115. synkit/Chem/Mapper/io/idxmapstr.py +82 -0
  116. synkit/Chem/Mapper/mapper.py +685 -0
  117. synkit/Chem/Mapper/reaction_search.py +554 -0
  118. synkit/Chem/Mapper/reporting/__init__.py +1 -0
  119. synkit/Chem/Mapper/reporting/alternatives.py +451 -0
  120. synkit/Chem/Mapper/reporting/analysis.py +681 -0
  121. synkit/Chem/Mapper/reporting/native_analysis.py +485 -0
  122. synkit/Chem/Mapper/reporting/spectrum.py +642 -0
  123. synkit/Chem/Mapper/solvers/__init__.py +1 -0
  124. synkit/Chem/Mapper/solvers/exact/__init__.py +141 -0
  125. synkit/Chem/Mapper/solvers/exact/assignment/__init__.py +1 -0
  126. synkit/Chem/Mapper/solvers/exact/assignment/assignment_certificate.py +113 -0
  127. synkit/Chem/Mapper/solvers/exact/assignment/assignment_domains.py +162 -0
  128. synkit/Chem/Mapper/solvers/exact/assignment/assignment_verification.py +58 -0
  129. synkit/Chem/Mapper/solvers/exact/assignment/incremental_assignment.py +247 -0
  130. synkit/Chem/Mapper/solvers/exact/certificate.py +128 -0
  131. synkit/Chem/Mapper/solvers/exact/core.py +183 -0
  132. synkit/Chem/Mapper/solvers/exact/distance_search/__init__.py +1 -0
  133. synkit/Chem/Mapper/solvers/exact/distance_search/bounds.py +319 -0
  134. synkit/Chem/Mapper/solvers/exact/distance_search/exhaustive.py +179 -0
  135. synkit/Chem/Mapper/solvers/exact/distance_search/inputs.py +283 -0
  136. synkit/Chem/Mapper/solvers/exact/distance_search/records.py +242 -0
  137. synkit/Chem/Mapper/solvers/exact/distance_search/search.py +1025 -0
  138. synkit/Chem/Mapper/solvers/exact/distance_search/verify.py +378 -0
  139. synkit/Chem/Mapper/solvers/exact/edit_support.py +375 -0
  140. synkit/Chem/Mapper/solvers/exact/hybrid.py +224 -0
  141. synkit/Chem/Mapper/solvers/exact/hydrogen.py +264 -0
  142. synkit/Chem/Mapper/solvers/exact/kernel_solvers/__init__.py +1 -0
  143. synkit/Chem/Mapper/solvers/exact/kernel_solvers/branching.py +499 -0
  144. synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumerate.py +1050 -0
  145. synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumeration_result.py +30 -0
  146. synkit/Chem/Mapper/solvers/exact/kernel_solvers/kernel.py +256 -0
  147. synkit/Chem/Mapper/solvers/exact/kernel_solvers/milp.py +194 -0
  148. synkit/Chem/Mapper/solvers/exact/native/__init__.py +1 -0
  149. synkit/Chem/Mapper/solvers/exact/native/build.py +154 -0
  150. synkit/Chem/Mapper/solvers/exact/native/candidates.py +593 -0
  151. synkit/Chem/Mapper/solvers/exact/native/canonical.py +396 -0
  152. synkit/Chem/Mapper/solvers/exact/native/disk_frontier.py +415 -0
  153. synkit/Chem/Mapper/solvers/exact/native/frontier.py +390 -0
  154. synkit/Chem/Mapper/solvers/exact/native/hydrogen_quotient.py +213 -0
  155. synkit/Chem/Mapper/solvers/exact/native/its.py +528 -0
  156. synkit/Chem/Mapper/solvers/exact/native/native_distance.cpp +2803 -0
  157. synkit/Chem/Mapper/solvers/exact/native/orbit_aggregation.py +328 -0
  158. synkit/Chem/Mapper/solvers/exact/native/parallel.py +205 -0
  159. synkit/Chem/Mapper/solvers/exact/native/pmcd.py +203 -0
  160. synkit/Chem/Mapper/solvers/exact/native/runtime.py +40 -0
  161. synkit/Chem/Mapper/solvers/exact/native/search.py +294 -0
  162. synkit/Chem/Mapper/solvers/exact/native/separator.py +224 -0
  163. synkit/Chem/Mapper/solvers/exact/native_build.py +12 -0
  164. synkit/Chem/Mapper/solvers/exact/pabs/__init__.py +1 -0
  165. synkit/Chem/Mapper/solvers/exact/pabs/cost_lattice.py +43 -0
  166. synkit/Chem/Mapper/solvers/exact/pabs/factor_spectrum.py +110 -0
  167. synkit/Chem/Mapper/solvers/exact/pabs/multi_shell.py +368 -0
  168. synkit/Chem/Mapper/solvers/exact/pabs/propagation.py +679 -0
  169. synkit/Chem/Mapper/solvers/exact/pabs/propagation_bounds.py +436 -0
  170. synkit/Chem/Mapper/solvers/exact/pabs/propagation_limits.py +13 -0
  171. synkit/Chem/Mapper/solvers/exact/pabs/propagation_search.py +856 -0
  172. synkit/Chem/Mapper/solvers/exact/pabs/propagation_symmetry.py +66 -0
  173. synkit/Chem/Mapper/solvers/exact/pabs/residual_typed_bonds.py +136 -0
  174. synkit/Chem/Mapper/solvers/exact/pabs/reward_frontier.py +201 -0
  175. synkit/Chem/Mapper/solvers/exact/pabs/separator_bound.py +258 -0
  176. synkit/Chem/Mapper/solvers/exact/pabs/separator_spectrum.py +308 -0
  177. synkit/Chem/Mapper/solvers/exact/pabs/sparse_reward_bound.py +207 -0
  178. synkit/Chem/Mapper/solvers/exact/pabs/suffix_spectrum.py +299 -0
  179. synkit/Chem/Mapper/solvers/exact/search.py +55 -0
  180. synkit/Chem/Mapper/solvers/exact/seeds/__init__.py +1 -0
  181. synkit/Chem/Mapper/solvers/exact/seeds/seed.py +104 -0
  182. synkit/Chem/Mapper/solvers/exact/seeds/seed_fragments.py +148 -0
  183. synkit/Chem/Mapper/solvers/exact/seeds/seed_relaxation.py +181 -0
  184. synkit/Chem/Mapper/solvers/exact/symmetry.py +223 -0
  185. synkit/Chem/Mapper/solvers/native/__init__.py +4 -0
  186. synkit/Chem/Mapper/solvers/native/assignment.py +99 -0
  187. synkit/Chem/Mapper/solvers/native/astar.py +22 -0
  188. synkit/Chem/Mapper/solvers/native/build.py +385 -0
  189. synkit/Chem/Mapper/solvers/native/classification.py +641 -0
  190. synkit/Chem/Mapper/solvers/native/core.py +378 -0
  191. synkit/Chem/Mapper/solvers/native/cpp/CMakeLists.txt +120 -0
  192. synkit/Chem/Mapper/solvers/native/cpp/examples/map_reaction.cpp +29 -0
  193. synkit/Chem/Mapper/solvers/native/cpp/examples/slap_graph.cpp +63 -0
  194. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/assignment/assignment.h +18 -0
  195. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/astar.h +18 -0
  196. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/bound.h +33 -0
  197. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/pmcd_witness.h +16 -0
  198. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/runtime.h +130 -0
  199. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/hydrogen/hydrogen.h +73 -0
  200. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mapper.h +175 -0
  201. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mces/mces.h +9 -0
  202. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/pabs/seed.h +34 -0
  203. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/reaction/reaction.h +30 -0
  204. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/sepdp/sepdp.h +21 -0
  205. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/slap.h +72 -0
  206. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/solvers/solvers.h +16 -0
  207. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/classification.h +140 -0
  208. synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/cpabs.h +33 -0
  209. synkit/Chem/Mapper/solvers/native/cpp/src/assignment/abb.cpp +302 -0
  210. synkit/Chem/Mapper/solvers/native/cpp/src/astar/CMakeLists.txt +12 -0
  211. synkit/Chem/Mapper/solvers/native/cpp/src/astar/README.md +47 -0
  212. synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar.cpp +228 -0
  213. synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar_graph.cpp +37 -0
  214. synkit/Chem/Mapper/solvers/native/cpp/src/astar/bound.cpp +212 -0
  215. synkit/Chem/Mapper/solvers/native/cpp/src/core/dispatch.cpp +272 -0
  216. synkit/Chem/Mapper/solvers/native/cpp/src/core/pmcd_witness.cpp +36 -0
  217. synkit/Chem/Mapper/solvers/native/cpp/src/hydrogen/hydrogen.cpp +380 -0
  218. synkit/Chem/Mapper/solvers/native/cpp/src/mces/README.md +57 -0
  219. synkit/Chem/Mapper/solvers/native/cpp/src/mces/mces.cpp +287 -0
  220. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/bridge.cpp +334 -0
  221. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/chemical_floor.inc +181 -0
  222. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/endpoint_symmetry.inc +104 -0
  223. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/exact_helpers.h +20 -0
  224. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_assignment_certificate.h +165 -0
  225. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_certificate.h +125 -0
  226. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_model.h +365 -0
  227. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_provider.inc +319 -0
  228. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_rounding.inc +170 -0
  229. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_test_hooks.h +342 -0
  230. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/objective_reduction.inc +137 -0
  231. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/overlap_dual.inc +351 -0
  232. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/profile_seed.inc +214 -0
  233. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/seed_heuristics.inc +640 -0
  234. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_embedding.cpp +430 -0
  235. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_root_lp.h +176 -0
  236. synkit/Chem/Mapper/solvers/native/cpp/src/pabs/test_hooks.inc +262 -0
  237. synkit/Chem/Mapper/solvers/native/cpp/src/reaction/reaction.cpp +611 -0
  238. synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/README.md +61 -0
  239. synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/sepdp.cpp +253 -0
  240. synkit/Chem/Mapper/solvers/native/cpp/src/slap.cpp +810 -0
  241. synkit/Chem/Mapper/solvers/native/cpp/src/solvers/formulation.h +138 -0
  242. synkit/Chem/Mapper/solvers/native/cpp/src/solvers/maxsat.cpp +526 -0
  243. synkit/Chem/Mapper/solvers/native/cpp/src/solvers/ortools.cpp +475 -0
  244. synkit/Chem/Mapper/solvers/native/cpp/src/solvers/seed.h +80 -0
  245. synkit/Chem/Mapper/solvers/native/cpp/src/solvers/weighted_cnf.h +256 -0
  246. synkit/Chem/Mapper/solvers/native/cpp/src/supporting/README.md +43 -0
  247. synkit/Chem/Mapper/solvers/native/cpp/src/supporting/dfs.cpp +123 -0
  248. synkit/Chem/Mapper/solvers/native/cpp/src/supporting/edit_support.cpp +224 -0
  249. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification.cpp +553 -0
  250. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_pipeline.cpp +124 -0
  251. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_stream.h +13 -0
  252. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/cpabs.cpp +455 -0
  253. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/edge_deck.cpp +743 -0
  254. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
  255. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
  256. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naugraph.c +732 -0
  257. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.c +94 -0
  258. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.h +49 -0
  259. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.c +1771 -0
  260. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.h +133 -0
  261. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nautil.c +750 -0
  262. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naututil.h +355 -0
  263. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.c +1256 -0
  264. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.h +1544 -0
  265. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.c +1131 -0
  266. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.h +70 -0
  267. synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/sorttemplates.c +580 -0
  268. synkit/Chem/Mapper/solvers/native/hydrogen.py +711 -0
  269. synkit/Chem/Mapper/solvers/native/implicit.py +506 -0
  270. synkit/Chem/Mapper/solvers/native/implicit_certificate.py +187 -0
  271. synkit/Chem/Mapper/solvers/native/implicit_preparation.py +309 -0
  272. synkit/Chem/Mapper/solvers/native/lib/synkit_mapper.dll +0 -0
  273. synkit/Chem/Mapper/solvers/native/mces.py +16 -0
  274. synkit/Chem/Mapper/solvers/native/reaction.py +179 -0
  275. synkit/Chem/Mapper/solvers/native/reaction_build.py +277 -0
  276. synkit/Chem/Mapper/solvers/native/reaction_text.py +26 -0
  277. synkit/Chem/Mapper/solvers/native/runtime.py +242 -0
  278. synkit/Chem/Mapper/solvers/native/sepdp.py +47 -0
  279. synkit/Chem/Mapper/solvers/native/slap.py +266 -0
  280. synkit/Chem/Mapper/solvers/native/solvers.py +67 -0
  281. synkit/Chem/Mapper/solvers/native/stereo.py +86 -0
  282. synkit/Chem/Mapper/solvers/native/supporting.py +34 -0
  283. synkit/Chem/Mapper/solvers/native/symmetry.py +91 -0
  284. synkit/Chem/Mapper/solvers/slap/__init__.py +29 -0
  285. synkit/Chem/Mapper/solvers/slap/lap.py +174 -0
  286. synkit/Chem/Mapper/solvers/slap/sequential.py +696 -0
  287. synkit/Chem/Mapper/validation/__init__.py +1 -0
  288. synkit/Chem/Mapper/validation/aam_validator.py +442 -0
  289. synkit/Chem/Mapper/validation/annotations.py +274 -0
  290. synkit/Chem/Mapper/validation/bonds.py +124 -0
  291. synkit/Chem/Mapper/validation/cohorts.py +72 -0
  292. synkit/Chem/Mapper/validation/identifiability.py +150 -0
  293. synkit/Chem/Mapper/validation/numerical_scope.py +36 -0
  294. synkit/Chem/Mapper/validation/orbits.py +137 -0
  295. synkit/Chem/Molecule/__init__.py +0 -0
  296. synkit/Chem/Molecule/_chirality_loci.py +165 -0
  297. synkit/Chem/Molecule/_chirality_types.py +231 -0
  298. synkit/Chem/Molecule/_helical_loci.py +167 -0
  299. synkit/Chem/Molecule/_stereo_axis_evidence.py +202 -0
  300. synkit/Chem/Molecule/_stereo_element_detection.py +193 -0
  301. synkit/Chem/Molecule/_stereo_orientation_constraints.py +511 -0
  302. synkit/Chem/Molecule/_tetrahedral_carriers.py +63 -0
  303. synkit/Chem/Molecule/atom_features.py +379 -0
  304. synkit/Chem/Molecule/chirality.py +1041 -0
  305. synkit/Chem/Molecule/cip_assignment.py +569 -0
  306. synkit/Chem/Molecule/cip_ranking.py +843 -0
  307. synkit/Chem/Molecule/coordinate_stereo.py +503 -0
  308. synkit/Chem/Molecule/derived_stereo_naming.py +165 -0
  309. synkit/Chem/Molecule/descriptors.py +452 -0
  310. synkit/Chem/Molecule/formula.py +249 -0
  311. synkit/Chem/Molecule/global_stereo.py +175 -0
  312. synkit/Chem/Molecule/graph_annotator.py +300 -0
  313. synkit/Chem/Molecule/standardize.py +817 -0
  314. synkit/Chem/Molecule/stereo_evidence.py +179 -0
  315. synkit/Chem/Molecule/stereo_perception.py +1032 -0
  316. synkit/Chem/Molecule/valence.py +123 -0
  317. synkit/Chem/Reaction/Mapper/__init__.py +44 -0
  318. synkit/Chem/Reaction/__init__.py +20 -0
  319. synkit/Chem/Reaction/aam_validator.py +5 -0
  320. synkit/Chem/Reaction/balance_check.py +138 -0
  321. synkit/Chem/Reaction/canon_rsmi.py +249 -0
  322. synkit/Chem/Reaction/cleaning.py +58 -0
  323. synkit/Chem/Reaction/deionize.py +199 -0
  324. synkit/Chem/Reaction/explicit_h_audit.py +232 -0
  325. synkit/Chem/Reaction/fix_aam.py +64 -0
  326. synkit/Chem/Reaction/neutralize.py +207 -0
  327. synkit/Chem/Reaction/radical_wildcard.py +224 -0
  328. synkit/Chem/Reaction/standardize.py +203 -0
  329. synkit/Chem/Reaction/tautomerize.py +205 -0
  330. synkit/Chem/__init__.py +1 -0
  331. synkit/Chem/utils.py +315 -0
  332. synkit/Data/__init__.py +0 -0
  333. synkit/Data/aldol.json.gz +1 -0
  334. synkit/Data/gen_partial_aam.py +147 -0
  335. synkit/Data/paracetamol.json.gz +1 -0
  336. synkit/Graph/Canon/__init__.py +16 -0
  337. synkit/Graph/Canon/_native/__init__.py +13 -0
  338. synkit/Graph/Canon/_native/build.py +93 -0
  339. synkit/Graph/Canon/_native/lib/synkit_canon.dll +0 -0
  340. synkit/Graph/Canon/_native/prepare.py +49 -0
  341. synkit/Graph/Canon/_native/runtime.py +140 -0
  342. synkit/Graph/Canon/_native/search.py +137 -0
  343. synkit/Graph/Canon/canon_algs.py +228 -0
  344. synkit/Graph/Canon/canon_graph.py +531 -0
  345. synkit/Graph/Canon/cpp/CMakeLists.txt +42 -0
  346. synkit/Graph/Canon/cpp/README.md +123 -0
  347. synkit/Graph/Canon/cpp/examples/canonical_graph.cpp +16 -0
  348. synkit/Graph/Canon/cpp/include/synkit_canon/canon.h +85 -0
  349. synkit/Graph/Canon/cpp/src/canonical.cpp +391 -0
  350. synkit/Graph/Canon/cpp/src/symmetry.h +83 -0
  351. synkit/Graph/Canon/cpp/tests/symmetry.cpp +93 -0
  352. synkit/Graph/Canon/exact.py +1020 -0
  353. synkit/Graph/Canon/exact_refinement.py +368 -0
  354. synkit/Graph/Canon/nauty.py +143 -0
  355. synkit/Graph/Context/__init__.py +0 -0
  356. synkit/Graph/Context/hier_context.py +244 -0
  357. synkit/Graph/Context/radius_expand.py +252 -0
  358. synkit/Graph/FG/__init__.py +19 -0
  359. synkit/Graph/FG/api.py +39 -0
  360. synkit/Graph/FG/audit.py +155 -0
  361. synkit/Graph/FG/catalog.py +919 -0
  362. synkit/Graph/FG/detector.py +288 -0
  363. synkit/Graph/FG/model.py +97 -0
  364. synkit/Graph/FG/recognizers.py +274 -0
  365. synkit/Graph/FG/ring_system.py +154 -0
  366. synkit/Graph/Feature/Descriptors/topology.py +857 -0
  367. synkit/Graph/Feature/Fingerprint/__init__.py +0 -0
  368. synkit/Graph/Feature/Fingerprint/wl_rxn_fps.py +222 -0
  369. synkit/Graph/Feature/__init__.py +5 -0
  370. synkit/Graph/Feature/graph_descriptors.py +323 -0
  371. synkit/Graph/Feature/graph_fps.py +96 -0
  372. synkit/Graph/Feature/graph_signature.py +239 -0
  373. synkit/Graph/Feature/hash_fps.py +133 -0
  374. synkit/Graph/Feature/morgan_fps.py +88 -0
  375. synkit/Graph/Feature/path_fps.py +81 -0
  376. synkit/Graph/Feature/wl_hash.py +134 -0
  377. synkit/Graph/Fusion/__init__.py +85 -0
  378. synkit/Graph/Fusion/candidate.py +559 -0
  379. synkit/Graph/Fusion/constructor.py +877 -0
  380. synkit/Graph/Fusion/identity.py +184 -0
  381. synkit/Graph/Fusion/interface.py +700 -0
  382. synkit/Graph/Fusion/search.py +241 -0
  383. synkit/Graph/Hyrogen/__init__.py +6 -0
  384. synkit/Graph/Hyrogen/_misc.py +591 -0
  385. synkit/Graph/Hyrogen/hcomplete.py +995 -0
  386. synkit/Graph/Hyrogen/hcomplete_legacy.py +368 -0
  387. synkit/Graph/Hyrogen/hcompletion_algorithms.py +713 -0
  388. synkit/Graph/Hyrogen/hextend.py +570 -0
  389. synkit/Graph/Hyrogen/hextend_legacy.py +215 -0
  390. synkit/Graph/ITS/__init__.py +4 -0
  391. synkit/Graph/ITS/its_builder.py +120 -0
  392. synkit/Graph/ITS/its_construction.py +719 -0
  393. synkit/Graph/ITS/its_decompose.py +572 -0
  394. synkit/Graph/ITS/its_destruction.py +331 -0
  395. synkit/Graph/ITS/its_expand.py +1251 -0
  396. synkit/Graph/ITS/its_relabel.py +187 -0
  397. synkit/Graph/ITS/its_reverter.py +356 -0
  398. synkit/Graph/ITS/normalize_aam.py +145 -0
  399. synkit/Graph/ITS/partial_its.py +238 -0
  400. synkit/Graph/ITS/rc_extractor.py +656 -0
  401. synkit/Graph/ITS/stereo.py +74 -0
  402. synkit/Graph/MTG/__init__.py +107 -0
  403. synkit/Graph/MTG/gluing.py +451 -0
  404. synkit/Graph/MTG/history.py +928 -0
  405. synkit/Graph/MTG/inventory.py +118 -0
  406. synkit/Graph/MTG/local.py +447 -0
  407. synkit/Graph/MTG/mcs_matcher.py +246 -0
  408. synkit/Graph/MTG/mtg.py +611 -0
  409. synkit/Graph/MTG/mtg_explore.py +74 -0
  410. synkit/Graph/MTG/observation.py +209 -0
  411. synkit/Graph/MTG/process.py +577 -0
  412. synkit/Graph/MTG/queries.py +66 -0
  413. synkit/Graph/MTG/realization.py +95 -0
  414. synkit/Graph/MTG/series_parallel.py +107 -0
  415. synkit/Graph/MTG/utils.py +424 -0
  416. synkit/Graph/Matcher/__init__.py +10 -0
  417. synkit/Graph/Matcher/approx_mcs.py +1264 -0
  418. synkit/Graph/Matcher/auto_est.py +736 -0
  419. synkit/Graph/Matcher/automorphism.py +314 -0
  420. synkit/Graph/Matcher/batch_cluster.py +224 -0
  421. synkit/Graph/Matcher/dedup_matches.py +247 -0
  422. synkit/Graph/Matcher/graph_cluster.py +191 -0
  423. synkit/Graph/Matcher/graph_matcher.py +312 -0
  424. synkit/Graph/Matcher/graph_morphism.py +421 -0
  425. synkit/Graph/Matcher/mcs_matcher.py +804 -0
  426. synkit/Graph/Matcher/multi_turbo_iso.py +186 -0
  427. synkit/Graph/Matcher/orbit.py +284 -0
  428. synkit/Graph/Matcher/partial_matcher.py +694 -0
  429. synkit/Graph/Matcher/sing.py +544 -0
  430. synkit/Graph/Matcher/subgraph_matcher.py +812 -0
  431. synkit/Graph/Matcher/turbo_iso.py +272 -0
  432. synkit/Graph/Matcher/wl_sel.py +537 -0
  433. synkit/Graph/Mech/__init__.py +26 -0
  434. synkit/Graph/Mech/conversion.py +1466 -0
  435. synkit/Graph/Mech/conversion_debug.py +237 -0
  436. synkit/Graph/Mech/electron_accounting.py +200 -0
  437. synkit/Graph/Mech/lwg_editor.py +406 -0
  438. synkit/Graph/Mech/lwg_ops.py +313 -0
  439. synkit/Graph/Morphism/__init__.py +99 -0
  440. synkit/Graph/Morphism/constraints.py +460 -0
  441. synkit/Graph/Morphism/llg.py +999 -0
  442. synkit/Graph/Morphism/morphism.py +349 -0
  443. synkit/Graph/Morphism/stereo.py +258 -0
  444. synkit/Graph/Morphism/stereo_morphism.py +383 -0
  445. synkit/Graph/Morphism/stereo_morphism_helpers.py +957 -0
  446. synkit/Graph/Morphism/stereo_morphism_types.py +117 -0
  447. synkit/Graph/Stereo/__init__.py +376 -0
  448. synkit/Graph/Stereo/_descriptor_core.py +207 -0
  449. synkit/Graph/Stereo/_descriptor_serialization.py +138 -0
  450. synkit/Graph/Stereo/canonical.py +648 -0
  451. synkit/Graph/Stereo/changes.py +964 -0
  452. synkit/Graph/Stereo/composition.py +391 -0
  453. synkit/Graph/Stereo/configured.py +946 -0
  454. synkit/Graph/Stereo/couplings.py +245 -0
  455. synkit/Graph/Stereo/descriptors.py +1030 -0
  456. synkit/Graph/Stereo/enumeration.py +597 -0
  457. synkit/Graph/Stereo/extended_descriptors.py +406 -0
  458. synkit/Graph/Stereo/global_configured.py +152 -0
  459. synkit/Graph/Stereo/global_stereo.py +304 -0
  460. synkit/Graph/Stereo/identity.py +648 -0
  461. synkit/Graph/Stereo/interchange.py +496 -0
  462. synkit/Graph/Stereo/legacy.py +460 -0
  463. synkit/Graph/Stereo/matching.py +899 -0
  464. synkit/Graph/Stereo/native.py +154 -0
  465. synkit/Graph/Stereo/orbits.py +668 -0
  466. synkit/Graph/Stereo/outcomes.py +99 -0
  467. synkit/Graph/Stereo/pairwise.py +350 -0
  468. synkit/Graph/Stereo/rdkit_adapter.py +662 -0
  469. synkit/Graph/Stereo/rdkit_identity.py +118 -0
  470. synkit/Graph/Stereo/rdkit_resonance.py +140 -0
  471. synkit/Graph/Stereo/reaction_interchange.py +266 -0
  472. synkit/Graph/Stereo/semantics.py +296 -0
  473. synkit/Graph/Stereo/supports.py +257 -0
  474. synkit/Graph/Stereo/wire.py +339 -0
  475. synkit/Graph/Wildcard/__init__.py +0 -0
  476. synkit/Graph/Wildcard/fuse_graph.py +156 -0
  477. synkit/Graph/Wildcard/graph_wc.py +303 -0
  478. synkit/Graph/Wildcard/its_merge.py +857 -0
  479. synkit/Graph/Wildcard/radwc.py +114 -0
  480. synkit/Graph/Wildcard/wc_matcher.py +576 -0
  481. synkit/Graph/Wildcard/wildcard.py +225 -0
  482. synkit/Graph/__init__.py +17 -0
  483. synkit/Graph/canon_graph.py +14 -0
  484. synkit/Graph/syn_graph.py +199 -0
  485. synkit/Graph/utils.py +324 -0
  486. synkit/IO/__init__.py +4 -0
  487. synkit/IO/chem_converter.py +1059 -0
  488. synkit/IO/combinatorial/__init__.py +8 -0
  489. synkit/IO/combinatorial/gml_to_graph.py +223 -0
  490. synkit/IO/combinatorial/graph_to_gml.py +280 -0
  491. synkit/IO/combinatorial/graph_to_smarts.py +186 -0
  492. synkit/IO/combinatorial/smarts_expander.py +147 -0
  493. synkit/IO/combinatorial/smarts_generalizer.py +133 -0
  494. synkit/IO/combinatorial/smarts_to_graph.py +179 -0
  495. synkit/IO/conversion.py +42 -0
  496. synkit/IO/data_io.py +269 -0
  497. synkit/IO/data_process.py +143 -0
  498. synkit/IO/debug.py +73 -0
  499. synkit/IO/gml_to_nx.py +150 -0
  500. synkit/IO/graph_to_mol.py +199 -0
  501. synkit/IO/mol_to_graph.py +1105 -0
  502. synkit/IO/mol_to_graph_chemistry.py +545 -0
  503. synkit/IO/nx_to_gml.py +209 -0
  504. synkit/IO/smiles_to_id.py +123 -0
  505. synkit/Mechanism/__init__.py +151 -0
  506. synkit/Mechanism/adapters.py +136 -0
  507. synkit/Mechanism/audit.py +323 -0
  508. synkit/Mechanism/benchmark.py +638 -0
  509. synkit/Mechanism/compatibility.py +13 -0
  510. synkit/Mechanism/drawing.py +85 -0
  511. synkit/Mechanism/electron_models.py +725 -0
  512. synkit/Mechanism/equivalence.py +521 -0
  513. synkit/Mechanism/evidence.py +262 -0
  514. synkit/Mechanism/interchange.py +141 -0
  515. synkit/Mechanism/model.py +918 -0
  516. synkit/Mechanism/neighbor_stereo.py +312 -0
  517. synkit/Mechanism/radical_data.py +740 -0
  518. synkit/Mechanism/replay.py +986 -0
  519. synkit/Mechanism/schema.py +264 -0
  520. synkit/Mechanism/stereo_state.py +416 -0
  521. synkit/Mechanism/symbols.py +91 -0
  522. synkit/Rule/Apply/__init__.py +35 -0
  523. synkit/Rule/Apply/conditions.py +45 -0
  524. synkit/Rule/Apply/dpo.py +998 -0
  525. synkit/Rule/Apply/rule_matcher.py +218 -0
  526. synkit/Rule/Apply/validation.py +354 -0
  527. synkit/Rule/Compose/__init__.py +106 -0
  528. synkit/Rule/Compose/_identity.py +43 -0
  529. synkit/Rule/Compose/composition.py +976 -0
  530. synkit/Rule/Compose/laws.py +439 -0
  531. synkit/Rule/Compose/search.py +771 -0
  532. synkit/Rule/Compose/synrule.py +170 -0
  533. synkit/Rule/Modify/__init__.py +0 -0
  534. synkit/Rule/Modify/implict_rule.py +56 -0
  535. synkit/Rule/Modify/longest_path.py +92 -0
  536. synkit/Rule/Modify/molecule_rule.py +115 -0
  537. synkit/Rule/Modify/prune_templates.py +78 -0
  538. synkit/Rule/Modify/rule_utils.py +194 -0
  539. synkit/Rule/Modify/strip_rule.py +97 -0
  540. synkit/Rule/__init__.py +28 -0
  541. synkit/Rule/generic_stereo.py +884 -0
  542. synkit/Rule/stereo_identity.py +271 -0
  543. synkit/Rule/syn_rule.py +1090 -0
  544. synkit/Synthesis/MSR/__init__.py +0 -0
  545. synkit/Synthesis/MSR/path_finder.py +239 -0
  546. synkit/Synthesis/Metrics/__init__.py +0 -0
  547. synkit/Synthesis/Metrics/_base.py +52 -0
  548. synkit/Synthesis/Metrics/_plot.py +129 -0
  549. synkit/Synthesis/Metrics/_ranking.py +179 -0
  550. synkit/Synthesis/RBL/__init__.py +80 -0
  551. synkit/Synthesis/RBL/engine.py +1249 -0
  552. synkit/Synthesis/RBL/matching.py +652 -0
  553. synkit/Synthesis/RBL/overlap.py +336 -0
  554. synkit/Synthesis/RBL/pipeline.py +376 -0
  555. synkit/Synthesis/RBL/policy.py +139 -0
  556. synkit/Synthesis/RBL/proof.py +370 -0
  557. synkit/Synthesis/RBL/reaction.py +506 -0
  558. synkit/Synthesis/RBL/state.py +169 -0
  559. synkit/Synthesis/RBL/validation.py +1060 -0
  560. synkit/Synthesis/Reactor/__init__.py +60 -0
  561. synkit/Synthesis/Reactor/core/__init__.py +1 -0
  562. synkit/Synthesis/Reactor/core/engine.py +967 -0
  563. synkit/Synthesis/Reactor/core/product.py +621 -0
  564. synkit/Synthesis/Reactor/core/rewrite.py +561 -0
  565. synkit/Synthesis/Reactor/core/strategy.py +44 -0
  566. synkit/Synthesis/Reactor/matching/__init__.py +1 -0
  567. synkit/Synthesis/Reactor/matching/mixin.py +920 -0
  568. synkit/Synthesis/Reactor/matching/policy.py +345 -0
  569. synkit/Synthesis/Reactor/matching/symmetry.py +309 -0
  570. synkit/Synthesis/Reactor/output/__init__.py +1 -0
  571. synkit/Synthesis/Reactor/output/deduplication.py +703 -0
  572. synkit/Synthesis/Reactor/output/policy.py +16 -0
  573. synkit/Synthesis/Reactor/output/serialization.py +485 -0
  574. synkit/Synthesis/Reactor/output/structural.py +893 -0
  575. synkit/Synthesis/Reactor/stereo/__init__.py +1 -0
  576. synkit/Synthesis/Reactor/stereo/assignment.py +35 -0
  577. synkit/Synthesis/Reactor/stereo/mixin.py +780 -0
  578. synkit/Synthesis/Reactor/variants/__init__.py +1 -0
  579. synkit/Synthesis/Reactor/variants/imbalanced.py +180 -0
  580. synkit/Synthesis/Reactor/variants/partial.py +84 -0
  581. synkit/Synthesis/Reactor/workflow/__init__.py +1 -0
  582. synkit/Synthesis/Reactor/workflow/batch.py +550 -0
  583. synkit/Synthesis/Reactor/workflow/benchmark.py +143 -0
  584. synkit/Synthesis/Reactor/workflow/postprocess.py +267 -0
  585. synkit/Synthesis/Reactor/workflow/rule_filter.py +210 -0
  586. synkit/Synthesis/__init__.py +0 -0
  587. synkit/Synthesis/reactor_utils.py +316 -0
  588. synkit/Utils/__init__.py +0 -0
  589. synkit/Utils/utils.py +172 -0
  590. synkit/Vis/__init__.py +91 -0
  591. synkit/Vis/crn/__init__.py +40 -0
  592. synkit/Vis/epd/__init__.py +20 -0
  593. synkit/Vis/epd/arrows.py +425 -0
  594. synkit/Vis/epd/chem.py +197 -0
  595. synkit/Vis/epd/constants.py +83 -0
  596. synkit/Vis/epd/layout.py +283 -0
  597. synkit/Vis/epd/mapping.py +51 -0
  598. synkit/Vis/epd/models.py +136 -0
  599. synkit/Vis/epd/render.py +543 -0
  600. synkit/Vis/epd/utils.py +108 -0
  601. synkit/Vis/epd/visualizer.py +811 -0
  602. synkit/Vis/graph_visualizer.py +375 -0
  603. synkit/Vis/its/__init__.py +19 -0
  604. synkit/Vis/its/drawer.py +615 -0
  605. synkit/Vis/its_drawer.py +35 -0
  606. synkit/Vis/molecule/__init__.py +31 -0
  607. synkit/Vis/molecule/drawer.py +563 -0
  608. synkit/Vis/molecule/reaction.py +285 -0
  609. synkit/Vis/molecule_drawer.py +33 -0
  610. synkit/Vis/mtg/__init__.py +17 -0
  611. synkit/Vis/mtg/drawer.py +769 -0
  612. synkit/Vis/mtg_drawer.py +34 -0
  613. synkit/Vis/pdf_writer.py +146 -0
  614. synkit/Vis/reaction/__init__.py +19 -0
  615. synkit/Vis/reaction/rule.py +141 -0
  616. synkit/Vis/reaction/rxn.py +532 -0
  617. synkit/Vis/reaction_drawer.py +41 -0
  618. synkit/Vis/space/__init__.py +17 -0
  619. synkit/Vis/space/chemical.py +80 -0
  620. synkit/Vis/space/embedding.py +87 -0
  621. synkit/Vis/vis_synedu/Vis/__init__.py +7 -0
  622. synkit/Vis/vis_synedu/Vis/dpo.py +862 -0
  623. synkit/Vis/vis_synedu/rxn_vis.py +377 -0
  624. synkit/Vis/vis_synedu/vis.py +501 -0
  625. synkit/Vis/visual_drawer.py +215 -0
  626. synkit/Vis/visual_model.py +520 -0
  627. synkit/__init__.py +3 -0
  628. synkit/_native.py +91 -0
  629. synkit/examples.py +50 -0
  630. synkit/version.py +23 -0
  631. synkit-1.6.5.dist-info/METADATA +156 -0
  632. synkit-1.6.5.dist-info/RECORD +636 -0
  633. synkit-1.6.5.dist-info/WHEEL +4 -0
  634. synkit-1.6.5.dist-info/licenses/LICENSE +21 -0
  635. synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
  636. synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
@@ -0,0 +1,656 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Iterable, Tuple
4
+
5
+ import networkx as nx
6
+
7
+
8
+ class RCExtractor:
9
+ """Extract reaction-center information from an ITS graph.
10
+
11
+ This class identifies the reaction center (RC) from an imaginary transition
12
+ state (ITS) graph using simple structural change rules on paired node and
13
+ edge attributes.
14
+
15
+ A node is considered part of the reaction center when at least one tracked
16
+ paired node attribute differs between the reactant and product states. An
17
+ edge is considered part of the reaction center when its ``standard_order``
18
+ is non-zero.
19
+
20
+ Reaction-center rules
21
+ ---------------------
22
+ Edge is RC if:
23
+
24
+ - ``standard_order != 0``
25
+
26
+ Node is RC if any of these paired attributes differ:
27
+
28
+ - ``element``
29
+ - ``hcount`` (after hydrogen-pair normalization)
30
+ - ``charge``
31
+ - ``lone_pairs`` (or alias ``lp``)
32
+ - ``radical``
33
+ - ``valence_electrons``
34
+
35
+ Default exported attribute sets
36
+ -------------------------------
37
+ By default, the extracted RC metadata also stores filtered node and edge
38
+ attribute snapshots for the following attribute names.
39
+
40
+ Default node attributes:
41
+
42
+ - ``element``
43
+ - ``aromatic``
44
+ - ``hcount``
45
+ - ``charge``
46
+ - ``neighbors``
47
+ - ``hybridization``
48
+ - ``atom_map``
49
+ - ``lone_pairs``
50
+ - ``radical``
51
+ - ``valence_electrons``
52
+ - ``partial_charge``
53
+
54
+ Default edge attributes:
55
+
56
+ - ``kekule_order``
57
+ - ``sigma_order``
58
+ - ``pi_order``
59
+ - ``order``
60
+ - ``bond_type``
61
+ - ``conjugated``
62
+ - ``in_ring``
63
+
64
+ .. rubric:: Notes
65
+
66
+ - All original ITS node and edge attributes are preserved.
67
+ - The extracted RC subgraph stores metadata in ``graph.graph["rc"]``.
68
+ - Endpoints of RC edges are automatically included as RC nodes.
69
+ - Lone-pair attributes may be stored under either ``"lone_pairs"`` or
70
+ ``"lp"``.
71
+ - Hydrogen comparison is handled specially: ``hcount`` is normalized to a
72
+ relative change form before comparison.
73
+ - Filtered attribute snapshots are stored in ``graph.graph["rc"]`` under
74
+ ``"node_attrs"``, ``"edge_attrs"``, ``"default_node_attrs"``, and
75
+ ``"default_edge_attrs"``.
76
+
77
+ .. rubric:: Example
78
+
79
+ .. code-block:: python
80
+
81
+ import networkx as nx
82
+
83
+ its = nx.Graph()
84
+
85
+ its.add_node(
86
+ 1,
87
+ element=("C", "C"),
88
+ hcount=(2, 1),
89
+ charge=(0, 0),
90
+ lone_pairs=(0, 0),
91
+ aromatic=(False, False),
92
+ atom_map=1,
93
+ )
94
+ its.add_node(
95
+ 2,
96
+ element=("O", "O"),
97
+ hcount=(0, 0),
98
+ charge=(0, -1),
99
+ lone_pairs=(2, 3),
100
+ aromatic=(False, False),
101
+ atom_map=2,
102
+ )
103
+
104
+ its.add_edge(
105
+ 1,
106
+ 2,
107
+ order=(1, 1),
108
+ standard_order=1,
109
+ bond_type=("single", "single"),
110
+ conjugated=False,
111
+ in_ring=False,
112
+ )
113
+
114
+ extractor = RCExtractor()
115
+
116
+ rc_graph = extractor.extract(its)
117
+ print(rc_graph.graph["rc"]["default_node_attrs"])
118
+ print(rc_graph.graph["rc"]["node_attrs"])
119
+
120
+ annotated = extractor.annotate(its)
121
+ print(annotated.nodes[1]["rc_reasons"])
122
+ """
123
+
124
+ NODE_KEYS = (
125
+ "element",
126
+ "hcount",
127
+ "charge",
128
+ "lone_pairs",
129
+ "radical",
130
+ "valence_electrons",
131
+ )
132
+ LP_ALIASES = ("lone_pairs", "lp")
133
+
134
+ DEFAULT_NODE_ATTRS = (
135
+ "element",
136
+ "aromatic",
137
+ "hcount",
138
+ "charge",
139
+ "neighbors",
140
+ "hybridization",
141
+ "atom_map",
142
+ "lone_pairs",
143
+ "radical",
144
+ "valence_electrons",
145
+ "partial_charge",
146
+ )
147
+
148
+ DEFAULT_EDGE_ATTRS = (
149
+ "kekule_order",
150
+ "sigma_order",
151
+ "pi_order",
152
+ "order",
153
+ "bond_type",
154
+ "conjugated",
155
+ "in_ring",
156
+ )
157
+
158
+ def __init__(
159
+ self,
160
+ node_attrs: Iterable[str] | None = None,
161
+ edge_attrs: Iterable[str] | None = None,
162
+ preserve_full_attrs: bool = False,
163
+ ) -> None:
164
+ """
165
+ Initialize the reaction-center extractor.
166
+
167
+ :param node_attrs: Attribute names to export for RC nodes in
168
+ ``graph.graph["rc"]["node_attrs"]``. If ``None``, the class
169
+ defaults are used.
170
+ :type node_attrs: Iterable[str] | None
171
+ :param edge_attrs: Attribute names to export for RC edges in
172
+ ``graph.graph["rc"]["edge_attrs"]``. If ``None``, the class
173
+ defaults are used.
174
+ :type edge_attrs: Iterable[str] | None
175
+ :param preserve_full_attrs: If ``True``, export complete node and edge
176
+ attribute dictionaries in the RC metadata snapshots instead of the
177
+ configured attribute subset.
178
+ :type preserve_full_attrs: bool
179
+ """
180
+ self._node_attrs = tuple(node_attrs or self.DEFAULT_NODE_ATTRS)
181
+ self._edge_attrs = tuple(edge_attrs or self.DEFAULT_EDGE_ATTRS)
182
+ self.preserve_full_attrs = preserve_full_attrs
183
+
184
+ def __repr__(self) -> str:
185
+ """
186
+ Return a compact string representation.
187
+
188
+ :return: String representation of the extractor.
189
+ :rtype: str
190
+ """
191
+ return (
192
+ f"{self.__class__.__name__}("
193
+ f"node_attrs={list(self._node_attrs)!r}, "
194
+ f"edge_attrs={list(self._edge_attrs)!r})"
195
+ )
196
+
197
+ @property
198
+ def node_attrs(self) -> tuple[str, ...]:
199
+ """
200
+ Return the configured RC node attributes.
201
+
202
+ :return: Configured node attribute names.
203
+ :rtype: tuple[str, ...]
204
+ """
205
+ return self._node_attrs
206
+
207
+ @property
208
+ def edge_attrs(self) -> tuple[str, ...]:
209
+ """
210
+ Return the configured RC edge attributes.
211
+
212
+ :return: Configured edge attribute names.
213
+ :rtype: tuple[str, ...]
214
+ """
215
+ return self._edge_attrs
216
+
217
+ @staticmethod
218
+ def _edge_key(u: int, v: int) -> tuple[int, int]:
219
+ """
220
+ Normalize an undirected edge key.
221
+
222
+ :param u: First node identifier.
223
+ :type u: int
224
+ :param v: Second node identifier.
225
+ :type v: int
226
+ :return: Sorted undirected edge key.
227
+ :rtype: tuple[int, int]
228
+ """
229
+ return (u, v) if u <= v else (v, u)
230
+
231
+ @staticmethod
232
+ def _is_pair(value: Any) -> bool:
233
+ """
234
+ Check whether a value looks like a 2-item paired attribute.
235
+
236
+ :param value: Value to inspect.
237
+ :type value: Any
238
+ :return: ``True`` if the value is a tuple or list of length 2,
239
+ otherwise ``False``.
240
+ :rtype: bool
241
+ """
242
+ return isinstance(value, (tuple, list)) and len(value) == 2
243
+
244
+ @staticmethod
245
+ def _normalize_h_pair(h_react: int, h_prod: int) -> Tuple[int, int]:
246
+ """Normalize reactant and product hydrogen counts to relative change form.
247
+
248
+ This removes the shared hydrogen baseline and keeps only the relative
249
+ hydrogen change between the two states.
250
+
251
+ .. rubric:: Examples
252
+
253
+ ``(1, 1) -> (0, 0)``
254
+ ``(2, 1) -> (1, 0)``
255
+ ``(1, 2) -> (0, 1)``
256
+
257
+ :param h_react: Hydrogen count in the reactant state.
258
+ :type h_react: int
259
+ :param h_prod: Hydrogen count in the product state.
260
+ :type h_prod: int
261
+ :return: Normalized hydrogen pair.
262
+ :rtype: Tuple[int, int]
263
+
264
+ .. rubric:: Example
265
+
266
+ .. code-block:: python
267
+
268
+ RCExtractor._normalize_h_pair(2, 1) # (1, 0)
269
+ RCExtractor._normalize_h_pair(1, 2) # (0, 1)
270
+ RCExtractor._normalize_h_pair(1, 1) # (0, 0)
271
+ """
272
+ common = min(h_react, h_prod)
273
+ return h_react - common, h_prod - common
274
+
275
+ @classmethod
276
+ def _pair_diff(cls, value: Any) -> bool:
277
+ """
278
+ Check whether a paired value differs between the two states.
279
+
280
+ :param value: Paired attribute value, typically a 2-item tuple or list.
281
+ :type value: Any
282
+ :return: ``True`` if the value is a valid pair and the two entries are
283
+ different, otherwise ``False``.
284
+ :rtype: bool
285
+ """
286
+ return cls._is_pair(value) and value[0] != value[1]
287
+
288
+ @classmethod
289
+ def _hcount_diff(cls, value: Any) -> bool:
290
+ """Check whether a hydrogen-count pair differs after normalization.
291
+
292
+ Hydrogen counts are treated specially. Instead of directly comparing the
293
+ raw pair, the shared hydrogen baseline is removed first by calling
294
+ :meth:`_normalize_h_pair`.
295
+
296
+ :param value: Hydrogen-count pair, usually ``(h_react, h_prod)``.
297
+ :type value: Any
298
+ :return: ``True`` if the normalized hydrogen counts differ, otherwise
299
+ ``False``.
300
+ :rtype: bool
301
+
302
+ .. rubric:: Example
303
+
304
+ .. code-block:: python
305
+
306
+ RCExtractor._hcount_diff((1, 1)) # False
307
+ RCExtractor._hcount_diff((2, 1)) # True
308
+ RCExtractor._hcount_diff((1, 2)) # True
309
+ """
310
+ if not cls._is_pair(value):
311
+ return False
312
+ norm = cls._normalize_h_pair(int(value[0]), int(value[1]))
313
+ return norm[0] != norm[1]
314
+
315
+ @classmethod
316
+ def _get_lp_value(cls, attrs: dict[str, Any]) -> Any:
317
+ """
318
+ Retrieve the lone-pair attribute from supported aliases.
319
+
320
+ :param attrs: Node attribute dictionary.
321
+ :type attrs: dict[str, Any]
322
+ :return: Lone-pair value if present, otherwise ``None``.
323
+ :rtype: Any
324
+ """
325
+ for key in cls.LP_ALIASES:
326
+ if key in attrs:
327
+ return attrs[key]
328
+ return None
329
+
330
+ @classmethod
331
+ def _node_reasons(cls, attrs: dict[str, Any]) -> list[str]:
332
+ """Determine why a node belongs to the reaction center.
333
+
334
+ Each tracked node attribute is inspected, and any attribute whose paired
335
+ values differ is recorded as a reaction-center reason. The ``hcount``
336
+ field is compared using hydrogen normalization.
337
+
338
+ :param attrs: Node attribute dictionary from the ITS graph.
339
+ :type attrs: dict[str, Any]
340
+ :return: List of attribute names that triggered RC membership for the
341
+ node.
342
+ :rtype: list[str]
343
+
344
+ .. rubric:: Example
345
+
346
+ .. code-block:: python
347
+
348
+ attrs = {
349
+ "element": ("N", "N"),
350
+ "hcount": (2, 1),
351
+ "charge": (0, 1),
352
+ "lone_pairs": (1, 1),
353
+ }
354
+
355
+ reasons = RCExtractor._node_reasons(attrs)
356
+ print(reasons) # ['hcount', 'charge']
357
+ """
358
+ reasons: list[str] = []
359
+
360
+ for key in cls.NODE_KEYS:
361
+ if key == "lone_pairs":
362
+ value = cls._get_lp_value(attrs)
363
+ actual_key = "lone_pairs" if "lone_pairs" in attrs else "lp"
364
+ is_diff = cls._pair_diff(value)
365
+ elif key == "hcount":
366
+ value = attrs.get(key)
367
+ actual_key = key
368
+ is_diff = cls._hcount_diff(value)
369
+ else:
370
+ value = attrs.get(key)
371
+ actual_key = key
372
+ is_diff = cls._pair_diff(value)
373
+
374
+ if is_diff:
375
+ reasons.append(actual_key)
376
+
377
+ return reasons
378
+
379
+ @staticmethod
380
+ def _edge_reasons(attrs: dict[str, Any]) -> list[str]:
381
+ """
382
+ Determine why an edge belongs to the reaction center.
383
+
384
+ An edge is marked as part of the reaction center when its
385
+ ``standard_order`` is non-zero.
386
+
387
+ :param attrs: Edge attribute dictionary from the ITS graph.
388
+ :type attrs: dict[str, Any]
389
+ :return: List containing ``"standard_order"`` if the edge is in the
390
+ reaction center, otherwise an empty list.
391
+ :rtype: list[str]
392
+ """
393
+ value = attrs.get("standard_order", 0.0)
394
+ if value != 0 and value != 0.0:
395
+ return ["standard_order"]
396
+ return []
397
+
398
+ def _select_attrs(
399
+ self,
400
+ attrs: dict[str, Any],
401
+ keys: Iterable[str],
402
+ ) -> dict[str, Any]:
403
+ """
404
+ Select a subset of attributes from a dictionary.
405
+
406
+ Missing keys are ignored.
407
+
408
+ :param attrs: Source attribute dictionary.
409
+ :type attrs: dict[str, Any]
410
+ :param keys: Attribute names to retain.
411
+ :type keys: Iterable[str]
412
+ :return: Filtered attribute dictionary.
413
+ :rtype: dict[str, Any]
414
+ """
415
+ return {key: attrs[key] for key in keys if key in attrs}
416
+
417
+ def _collect_node_attrs(
418
+ self,
419
+ graph: nx.Graph,
420
+ nodes: Iterable[int],
421
+ ) -> dict[int, dict[str, Any]]:
422
+ """
423
+ Collect configured node attributes for reaction-center nodes.
424
+
425
+ :param graph: Graph containing node attributes.
426
+ :type graph: nx.Graph
427
+ :param nodes: Node identifiers to inspect.
428
+ :type nodes: Iterable[int]
429
+ :return: Mapping from node identifier to filtered attribute dictionary.
430
+ :rtype: dict[int, dict[str, Any]]
431
+ """
432
+ collected: dict[int, dict[str, Any]] = {}
433
+ for node in nodes:
434
+ selected = (
435
+ dict(graph.nodes[node])
436
+ if self.preserve_full_attrs
437
+ else self._select_attrs(graph.nodes[node], self.node_attrs)
438
+ )
439
+ if selected:
440
+ collected[node] = selected
441
+ return collected
442
+
443
+ def _collect_edge_attrs(
444
+ self,
445
+ graph: nx.Graph,
446
+ edges: Iterable[tuple[int, int]],
447
+ ) -> dict[tuple[int, int], dict[str, Any]]:
448
+ """
449
+ Collect configured edge attributes for reaction-center edges.
450
+
451
+ :param graph: Graph containing edge attributes.
452
+ :type graph: nx.Graph
453
+ :param edges: Edge identifiers to inspect.
454
+ :type edges: Iterable[tuple[int, int]]
455
+ :return: Mapping from normalized edge identifier to filtered attribute
456
+ dictionary.
457
+ :rtype: dict[tuple[int, int], dict[str, Any]]
458
+ """
459
+ collected: dict[tuple[int, int], dict[str, Any]] = {}
460
+ for u, v in edges:
461
+ edge_key = self._edge_key(u, v)
462
+ selected = (
463
+ dict(graph.edges[u, v])
464
+ if self.preserve_full_attrs
465
+ else self._select_attrs(graph.edges[u, v], self.edge_attrs)
466
+ )
467
+ if selected:
468
+ collected[edge_key] = selected
469
+ return collected
470
+
471
+ def extract(
472
+ self,
473
+ its: nx.Graph,
474
+ include_context_edges: bool = True,
475
+ ) -> nx.Graph:
476
+ """Extract the reaction-center subgraph from an ITS graph.
477
+
478
+ By default, the returned graph is the induced subgraph on all
479
+ reaction-center nodes. Set ``include_context_edges=False`` to retain
480
+ the same nodes but only the edges explicitly classified as
481
+ reaction-center edges. All original node and retained edge attributes
482
+ are preserved. Additional reaction-center metadata is stored in
483
+ ``graph.graph["rc"]``.
484
+
485
+ The metadata dictionary contains:
486
+
487
+ - ``"nodes"``: sorted list of RC node identifiers
488
+ - ``"edges"``: sorted list of RC edge identifiers
489
+ - ``"node_reasons"``: per-node reasons for RC membership
490
+ - ``"edge_reasons"``: per-edge reasons for RC membership
491
+ - ``"default_node_attrs"``: configured node attribute names exported
492
+ - ``"default_edge_attrs"``: configured edge attribute names exported
493
+ - ``"node_attrs"``: filtered attribute snapshots for RC nodes
494
+ - ``"edge_attrs"``: filtered attribute snapshots for RC edges
495
+
496
+ :param its: ITS graph containing paired node and edge attributes.
497
+ :type its: nx.Graph
498
+ :param include_context_edges: If ``True``, include unchanged edges
499
+ between reaction-center nodes. If ``False``, include only edges
500
+ explicitly classified as reaction-center edges.
501
+ :type include_context_edges: bool
502
+ :return: Reaction-center subgraph with RC metadata stored in
503
+ ``graph.graph["rc"]``.
504
+ :rtype: nx.Graph
505
+
506
+ .. rubric:: Example
507
+
508
+ .. code-block:: python
509
+
510
+ import networkx as nx
511
+
512
+ its = nx.Graph()
513
+ its.add_node(
514
+ 1,
515
+ element=("C", "C"),
516
+ hcount=(2, 1),
517
+ charge=(0, 0),
518
+ atom_map=1,
519
+ )
520
+ its.add_node(
521
+ 2,
522
+ element=("O", "O"),
523
+ hcount=(0, 0),
524
+ charge=(0, 0),
525
+ atom_map=2,
526
+ )
527
+ its.add_edge(
528
+ 1,
529
+ 2,
530
+ standard_order=1,
531
+ bond_type=("single", "single"),
532
+ )
533
+
534
+ extractor = RCExtractor()
535
+ rc_graph = extractor.extract(its)
536
+
537
+ print(rc_graph.nodes())
538
+ print(rc_graph.edges())
539
+ print(rc_graph.graph["rc"]["default_node_attrs"])
540
+ print(rc_graph.graph["rc"]["node_attrs"])
541
+ """
542
+ rc_nodes: set[int] = set()
543
+ rc_edges: set[tuple[int, int]] = set()
544
+ node_reasons: dict[int, list[str]] = {}
545
+ edge_reasons: dict[tuple[int, int], list[str]] = {}
546
+
547
+ for node, attrs in its.nodes(data=True):
548
+ reasons = self._node_reasons(attrs)
549
+ if reasons:
550
+ rc_nodes.add(node)
551
+ node_reasons[node] = reasons
552
+
553
+ for u, v, attrs in its.edges(data=True):
554
+ reasons = self._edge_reasons(attrs)
555
+ if reasons:
556
+ edge_key = self._edge_key(u, v)
557
+ rc_edges.add(edge_key)
558
+ edge_reasons[edge_key] = reasons
559
+ rc_nodes.add(u)
560
+ rc_nodes.add(v)
561
+
562
+ try:
563
+ from synkit.Graph.Stereo import stereo_complete_reaction_center_nodes
564
+
565
+ for node in stereo_complete_reaction_center_nodes(its):
566
+ rc_nodes.add(node)
567
+ node_reasons.setdefault(node, []).append("stereo_change_dependency")
568
+ except ImportError:
569
+ pass
570
+
571
+ if include_context_edges:
572
+ rc_graph = its.subgraph(rc_nodes).copy()
573
+ else:
574
+ rc_graph = its.__class__()
575
+ rc_graph.graph.update(its.graph)
576
+ rc_graph.add_nodes_from((node, dict(its.nodes[node])) for node in rc_nodes)
577
+ rc_graph.add_edges_from((u, v, dict(its.edges[u, v])) for u, v in rc_edges)
578
+ rc_graph.graph["rc"] = {
579
+ "nodes": sorted(rc_nodes),
580
+ "edges": sorted(rc_edges),
581
+ "node_reasons": node_reasons,
582
+ "edge_reasons": edge_reasons,
583
+ "default_node_attrs": list(self.node_attrs),
584
+ "default_edge_attrs": list(self.edge_attrs),
585
+ "node_attrs": self._collect_node_attrs(rc_graph, sorted(rc_nodes)),
586
+ "edge_attrs": self._collect_edge_attrs(rc_graph, sorted(rc_edges)),
587
+ }
588
+
589
+ return rc_graph
590
+
591
+ def annotate(self, its: nx.Graph) -> nx.Graph:
592
+ """Return a full ITS graph annotated with reaction-center flags.
593
+
594
+ This method copies the full ITS graph and adds per-node and per-edge
595
+ reaction-center annotations without removing non-reaction-center
596
+ components.
597
+
598
+ Added node attributes:
599
+
600
+ - ``node["rc"]``: boolean reaction-center membership flag
601
+ - ``node["rc_reasons"]``: list of reasons for RC membership
602
+
603
+ Added edge attributes:
604
+
605
+ - ``edge["rc"]``: boolean reaction-center membership flag
606
+ - ``edge["rc_reasons"]``: list of reasons for RC membership
607
+
608
+ Added graph attribute:
609
+
610
+ - ``graph.graph["rc"]``: reaction-center metadata dictionary
611
+
612
+ :param its: ITS graph containing paired node and edge attributes.
613
+ :type its: nx.Graph
614
+ :return: Copy of the original ITS graph with reaction-center
615
+ annotations attached to nodes, edges, and graph metadata.
616
+ :rtype: nx.Graph
617
+
618
+ .. rubric:: Example
619
+
620
+ .. code-block:: python
621
+
622
+ import networkx as nx
623
+
624
+ its = nx.Graph()
625
+ its.add_node(1, element=("C", "N"), hcount=(2, 1), charge=(0, 0))
626
+ its.add_node(2, element=("O", "O"), hcount=(0, 0), charge=(0, 0))
627
+ its.add_edge(1, 2, standard_order=0)
628
+
629
+ extractor = RCExtractor()
630
+ annotated = extractor.annotate(its)
631
+
632
+ print(annotated.nodes[1]["rc"]) # True
633
+ print(annotated.nodes[1]["rc_reasons"]) # ['element', 'hcount']
634
+ print(annotated.edges[1, 2]["rc"]) # False
635
+ print(annotated.graph["rc"])
636
+ """
637
+ graph = its.copy()
638
+ rc_subgraph = self.extract(graph)
639
+ rc_info = rc_subgraph.graph["rc"]
640
+
641
+ rc_nodes = set(rc_info["nodes"])
642
+ rc_edges = set(tuple(edge) for edge in rc_info["edges"])
643
+ node_reasons = rc_info["node_reasons"]
644
+ edge_reasons = rc_info["edge_reasons"]
645
+
646
+ for node in graph.nodes:
647
+ graph.nodes[node]["rc"] = node in rc_nodes
648
+ graph.nodes[node]["rc_reasons"] = node_reasons.get(node, [])
649
+
650
+ for u, v in graph.edges:
651
+ edge_key = self._edge_key(u, v)
652
+ graph.edges[u, v]["rc"] = edge_key in rc_edges
653
+ graph.edges[u, v]["rc_reasons"] = edge_reasons.get(edge_key, [])
654
+
655
+ graph.graph["rc"] = rc_info
656
+ return graph