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,123 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Protocol, runtime_checkable
4
+
5
+ from rdkit import Chem
6
+ from rdkit.Chem import rdchem as rdchem
7
+
8
+
9
+ @runtime_checkable
10
+ class _AtomLike(Protocol):
11
+ """Minimal protocol RDKit atoms satisfy (duck-typed for typing tools)."""
12
+
13
+ def GetValence(self, which: rdchem.ValenceType | int = ...) -> int: ...
14
+ def GetExplicitValence(self) -> int: ...
15
+ def GetImplicitValence(self) -> int: ...
16
+ def GetNumImplicitHs(self) -> int: ...
17
+
18
+
19
+ class ValenceResolver:
20
+ """Warning-free valence utilities for RDKit atoms.
21
+
22
+ These helpers retrieve **explicit**, **implicit**, and **total** valences
23
+ while silencing common deprecation or signature warnings across RDKit
24
+ versions. They first try the modern keyword-argument API and then
25
+ fall back to older call signatures or legacy methods.
26
+
27
+ Preferred (modern) RDKit API:
28
+ - ``atom.GetValence(which=rdchem.ValenceType.EXPLICIT)``
29
+ - ``atom.GetValence(which=rdchem.ValenceType.IMPLICIT)``
30
+
31
+ Fallbacks maintain compatibility with older wrappers:
32
+ - ``atom.GetValence(rdchem.ValenceType.EXPLICIT)`` (positional)
33
+ - ``atom.GetExplicitValence()``
34
+ - ``atom.GetImplicitValence()``
35
+ - ``atom.GetNumImplicitHs()`` (as a last resort for implicit)
36
+
37
+ .. rubric:: Notes
38
+
39
+ * Returned values are coerced to Python ``int`` and guaranteed non-negative,
40
+ with ``0`` returned if all strategies fail.
41
+ * Values reflect the current atom state and must be queried again after
42
+ changes to hydrogen counts, aromaticity, or bond orders.
43
+ * ``Chem.Atom`` is an alias of ``rdchem.Atom``, but a structural duck-type
44
+ ``_AtomLike`` protocol is provided for static typing tools.
45
+
46
+ .. rubric:: Examples
47
+
48
+ >>> from rdkit import Chem
49
+ >>> m = Chem.MolFromSmiles("CCO")
50
+ >>> a = m.GetAtomWithIdx(1) # central carbon
51
+ >>> ValenceResolver.explicit(a) >= 0
52
+ True
53
+ >>> ValenceResolver.total(a) == ValenceResolver.explicit(a) + ValenceResolver.implicit(a)
54
+ True
55
+ """
56
+
57
+ @staticmethod
58
+ def explicit(atom: Chem.Atom | _AtomLike) -> int:
59
+ """Return the **explicit valence** of an atom.
60
+
61
+ Tries modern ``GetValence(which=EXPLICIT)`` first, then older positional
62
+ form, then ``GetExplicitValence()``. Returns ``0`` on failure.
63
+
64
+ :param atom: RDKit atom instance.
65
+ :type atom: rdchem.Atom
66
+ :return: Explicit valence (non-negative integer).
67
+ :rtype: int
68
+ """
69
+ # Modern keyword form (preferred; avoids RDKit warnings)
70
+ try:
71
+ return int(atom.GetValence(which=rdchem.ValenceType.EXPLICIT)) # type: ignore[call-arg]
72
+ except TypeError:
73
+ # Some RDKit builds don't accept the kwarg form
74
+ try:
75
+ return int(atom.GetValence(rdchem.ValenceType.EXPLICIT)) # type: ignore[arg-type]
76
+ except Exception:
77
+ # Legacy explicit valence API
78
+ try:
79
+ return int(atom.GetExplicitValence())
80
+ except Exception:
81
+ return 0
82
+
83
+ @staticmethod
84
+ def implicit(atom: Chem.Atom | _AtomLike) -> int:
85
+ """Return the **implicit valence** of an atom.
86
+
87
+ Tries modern ``GetValence(which=IMPLICIT)`` first, then older positional
88
+ form, then ``GetImplicitValence()``, finally falls back to the number of
89
+ implicit hydrogens if needed. Returns ``0`` on failure.
90
+
91
+ :param atom: RDKit atom instance.
92
+ :type atom: rdchem.Atom
93
+ :return: Implicit valence (non-negative integer).
94
+ :rtype: int
95
+ """
96
+ # Modern keyword form (preferred)
97
+ try:
98
+ return int(atom.GetValence(which=rdchem.ValenceType.IMPLICIT)) # type: ignore[call-arg]
99
+ except TypeError:
100
+ # Older builds without kwarg support
101
+ try:
102
+ return int(atom.GetValence(rdchem.ValenceType.IMPLICIT)) # type: ignore[arg-type]
103
+ except Exception:
104
+ # Legacy implicit valence API
105
+ try:
106
+ return int(atom.GetImplicitValence())
107
+ except Exception:
108
+ # As a last resort, approximate with implicit Hs
109
+ try:
110
+ return int(atom.GetNumImplicitHs())
111
+ except Exception:
112
+ return 0
113
+
114
+ @staticmethod
115
+ def total(atom: Chem.Atom | _AtomLike) -> int:
116
+ """Return the **total valence** (explicit + implicit).
117
+
118
+ :param atom: RDKit atom instance.
119
+ :type atom: rdchem.Atom
120
+ :return: Total valence as ``explicit(atom) + implicit(atom)``.
121
+ :rtype: int
122
+ """
123
+ return ValenceResolver.explicit(atom) + ValenceResolver.implicit(atom)
@@ -0,0 +1,44 @@
1
+ """Compatibility alias for :mod:`synkit.Chem.Mapper`.
2
+
3
+ Atom-to-atom mapping is now a top-level chemistry concern. New code should
4
+ import from :mod:`synkit.Chem.Mapper`; this package preserves the former
5
+ ``synkit.Chem.Reaction.Mapper`` imports, including imports of its submodules.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import importlib
11
+ import pkgutil
12
+ import sys
13
+
14
+ from synkit.Chem import Mapper as _mapper
15
+ from synkit.Chem.Mapper import * # noqa: F401,F403
16
+
17
+ __all__ = _mapper.__all__
18
+ __path__ = _mapper.__path__
19
+
20
+ for _solver_name in ("exact", "slap", "_native"):
21
+ globals()[_solver_name] = getattr(_mapper, _solver_name)
22
+
23
+ # Bind every canonical mapper module to its historical name. Besides keeping
24
+ # deep imports working, this ensures classes imported through old and new
25
+ # paths have the same identity.
26
+ for _module_info in pkgutil.walk_packages(
27
+ _mapper.__path__, prefix=f"{_mapper.__name__}."
28
+ ):
29
+ _canonical_name = _module_info.name
30
+ _module = importlib.import_module(_canonical_name)
31
+ _suffix = _canonical_name.removeprefix(_mapper.__name__)
32
+ sys.modules[f"{__name__}{_suffix}"] = _module
33
+ if _suffix.count(".") == 1:
34
+ globals()[_suffix[1:]] = _module
35
+
36
+ # Include flat compatibility aliases that no longer have their own source file.
37
+ for _canonical_name, _module in list(sys.modules.items()):
38
+ if _canonical_name.startswith(f"{_mapper.__name__}."):
39
+ _suffix = _canonical_name.removeprefix(_mapper.__name__)
40
+ sys.modules[f"{__name__}{_suffix}"] = _module
41
+ if _suffix.count(".") == 1:
42
+ globals()[_suffix[1:]] = _module
43
+
44
+ del _canonical_name, _mapper, _module, _module_info, _suffix, _solver_name
@@ -0,0 +1,20 @@
1
+ from .aam_validator import AAMValidator
2
+ from .explicit_h_audit import (
3
+ ExplicitHydrogenReactionAudit,
4
+ MappedBondChange,
5
+ audit_explicit_h_reaction,
6
+ reaction_smiles_from_annotated_text,
7
+ )
8
+ from synkit.Chem.utils import remove_explicit_H_from_rsmi
9
+
10
+ # from .standardize import Standardize
11
+ # from .canon_rsmi import CanonRSMI
12
+
13
+ __all__ = [
14
+ "AAMValidator",
15
+ "ExplicitHydrogenReactionAudit",
16
+ "MappedBondChange",
17
+ "audit_explicit_h_reaction",
18
+ "reaction_smiles_from_annotated_text",
19
+ "remove_explicit_H_from_rsmi",
20
+ ]
@@ -0,0 +1,5 @@
1
+ """Backward-compatible AAMValidator import path."""
2
+
3
+ from synkit.Chem.Mapper.aam_validator import AAMValidator
4
+
5
+ __all__ = ["AAMValidator"]
@@ -0,0 +1,138 @@
1
+ from rdkit import Chem
2
+ from rdkit.Chem.rdMolDescriptors import CalcMolFormula
3
+ from joblib import Parallel, delayed
4
+ from typing import List, Dict, Union, Tuple, Any
5
+
6
+
7
+ class BalanceReactionCheck:
8
+ """Check elemental balance of chemical reactions in SMILES format.
9
+
10
+ Supports checking single reactions, reaction dictionaries, or lists
11
+ in parallel.
12
+
13
+ :ivar n_jobs: Number of parallel jobs for batch checking.
14
+ :ivar verbose: Verbosity level for joblib.
15
+ """
16
+
17
+ def __init__(self, n_jobs: int = 4, verbose: int = 0) -> None:
18
+ """
19
+ :param n_jobs: Number of parallel jobs for batch balance checks. Defaults to 4.
20
+ :type n_jobs: int
21
+ :param verbose: Verbosity level passed to joblib. Defaults to 0.
22
+ :type verbose: int
23
+ """
24
+ self.n_jobs = n_jobs
25
+ self.verbose = verbose
26
+
27
+ @staticmethod
28
+ def get_combined_molecular_formula(smiles: str) -> str:
29
+ """Compute the molecular formula of a SMILES.
30
+
31
+ :param smiles: SMILES string of the molecule.
32
+ :type smiles: str
33
+ :return: Elemental formula (e.g., "C6H6") or empty string if
34
+ invalid.
35
+ :rtype: str
36
+ """
37
+ mol = Chem.MolFromSmiles(smiles)
38
+ if not mol:
39
+ return ""
40
+ return CalcMolFormula(mol)
41
+
42
+ @staticmethod
43
+ def parse_input(
44
+ input_data: Union[str, List[Union[str, Dict[str, str]]]],
45
+ rsmi_column: str = "reactions",
46
+ ) -> List[Dict[str, str]]:
47
+ """Normalize input into a list of reaction‐dicts.
48
+
49
+ :param input_data: A single SMILES, list of SMILES, or list of dicts containing `rsmi_column`.
50
+ :type input_data: str or List[Union[str, Dict[str, str]]]
51
+ :param rsmi_column: Key in dicts for the reaction SMILES. Defaults to "reactions".
52
+ :type rsmi_column: str
53
+ :return: List of dicts with a single key `rsmi_column` mapping to each reaction.
54
+ :rtype: List[Dict[str, str]]
55
+ :raises ValueError: If `input_data` is neither str nor list.
56
+ """
57
+ standardized: List[Dict[str, str]] = []
58
+ if isinstance(input_data, str):
59
+ standardized.append({rsmi_column: input_data})
60
+ elif isinstance(input_data, list):
61
+ for item in input_data:
62
+ if isinstance(item, str):
63
+ standardized.append({rsmi_column: item})
64
+ elif isinstance(item, dict) and rsmi_column in item:
65
+ standardized.append(item)
66
+ else:
67
+ raise ValueError("Unsupported input type for balance checking")
68
+ return standardized
69
+
70
+ @staticmethod
71
+ def parse_reaction(reaction_smiles: str) -> Tuple[str, str]:
72
+ """Split a reaction SMILES into reactant and product SMILES strings.
73
+
74
+ :param reaction_smiles: Reaction SMILES in 'reactants>>products'
75
+ format.
76
+ :type reaction_smiles: str
77
+ :return: Tuple of (reactants, products) SMILES.
78
+ :rtype: Tuple[str, str]
79
+ """
80
+ return tuple(reaction_smiles.split(">>"))
81
+
82
+ @staticmethod
83
+ def rsmi_balance_check(reaction_smiles: str) -> bool:
84
+ """Determine if a reaction SMILES is elementally balanced.
85
+
86
+ :param reaction_smiles: Reaction SMILES in 'reactants>>products'
87
+ format.
88
+ :type reaction_smiles: str
89
+ :return: True if reactant and product formulas match, else
90
+ False.
91
+ :rtype: bool
92
+ """
93
+ react, prod = BalanceReactionCheck.parse_reaction(reaction_smiles)
94
+ react_formula = BalanceReactionCheck.get_combined_molecular_formula(react)
95
+ prod_formula = BalanceReactionCheck.get_combined_molecular_formula(prod)
96
+ return react_formula == prod_formula
97
+
98
+ @staticmethod
99
+ def dict_balance_check(
100
+ reaction_dict: Dict[str, str], rsmi_column: str
101
+ ) -> Dict[str, Any]:
102
+ """Check balance for a single reaction dict, preserving original keys.
103
+
104
+ :param reaction_dict: Dict containing at least a `rsmi_column` key.
105
+ :type reaction_dict: Dict[str, str]
106
+ :param rsmi_column: Key for reaction SMILES in `reaction_dict`.
107
+ :type rsmi_column: str
108
+ :return: Original dict augmented with `"balanced": bool`.
109
+ :rtype: Dict[str, Any]
110
+ """
111
+ rsmi = reaction_dict[rsmi_column]
112
+ balanced = BalanceReactionCheck.rsmi_balance_check(rsmi)
113
+ return {"balanced": balanced, **reaction_dict}
114
+
115
+ def dicts_balance_check(
116
+ self,
117
+ input_data: Union[str, List[Union[str, Dict[str, str]]]],
118
+ rsmi_column: str = "reactions",
119
+ ) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
120
+ """Batch‐check balance for multiple reactions, in parallel.
121
+
122
+ :param input_data: Single reaction SMILES, list of SMILES, or
123
+ list of dicts.
124
+ :type input_data: Union[str, List[Union[str, Dict[str, str]]]]
125
+ :param rsmi_column: Key for reaction SMILES in each dict.
126
+ Defaults to "reactions".
127
+ :type rsmi_column: str
128
+ :return: Tuple (balanced_list, unbalanced_list) of dicts each
129
+ including `"balanced"`.
130
+ :rtype: Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]
131
+ """
132
+ reactions = self.parse_input(input_data, rsmi_column)
133
+ results = Parallel(n_jobs=self.n_jobs, verbose=self.verbose)(
134
+ delayed(self.dict_balance_check)(rd, rsmi_column) for rd in reactions
135
+ )
136
+ balanced = [r for r in results if r["balanced"]]
137
+ unbalanced = [r for r in results if not r["balanced"]]
138
+ return balanced, unbalanced
@@ -0,0 +1,249 @@
1
+ import inspect
2
+ import networkx as nx
3
+ from rdkit import Chem
4
+ from rdkit.Chem import MolFromSmiles as _rdkit_MolFromSmiles
5
+ from typing import List, Tuple, Union, Optional
6
+
7
+ from synkit.Graph.canon_graph import GraphCanonicaliser
8
+ from synkit.IO import graph_to_smi, rsmi_to_graph
9
+
10
+
11
+ class CanonRSMI:
12
+ """A **pure-Python / pure-NetworkX** utility for canonicalizing reaction
13
+ SMILES by expanding atom-maps and deterministically reindexing reaction
14
+ graphs.
15
+
16
+ Workflow
17
+ --------
18
+ 1. **Expand atom-maps** on reactants to ensure each atom has a unique map ID.
19
+ 2. **Convert** reaction SMILES to reactant/product NetworkX graphs.
20
+ 3. **Canonicalize** the reactant graph using `GraphCanonicaliser` (generic or WL backend).
21
+ 4. **Match** atom-map IDs to compute pairwise indices between reactants and products.
22
+ 5. **Remap** the product graph to align with the canonical reactant ordering.
23
+ 6. **Sync** each node’s `atom_map` attribute to its new graph index.
24
+ 7. **Reassemble** the reaction SMILES from the canonical graphs.
25
+
26
+ Classes
27
+ -------
28
+ - `CanonRSMI` – Main interface for transforming any `reactants>>products` SMILES
29
+ into a canonicalized form, preserving all node and edge attributes.
30
+
31
+ .. rubric:: Example
32
+
33
+ >>> from canonical_rsm import CanonRSMI
34
+ >>> canon = CanonRSMI(backend='wl', wl_iterations=5)
35
+ >>> result = canon.canonicalise('[CH3:3][CH2:5][OH:10]>>[CH2:3]=[CH2:5].[OH2:10]')
36
+ >>> print(result.canonical_rsmi)
37
+ [OH:1][CH2:3][CH3:2]>>[CH2:2]=[CH2:3].[OH2:1]
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ backend: str = "wl",
43
+ wl_iterations: int = 3,
44
+ morgan_radius: int = 3,
45
+ node_attrs: List[str] = ("element", "aromatic", "charge", "hcount"),
46
+ ):
47
+ self._canon = GraphCanonicaliser(
48
+ backend=backend,
49
+ wl_iterations=wl_iterations,
50
+ morgan_radius=morgan_radius,
51
+ node_attrs=node_attrs,
52
+ )
53
+ # internal storage
54
+ self._raw_rsmi: Optional[str] = None
55
+ self._canon_rsmi: Optional[str] = None
56
+ self._raw_reactant_graph: Optional[nx.Graph] = None
57
+ self._raw_product_graph: Optional[nx.Graph] = None
58
+ self._canon_reactant_graph: Optional[nx.Graph] = None
59
+ self._canon_product_graph: Optional[nx.Graph] = None
60
+ self._mapping_pairs: Optional[List[Tuple[int, int]]] = None
61
+
62
+ @staticmethod
63
+ def _mol_from_smiles(smi: str) -> Chem.Mol:
64
+ """RDKit MolFromSmiles with explicit sanitize step."""
65
+ mol = _rdkit_MolFromSmiles(smi, sanitize=False)
66
+ Chem.SanitizeMol(mol)
67
+ return mol
68
+
69
+ def expand_aam(self, rsmi: str) -> str:
70
+ """Assign new atom-map IDs to unmapped reactant atoms in
71
+ 'reactants>>products' SMILES.
72
+
73
+ New IDs start at max(existing maps)+1.
74
+ """
75
+ try:
76
+ reac_s, prod_s = rsmi.split(">>")
77
+ except ValueError:
78
+ raise ValueError("Input must be in 'reactants>>products' form")
79
+
80
+ reac_mols = [self._mol_from_smiles(s) for s in reac_s.split(".")]
81
+ prod_mols = [self._mol_from_smiles(s) for s in prod_s.split(".")]
82
+
83
+ existing = {
84
+ atom.GetAtomMapNum()
85
+ for mol in (*reac_mols, *prod_mols)
86
+ for atom in mol.GetAtoms()
87
+ if atom.GetAtomMapNum() > 0
88
+ }
89
+ next_id = max(existing, default=0) + 1
90
+
91
+ for mol in reac_mols:
92
+ for atom in mol.GetAtoms():
93
+ if atom.GetAtomMapNum() == 0:
94
+ atom.SetAtomMapNum(next_id)
95
+ next_id += 1
96
+
97
+ new_reac = ".".join(Chem.MolToSmiles(m, canonical=True) for m in reac_mols)
98
+ new_prod = ".".join(Chem.MolToSmiles(m, canonical=True) for m in prod_mols)
99
+ return f"{new_reac}>>{new_prod}"
100
+
101
+ @staticmethod
102
+ def sync_atom_map_with_index(G: nx.Graph) -> None:
103
+ """
104
+ In-place: set each node's 'atom_map' attribute to its node ID.
105
+ """
106
+ nx.set_node_attributes(G, {n: n for n in G.nodes()}, "atom_map")
107
+
108
+ @staticmethod
109
+ def get_aam_pairwise_indices(
110
+ G: nx.Graph, H: nx.Graph, aam_key: str = "atom_map"
111
+ ) -> List[Tuple[int, int]]:
112
+ """Return sorted list of (G_node, H_node) for shared atom-map IDs."""
113
+ gmap = {
114
+ data[aam_key]: n
115
+ for n, data in G.nodes(data=True)
116
+ if data.get(aam_key, 0) > 0
117
+ }
118
+ hmap = {
119
+ data[aam_key]: n
120
+ for n, data in H.nodes(data=True)
121
+ if data.get(aam_key, 0) > 0
122
+ }
123
+ common = sorted(gmap.keys() & hmap.keys())
124
+ return [(gmap[k], hmap[k]) for k in common]
125
+
126
+ @staticmethod
127
+ def remap_graph(
128
+ G: nx.Graph, node_map: Union[List[int], List[Tuple[int, int]]]
129
+ ) -> nx.Graph:
130
+ """Remap a product graph to match a canonical reactant ordering:
131
+
132
+ :param G: reactant graph
133
+ :type G: nx.Graph
134
+ :param node_map: Product node ordering or ``(new, old)`` node pairs.
135
+ :type node_map: list[int] | list[tuple[int, int]]
136
+ :return:
137
+ remapped product graph
138
+ :rtype: nx.Graph
139
+ """
140
+
141
+ if not node_map:
142
+ raise ValueError("node_map must be non-empty")
143
+ if isinstance(node_map[0], int):
144
+ mapping = {old: new for new, old in enumerate(node_map, start=1)}
145
+ else:
146
+ mapping = {old: new for new, old in node_map}
147
+ missing = set(mapping) - set(G.nodes())
148
+ if missing:
149
+ raise KeyError(f"Mappings refer to nodes not in G: {missing}")
150
+ return nx.relabel_nodes(G, mapping, copy=True)
151
+
152
+ def canonicalise(self, rsmi: str) -> "CanonRSMI":
153
+ """
154
+ Full pipeline returning self with properties populated:
155
+ - raw_rsmi
156
+ - raw_reactant_graph, raw_product_graph
157
+ - mapping_pairs
158
+ - canonical_reactant_graph, canonical_product_graph
159
+ - canonical_rsmi
160
+ """
161
+ # store raw
162
+ self._raw_rsmi = rsmi
163
+ # expand and build graphs
164
+ expanded = self.expand_aam(rsmi)
165
+ self._raw_reactant_graph, self._raw_product_graph = rsmi_to_graph(expanded)
166
+ # canonicalise reactants
167
+ self._canon_reactant_graph = self._canon.canonicalise_graph(
168
+ self._raw_reactant_graph
169
+ ).canonical_graph
170
+ # map products
171
+ self._mapping_pairs = self.get_aam_pairwise_indices(
172
+ self._canon_reactant_graph, self._raw_product_graph
173
+ )
174
+ self._canon_product_graph = self.remap_graph(
175
+ self._raw_product_graph, self._mapping_pairs
176
+ )
177
+ # sync maps
178
+ self.sync_atom_map_with_index(self._canon_reactant_graph)
179
+ self.sync_atom_map_with_index(self._canon_product_graph)
180
+ # assemble output
181
+ self._canon_rsmi = (
182
+ f"{graph_to_smi(self._canon_reactant_graph)}>>"
183
+ f"{graph_to_smi(self._canon_product_graph)}"
184
+ )
185
+ return self
186
+
187
+ __call__ = canonicalise
188
+
189
+ @property
190
+ def raw_rsmi(self) -> Optional[str]:
191
+ """Original SMILES before canonicalisation."""
192
+ return self._raw_rsmi
193
+
194
+ @property
195
+ def canonical_rsmi(self) -> Optional[str]:
196
+ """Canonical SMILES after processing."""
197
+ return self._canon_rsmi
198
+
199
+ @property
200
+ def raw_reactant_graph(self) -> Optional[nx.Graph]:
201
+ """NetworkX graph of raw reactants."""
202
+ return self._raw_reactant_graph
203
+
204
+ @property
205
+ def raw_product_graph(self) -> Optional[nx.Graph]:
206
+ """NetworkX graph of raw products."""
207
+ return self._raw_product_graph
208
+
209
+ @property
210
+ def canonical_reactant_graph(self) -> Optional[nx.Graph]:
211
+ """NetworkX graph of canonicalised reactants."""
212
+ return self._canon_reactant_graph
213
+
214
+ @property
215
+ def canonical_product_graph(self) -> Optional[nx.Graph]:
216
+ """NetworkX graph of canonicalised products."""
217
+ return self._canon_product_graph
218
+
219
+ @property
220
+ def canonical_hash(self) -> Optional[str]:
221
+ """Reaction-level hash combining reactant and product canonical
222
+ hashes."""
223
+ if not self._canon_reactant_graph or not self._canon_product_graph:
224
+ return None
225
+ h_reac = self._canon.canonical_signature(self._canon_reactant_graph)
226
+ h_prod = self._canon.canonical_signature(self._canon_product_graph)
227
+ return f"{h_reac}>>{h_prod}"
228
+
229
+ @property
230
+ def mapping_pairs(self) -> Optional[List[Tuple[int, int]]]:
231
+ """List of atom-map index pairs between reactants and products."""
232
+ return self._mapping_pairs
233
+
234
+ def help(self) -> None: # pragma: no cover
235
+ """Pretty-print the class doc and public methods with signatures."""
236
+ print(inspect.getdoc(self.__class__))
237
+ for meth in (
238
+ "expand_aam",
239
+ "canonicalise",
240
+ "get_aam_pairwise_indices",
241
+ "remap_graph",
242
+ ):
243
+ print(f" • {meth}{inspect.signature(getattr(self, meth))}")
244
+
245
+ def __repr__(self) -> str: # pragma: no cover
246
+ return (
247
+ f"<CanonRSMI backend={self._canon.backend!r} "
248
+ f"wl_iterations={self._canon._wl_k}>"
249
+ )
@@ -0,0 +1,58 @@
1
+ from typing import List
2
+ from synkit.Chem.Reaction.standardize import Standardize
3
+ from synkit.Chem.Reaction.balance_check import BalanceReactionCheck
4
+
5
+
6
+ class Cleaning:
7
+ """Utilities for cleaning and filtering reaction SMILES lists."""
8
+
9
+ def __init__(self) -> None:
10
+ """Initialize the Cleaning helper.
11
+
12
+ No instance attributes are used.
13
+ """
14
+ pass
15
+
16
+ @staticmethod
17
+ def remove_duplicates(smiles_list: List[str]) -> List[str]:
18
+ """Remove duplicate SMILES strings, preserving first occurrences.
19
+
20
+ :param smiles_list: List of reaction SMILES strings.
21
+ :type smiles_list: List[str]
22
+ :return: List of unique SMILES in original order.
23
+ :rtype: List[str]
24
+ """
25
+ seen = set()
26
+ return [smi for smi in smiles_list if not (smi in seen or seen.add(smi))]
27
+
28
+ @staticmethod
29
+ def clean_smiles(smiles_list: List[str]) -> List[str]:
30
+ """Standardize, balance‑check, and deduplicate reaction SMILES.
31
+
32
+ Steps:
33
+ 1. Standardize each SMILES via `Standardize.standardize_rsmi`.
34
+ 2. Keep only those that pass `BalanceReactionCheck.rsmi_balance_check`.
35
+ 3. Remove duplicates preserving order.
36
+
37
+ :param smiles_list: List of reaction SMILES strings to clean.
38
+ :type smiles_list: List[str]
39
+ :return: Cleaned list of standardized, balanced, unique SMILES.
40
+ :rtype: List[str]
41
+ """
42
+ standardizer = Standardize()
43
+ balance_checker = BalanceReactionCheck()
44
+
45
+ standardized: List[str] = []
46
+ for smi in smiles_list:
47
+ try:
48
+ std = standardizer.standardize_rsmi(smi, stereo=True)
49
+ if std:
50
+ standardized.append(std)
51
+ except Exception:
52
+ continue
53
+
54
+ balanced = [
55
+ smi for smi in standardized if balance_checker.rsmi_balance_check(smi)
56
+ ]
57
+
58
+ return Cleaning.remove_duplicates(balanced)