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,186 @@
1
+ import networkx as nx
2
+ from typing import List, Dict, Any, Set, Optional
3
+ from rdkit import Chem
4
+ from rdkit.Chem import AllChem
5
+
6
+
7
+ class GraphToSMARTS:
8
+ """Convert NetworkX graphs (with placeholder nodes/constraints) into SMARTS or reaction SMARTS strings.
9
+
10
+ :param placeholder_labels: Set of labels recognized as placeholders (e.g., '_R', 'X', 'Y', 'Z').
11
+ :type placeholder_labels: Optional[Set[str]]
12
+ :param validate: If True, validate generated SMARTS or reaction SMARTS using RDKit.
13
+ :type validate: bool
14
+
15
+ .. rubric:: Examples
16
+
17
+ >>> G = nx.Graph()
18
+ >>> G.add_node(1, label='C', constraint=None)
19
+ >>> G.add_node(2, label='O', constraint=None)
20
+ >>> G.add_edge(1, 2, order=1)
21
+ >>> g2s = GraphToSMARTS()
22
+ >>> smarts = g2s.graph_to_smarts(G)
23
+ >>> isinstance(smarts, str)
24
+ True
25
+ """
26
+
27
+ def __init__(
28
+ self, placeholder_labels: Optional[Set[str]] = None, validate: bool = True
29
+ ) -> None:
30
+ """Initialize the GraphToSMARTS converter.
31
+
32
+ :param placeholder_labels: Labels to treat as wildcard placeholders; defaults to {'_R','X','Y','Z'}.
33
+ :type placeholder_labels: Optional[Set[str]]
34
+ :param validate: Whether to validate SMARTS with RDKit if available.
35
+ :type validate: bool
36
+ :return: None
37
+ :rtype: None
38
+ """
39
+ if placeholder_labels is None:
40
+ placeholder_labels = {"_R", "X", "Y", "Z"}
41
+ self.placeholder_labels: Set[str] = placeholder_labels
42
+ self.validate: bool = validate
43
+
44
+ def graph_to_smarts(self, G: nx.Graph) -> str:
45
+ """Convert a NetworkX graph into a SMARTS string representation.
46
+
47
+ :param G: NetworkX Graph with node attributes:
48
+ - 'label': str atomic label or placeholder
49
+ - 'constraint': Optional[List[str]] allowed element list for placeholders
50
+ and edge attribute:
51
+ - 'order': float bond order (1,1.5,2,3)
52
+ :type G: nx.Graph
53
+ :return: SMARTS string encoding the graph structure.
54
+ :rtype: str
55
+ :raises ValueError: If RDKit fails to parse the generated SMARTS when validate=True.
56
+
57
+ .. rubric:: Examples
58
+
59
+ >>> G = nx.Graph()
60
+ >>> G.add_node(1, label='C', constraint=None)
61
+ >>> G.add_node(2, label='O', constraint=None)
62
+ >>> G.add_edge(1, 2, order=1)
63
+ >>> smarts = GraphToSMARTS().graph_to_smarts(G)
64
+ >>> smarts
65
+ '[C:1](-[O:2])'
66
+ """
67
+ bond_sym: Dict[float, str] = {1: "-", 1.5: ":", 2: "=", 3: "#"}
68
+
69
+ def bracket(node: Any, data: Dict[str, Any]) -> str:
70
+ map_num = node
71
+ if data.get("constraint"):
72
+ core = ",".join(data["constraint"])
73
+ else:
74
+ core = data["label"]
75
+ return f"[{core}:{map_num}]"
76
+
77
+ def choose_root(sub: nx.Graph) -> Any:
78
+ real_nodes = [
79
+ n
80
+ for n, d in sub.nodes(data=True)
81
+ if d.get("label") not in self.placeholder_labels
82
+ ]
83
+ if real_nodes:
84
+ return max(real_nodes, key=sub.degree)
85
+ return min(sub.nodes)
86
+
87
+ def rec(node: Any, parent: Any, sub: nx.Graph, visited: Set[Any]) -> str:
88
+ visited.add(node)
89
+ s = bracket(node, sub.nodes[node])
90
+ for nbr in sub.neighbors(node):
91
+ if nbr == parent:
92
+ continue
93
+ order = sub[node][nbr].get("order", 1)
94
+ bond = bond_sym.get(order, "-")
95
+ s += f"({bond}{rec(nbr, node, sub, visited)})"
96
+ return s
97
+
98
+ frags: List[str] = []
99
+ for comp in nx.connected_components(G):
100
+ subgraph = G.subgraph(comp)
101
+ root = choose_root(subgraph)
102
+ frags.append(rec(root, None, subgraph, set()))
103
+
104
+ smarts: str = ".".join(frags)
105
+
106
+ if self.validate:
107
+ try:
108
+ if not Chem.MolFromSmarts(smarts):
109
+ raise ValueError("RDKit could not parse generated SMARTS.")
110
+ except ImportError:
111
+ pass
112
+
113
+ return smarts
114
+
115
+ def graphs_to_rxn_smarts(self, reactant: nx.Graph, product: nx.Graph) -> str:
116
+ """Construct a reaction SMARTS string from reactant and product graphs.
117
+
118
+ :param reactant: Reactant NetworkX graph.
119
+ :type reactant: nx.Graph
120
+ :param product: Product NetworkX graph.
121
+ :type product: nx.Graph
122
+ :return: Reaction SMARTS in the form 'reactants>>products'.
123
+ :rtype: str
124
+ :raises ValueError: If RDKit fails to parse the reaction SMARTS when validate=True.
125
+
126
+ .. rubric:: Examples
127
+
128
+ >>> G1 = nx.Graph()
129
+ >>> G1.add_node(1, label='C', constraint=None)
130
+ >>> G1.add_node(2, label='O', constraint=None)
131
+ >>> G1.add_edge(1, 2, order=1)
132
+ >>> G2 = nx.Graph()
133
+ >>> G2.add_node(1, label='C', constraint=None)
134
+ >>> G2.add_node(2, label='O', constraint=None)
135
+ >>> G2.add_edge(1, 2, order=2)
136
+ >>> rxn = GraphToSMARTS().graphs_to_rxn_smarts(G1, G2)
137
+ >>> rxn
138
+ '[C:1](-[O:2])>>[C:1]([O:2])='
139
+ """
140
+ sm_r: str = self.graph_to_smarts(reactant)
141
+ sm_p: str = self.graph_to_smarts(product)
142
+ rxn: str = f"{sm_r}>>{sm_p}"
143
+
144
+ if self.validate:
145
+ try:
146
+ if not AllChem.ReactionFromSmarts(rxn):
147
+ raise ValueError("RDKit could not parse generated reaction SMARTS.")
148
+ except ImportError:
149
+ pass
150
+
151
+ return rxn
152
+
153
+ def __repr__(self) -> str:
154
+ """Return an unambiguous representation of the converter instance.
155
+
156
+ :return: String showing placeholder labels and validation setting.
157
+ :rtype: str
158
+ """
159
+ return (
160
+ f"<GraphToSMARTS placeholder_labels={self.placeholder_labels}, "
161
+ f"validate={self.validate}>"
162
+ )
163
+
164
+ def help(self) -> str:
165
+ """Provide usage information for GraphToSMARTS.
166
+
167
+ :return: Multi-line help string describing available methods.
168
+ :rtype: str
169
+
170
+ .. rubric:: Examples
171
+
172
+ >>> print(GraphToSMARTS().help()) # doctest:+NORMALIZE_WHITESPACE
173
+ GraphToSMARTS(placeholder_labels=None, validate=True)
174
+ - Use .graph_to_smarts(G) for a single graph
175
+ - Use .graphs_to_rxn_smarts(G_react, G_prod) for reaction SMARTS
176
+ """
177
+ return (
178
+ "GraphToSMARTS(placeholder_labels=None, validate=True)\n"
179
+ " - Use .graph_to_smarts(G) for a single graph\n"
180
+ " - Use .graphs_to_rxn_smarts(G_react, G_prod) for reaction SMARTS\n"
181
+ "Node attributes expected:\n"
182
+ " label: str (e.g., 'C', '_R', 'H+')\n"
183
+ " constraint: Optional[List[str]] for placeholders\n"
184
+ "Edge attribute:\n"
185
+ " order: float (1, 1.5, 2, 3) mapped to '-', ':', '=', '#'\n"
186
+ )
@@ -0,0 +1,147 @@
1
+ import re
2
+ import itertools
3
+ from typing import List, Dict, Tuple, Iterator, Union
4
+
5
+
6
+ class SMARTSExpander:
7
+ """Efficiently enumerate all valid reaction SMARTS by expanding atom-list
8
+ placeholders like [C,N,O,P,S:9], ensuring that each atom-map uses the same
9
+ element everywhere it appears (on both sides of a reaction).
10
+
11
+ :param smarts: SMARTS string, possibly containing one or more atom-list placeholders.
12
+ :type smarts: str
13
+ :return: Expanded SMARTS strings without atom-list placeholders.
14
+ :rtype: List[str]
15
+ :raises ValueError: If no valid expansions exist due to incompatible element lists.
16
+
17
+ Example usage::
18
+
19
+ >>> rxn = (
20
+ ... '[H+:6].[C:7](-[O:8](-[H:12]))(-[C,N,O,P,S:9])'
21
+ ... '(-[C,N,O,P,S:10])(-[H:11]).'
22
+ ... '[C:2](-[S:4](-[C,N,O,P,S:5]))(-[C,N,O,P,S:1])(=[O:3])>>'
23
+ ... '[S:4](-[H:6])(-[C,N,O,P,S:5]).[H+:12].'
24
+ ... '[C:7](-[O:8](-[C:2](-[C,N,O,P,S:1])(=[O:3])))(-[C,N,O,P,S:9])'
25
+ ... '(-[C,N,O,P,S:10])(-[H:11])'
26
+ ... )
27
+ >>> ex = SMARTSExpander.expand(rxn)
28
+ >>> len(ex)
29
+ 625
30
+ >>> ex[:3] # first three expansions
31
+ ['[H+:6].[C:7](-[O:8](-[H:12]))(-[C:9])(-[C:10])(-[H:11]).[C:2]...'
32
+ '>>',
33
+ '...',
34
+ '...']
35
+ """
36
+
37
+ _PAT = re.compile(r"\[([A-Z][a-z]?(?:,[A-Z][a-z]?)*)(:[0-9]+)\]")
38
+
39
+ @staticmethod
40
+ def _extract_map_to_elements(matches: List[re.Match]) -> Dict[str, List[str]]:
41
+ """Build a mapping from atom-map to the intersection of allowed elements.
42
+
43
+ :param matches: List of regex match objects for placeholders.
44
+ :type matches: List[re.Match]
45
+ :return: Dictionary mapping ":map" to sorted list of shared elements.
46
+ :rtype: Dict[str, List[str]]
47
+ """
48
+ amap2set: Dict[str, set] = {}
49
+ for m in matches:
50
+ elems = set(m.group(1).split(","))
51
+ amap = m.group(2)
52
+ if amap not in amap2set:
53
+ amap2set[amap] = elems
54
+ else:
55
+ amap2set[amap] &= elems
56
+ for amap, s in amap2set.items():
57
+ if not s:
58
+ raise ValueError(f"No overlapping elements for atom-map {amap}")
59
+ return {amap: sorted(s) for amap, s in amap2set.items()}
60
+
61
+ @staticmethod
62
+ def _build_template(
63
+ smarts: str, matches: List[re.Match]
64
+ ) -> Tuple[List[Union[str, str]], List[str]]:
65
+ """Build a list of string segments and placeholders for reconstruction.
66
+
67
+ :param smarts: Original SMARTS string.
68
+ :type smarts: str
69
+ :param matches: Regex matches for placeholders.
70
+ :type matches: List[re.Match]
71
+ :return: Tuple of list of segments and placeholder order.
72
+ :rtype: Tuple[List[Union[str, str]], List[str]]
73
+ """
74
+ segments: List[Union[str, str]] = []
75
+ placeholder_order: List[str] = []
76
+ last = 0
77
+ for m in matches:
78
+ # fmt: off
79
+ segments.append(smarts[last: m.start()])
80
+ # fmt: on
81
+ amap = m.group(2)
82
+ segments.append(amap)
83
+ placeholder_order.append(amap)
84
+ last = m.end()
85
+ segments.append(smarts[last:])
86
+ return segments, placeholder_order
87
+
88
+ @classmethod
89
+ def expand_iter(cls, smarts: str) -> Iterator[str]:
90
+ """Yield expanded SMARTS strings lazily.
91
+
92
+ :param smarts: SMARTS string with placeholders.
93
+ :type smarts: str
94
+ :yield: One expanded SMARTS string at a time.
95
+ :rtype: Iterator[str]
96
+
97
+ :raises ValueError: If no valid expansions due to incompatible lists.
98
+ """
99
+ matches = list(cls._PAT.finditer(smarts))
100
+ if not matches:
101
+ yield smarts
102
+ return
103
+
104
+ amap2els = cls._extract_map_to_elements(matches)
105
+ segments, order = cls._build_template(smarts, matches)
106
+ unique_maps = list(dict.fromkeys(order))
107
+
108
+ pools = [amap2els[am] for am in unique_maps]
109
+ for combo in itertools.product(*pools):
110
+ mapping = dict(zip(unique_maps, combo))
111
+ out = []
112
+ for seg in segments:
113
+ if seg in mapping:
114
+ out.append(f"[{mapping[seg]}{seg}]")
115
+ else:
116
+ out.append(seg)
117
+ yield "".join(out)
118
+
119
+ @classmethod
120
+ def expand(cls, smarts: str) -> List[str]:
121
+ """Return a list of all expanded SMARTS.
122
+
123
+ :param smarts: SMARTS string with placeholders.
124
+ :type smarts: str
125
+ :return: List of expanded SMARTS strings.
126
+ :rtype: List[str]
127
+
128
+ :raises ValueError: If no valid expansions exist.
129
+ """
130
+ return list(cls.expand_iter(smarts))
131
+
132
+
133
+ # # --- Example usage ---
134
+
135
+ # if __name__ == "__main__":
136
+ # rxn = (
137
+ # '[H+:6].[C:7](-[O:8](-[H:12]))(-[C,N,O,P,S:9])(-[C,N,O,P,S:10])(-[H:11]).'
138
+ # '[C:2](-[S:4](-[C,N,O,P,S:5]))(-[C,N,O,P,S:1])(=[O:3])>>'
139
+ # '[S:4](-[H:6])(-[C,N,O,P,S:5]).[H+:12].'
140
+ # '[C:7](-[O:8](-[C:2](-[C,N,O,P,S:1])(=[O:3])))(-[C,N,O,P,S:9])(-[C,N,O,P,S:10])(-[H:11])'
141
+ # )
142
+ # n = 0
143
+ # for i, s in enumerate(SMARTSExpander.expand_iter(rxn)):
144
+ # if i < 3 or i > 621:
145
+ # print(f"{i+1}: {s}")
146
+ # n += 1
147
+ # print(f"Total: {n} enumerated SMARTS.")
@@ -0,0 +1,133 @@
1
+ import re
2
+ from typing import List, Set
3
+ from rdkit import Chem
4
+ from rdkit.Chem import rdChemReactions
5
+
6
+
7
+ class SMARTSGeneralizer:
8
+ """Generalizes a list of atom-mapped (reaction) SMARTS into one combinatorial SMARTS
9
+ with element-list placeholders at mapped atom positions.
10
+ Optionally validates output using RDKit.
11
+
12
+ :param sanity_check: If True, validate the output SMARTS with RDKit.
13
+ :type sanity_check: bool
14
+
15
+ .. rubric:: Example
16
+
17
+ >>> input_smarts = [
18
+ ... '[C:1]-[N:2]>>[N:1]-[C:2]',
19
+ ... '[N:1]-[N:2]>>[N:1]-[N:2]',
20
+ ... '[O:1]-[N:2]>>[N:1]-[N:2]'
21
+ ... ]
22
+ >>> gen = SMARTSGeneralizer()
23
+ >>> print(gen.generalize(input_smarts))
24
+ [C,N,O:1]-[N:2]>>[N:1]-[C,N,O:2]
25
+ """
26
+
27
+ _atom_pat = re.compile(r"\[([A-Z][a-z]?):(\d+)\]")
28
+
29
+ def __init__(self, sanity_check: bool = True):
30
+ """
31
+ Initialize SMARTSGeneralizer.
32
+
33
+ :param sanity_check: If True, validate the output SMARTS with RDKit.
34
+ :type sanity_check: bool
35
+ """
36
+ self.sanity_check = sanity_check
37
+
38
+ def generalize(self, smarts_list: List[str]) -> str:
39
+ """
40
+ Generalize a list of SMARTS/reaction SMARTS into one combinatorial SMARTS,
41
+ with element-list placeholders per atom-map index and position.
42
+
43
+ :param smarts_list: List of atom-mapped SMARTS strings (same topology/order).
44
+ :type smarts_list: list[str]
45
+ :return: Generalized SMARTS with atom-list placeholders.
46
+ :rtype: str
47
+ :raises ValueError: If input list is empty, topology is inconsistent, or output is invalid.
48
+ """
49
+ if not smarts_list:
50
+ raise ValueError("Input list is empty.")
51
+
52
+ if len(smarts_list) == 1:
53
+ combined = smarts_list[0]
54
+ else:
55
+ pos_list: List[List[re.Match]] = [
56
+ list(self._atom_pat.finditer(s)) for s in smarts_list
57
+ ]
58
+ n_atoms = len(pos_list[0])
59
+ for pl in pos_list:
60
+ if len(pl) != n_atoms:
61
+ raise ValueError(
62
+ "All input SMARTS must have same atom-mapped topology and order."
63
+ )
64
+
65
+ pos2map: List[str] = []
66
+ pos2elems: List[Set[str]] = []
67
+ for i in range(n_atoms):
68
+ mapnum = pos_list[0][i].group(2)
69
+ elems = set(match[i].group(1) for match in pos_list)
70
+ pos2map.append(mapnum)
71
+ pos2elems.append(elems)
72
+
73
+ # Template assembly: alternate static and atom-map segments
74
+ first = smarts_list[0]
75
+ atoms = list(self._atom_pat.finditer(first))
76
+ segments = []
77
+ last = 0
78
+ for m in atoms:
79
+ # fmt: off
80
+ segments.append(first[last: m.start()])
81
+ # fmt: on
82
+ segments.append(m.group(2)) # mapnum as marker
83
+ last = m.end()
84
+ segments.append(first[last:])
85
+
86
+ # Reconstruct combinatorial SMARTS
87
+ out = []
88
+ idx = 0
89
+ for seg in segments:
90
+ if idx < len(pos2map) and seg == pos2map[idx]:
91
+ els = sorted(pos2elems[idx])
92
+ out.append(f"[{','.join(els)}:{seg}]")
93
+ idx += 1
94
+ else:
95
+ out.append(seg)
96
+ combined = "".join(out)
97
+
98
+ # RDKit validation
99
+ if self.sanity_check:
100
+ if ">>" in combined:
101
+ rxn = rdChemReactions.ReactionFromSmarts(combined)
102
+ if rxn is None or rxn.GetNumProductTemplates() == 0:
103
+ raise ValueError(f"Invalid reaction SMARTS generated: {combined}")
104
+ else:
105
+ mol = Chem.MolFromSmarts(combined)
106
+ if mol is None:
107
+ raise ValueError(f"Invalid molecule SMARTS generated: {combined}")
108
+
109
+ return combined
110
+
111
+ def describe(self) -> None:
112
+ """
113
+ Print usage instructions and an example.
114
+
115
+ :return: None
116
+ """
117
+ print(
118
+ "SMARTSGeneralizer: Generalize a list of atom-mapped (reaction) SMARTS into a single "
119
+ "SMARTS with element-list placeholders at each mapped atom position.\n"
120
+ "Usage example:\n"
121
+ " >>> gen = SMARTSGeneralizer(sanity_check=True)\n"
122
+ " >>> smarts_list = ['[C:1]-[N:2]', '[O:1]-[N:2]', '[N:1]-[N:2]']\n"
123
+ " >>> print(gen.generalize(smarts_list)) # [C,N,O:1]-[N:2]"
124
+ )
125
+
126
+ def __repr__(self) -> str:
127
+ """
128
+ String representation.
129
+
130
+ :return: Description with current sanity_check setting.
131
+ :rtype: str
132
+ """
133
+ return f"SMARTSGeneralizer(sanity_check={self.sanity_check})"
@@ -0,0 +1,179 @@
1
+ import re
2
+ import networkx as nx
3
+ from typing import Optional, Set, Tuple, List, Dict
4
+
5
+ from rdkit import Chem
6
+
7
+
8
+ class SMARTSToGraph:
9
+ """Convert SMARTS or reaction SMARTS strings into NetworkX graphs with full atom and constraint data.
10
+
11
+ :param placeholder_labels: Optional set of labels to treat as placeholders (e.g., wildcard atoms).
12
+ :type placeholder_labels: Optional[Set[str]]
13
+ """
14
+
15
+ def __init__(self, placeholder_labels: Optional[Set[str]] = None) -> None:
16
+ """Initialize a SMARTSToGraph converter.
17
+
18
+ :param placeholder_labels: Set of placeholder labels used in SMARTS to identify wildcard positions.
19
+ Defaults to {'_R', 'X', 'Y', 'Z'} if None.
20
+ :type placeholder_labels: Optional[Set[str]]
21
+ :return: None
22
+ :rtype: None
23
+ """
24
+ self.placeholder_labels: Set[str] = placeholder_labels or {"_R", "X", "Y", "Z"}
25
+
26
+ @staticmethod
27
+ def _safe_total_hs(atom: "Chem.Atom") -> int:
28
+ """Compute the total number of hydrogens (explicit + implicit) for an RDKit Atom safely.
29
+
30
+ :param atom: RDKit Atom instance whose hydrogen count is desired.
31
+ :type atom: Chem.Atom
32
+ :return: Total hydrogen count for the atom.
33
+ :rtype: int
34
+ :raises Exception: If RDKit property cache update fails.
35
+
36
+ .. rubric:: Examples
37
+
38
+ >>> from rdkit import Chem
39
+ >>> atom = Chem.MolFromSmiles('C').GetAtomWithIdx(0)
40
+ >>> SMARTSToGraph._safe_total_hs(atom)
41
+ 3
42
+ """
43
+ try:
44
+ atom.UpdatePropertyCache(strict=False)
45
+ return int(atom.GetTotalNumHs(includeExplicit=True))
46
+ except Exception:
47
+ return 0
48
+
49
+ def smarts_to_graph(self, smarts: str) -> nx.Graph:
50
+ """Parse a SMARTS string into a NetworkX graph representation, extracting wildcard constraints.
51
+
52
+ :param smarts: SMARTS pattern to convert (e.g., '[C:1]C[O:2]').
53
+ :type smarts: str
54
+ :return: NetworkX Graph with:
55
+ - node attributes: element (str), charge (int), hcount (int),
56
+ label (str), constraint (Optional[List[str]]), atom_map (int)
57
+ - edge attributes: order (float), standard_order (float)
58
+ :rtype: nx.Graph
59
+ :raises ImportError: If RDKit is not available.
60
+ :raises ValueError: If the SMARTS string is invalid or atoms lack mapping numbers.
61
+
62
+ .. rubric:: Examples
63
+
64
+ >>> stg = SMARTSToGraph()
65
+ >>> graph = stg.smarts_to_graph('[CH3:1]-[OH:2]')
66
+ >>> graph.nodes[1]['element']
67
+ 'C'
68
+ >>> graph.nodes[2]['element']
69
+ 'O'
70
+ """
71
+ if Chem is None:
72
+ raise ImportError("RDKit is required for SMARTS parsing.")
73
+
74
+ # Pre-scan SMARTS for wildcard constraint lists (e.g., [C,N:5])
75
+ constraint_map: Dict[int, List[str]] = {}
76
+ for match in re.finditer(r"\[([^:\]]+?):(\d+)\]", smarts):
77
+ atom_expr, atom_idx = match.groups()
78
+ idx = int(atom_idx)
79
+ if "," in atom_expr:
80
+ constraint_map[idx] = [s.strip() for s in atom_expr.split(",")]
81
+
82
+ mol = Chem.MolFromSmarts(smarts)
83
+ if mol is None:
84
+ raise ValueError(f"Invalid SMARTS string: {smarts!r}")
85
+
86
+ G = nx.Graph()
87
+ idx_to_map: Dict[int, int] = {}
88
+
89
+ # Add nodes with full atom data
90
+ for atom in mol.GetAtoms():
91
+ amap = atom.GetAtomMapNum()
92
+ if amap == 0:
93
+ raise ValueError(
94
+ "All atoms in SMARTS must have a mapping number (atom map)."
95
+ )
96
+ idx_to_map[atom.GetIdx()] = amap
97
+
98
+ # Determine element, label, and constraints
99
+ raw_label = atom.GetSymbol()
100
+ if amap in constraint_map:
101
+ constraint = constraint_map[amap]
102
+ label = next(iter(self.placeholder_labels))
103
+ element = "*"
104
+ else:
105
+ constraint = None
106
+ label = raw_label
107
+ element = "*" if raw_label in self.placeholder_labels else raw_label
108
+
109
+ charge = atom.GetFormalCharge()
110
+ hcount = self._safe_total_hs(atom)
111
+
112
+ G.add_node(
113
+ amap,
114
+ element=element,
115
+ charge=charge,
116
+ hcount=hcount,
117
+ label=label,
118
+ constraint=constraint,
119
+ atom_map=amap,
120
+ )
121
+
122
+ # Add edges with bond order data
123
+ for bond in mol.GetBonds():
124
+ u = idx_to_map[bond.GetBeginAtomIdx()]
125
+ v = idx_to_map[bond.GetEndAtomIdx()]
126
+ order = bond.GetBondTypeAsDouble()
127
+ G.add_edge(u, v, order=order, standard_order=order)
128
+
129
+ return G
130
+
131
+ def rxn_smarts_to_graphs(self, rxn: str) -> Tuple[nx.Graph, nx.Graph]:
132
+ """Split a reaction SMARTS into separate reactant and product graphs.
133
+
134
+ :param rxn: Reaction SMARTS in the format 'reactants>>products'.
135
+ :type rxn: str
136
+ :return: Tuple of (reactant_graph, product_graph).
137
+ :rtype: Tuple[nx.Graph, nx.Graph]
138
+ :raises ValueError: If the reaction SMARTS string does not contain '>>'.
139
+
140
+ .. rubric:: Examples
141
+
142
+ >>> stg = SMARTSToGraph()
143
+ >>> react, prod = stg.rxn_smarts_to_graphs('[CH3:1]-[OH:2]>>[CH2:1]=[O:2]')
144
+ >>> react.nodes
145
+ [1, 2]
146
+ >>> prod.nodes
147
+ [1, 2]
148
+ """
149
+ if ">>" not in rxn:
150
+ raise ValueError("Reaction SMARTS must contain '>>' separator.")
151
+ lhs, rhs = rxn.split(">>", 1)
152
+ return self.smarts_to_graph(lhs), self.smarts_to_graph(rhs)
153
+
154
+ def __repr__(self) -> str:
155
+ """Return an unambiguous string representation of this converter.
156
+
157
+ :return: Representation of the instance showing placeholder labels.
158
+ :rtype: str
159
+ """
160
+ return f"<SMARTSToGraph placeholders={self.placeholder_labels}>"
161
+
162
+ def describe(self) -> str:
163
+ """Provide a usage summary for SMARTSToGraph.
164
+
165
+ :return: Multi-line string explaining available methods and usage.
166
+ :rtype: str
167
+
168
+ .. rubric:: Examples
169
+
170
+ >>> print(SMARTSToGraph().describe())
171
+ SMARTSToGraph(placeholder_labels=None)
172
+ smarts_to_graph(smarts_str) -> Graph
173
+ rxn_smarts_to_graphs(rxn_smarts) -> (Graph_react, Graph_prod)
174
+ """
175
+ return (
176
+ "SMARTSToGraph(placeholder_labels=None)\n"
177
+ " smarts_to_graph(smarts_str) -> Graph\n"
178
+ " rxn_smarts_to_graphs(rxn_smarts) -> (Graph_react, Graph_prod)\n"
179
+ )
@@ -0,0 +1,42 @@
1
+ """High-level conversion entry points.
2
+
3
+ This module provides I/O-facing access to conversions whose implementation
4
+ belongs to a domain-specific SynKit package.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Optional
10
+
11
+
12
+ def ef_smirks_to_epd(
13
+ ef_smirks: str,
14
+ orbital_class: Optional[str] = None,
15
+ strict_bond_lookup: bool = True,
16
+ ) -> dict[str, Any]:
17
+ """Complete AAM and convert EF-SMIRKS text into generic and typed EPD.
18
+
19
+ See :func:`synkit.Graph.Mech.conversion.ef_smirks_to_epd` for the
20
+ EF-SMIRKS input format and returned fields.
21
+ """
22
+ from synkit.Graph.Mech.conversion import ef_smirks_to_epd as _convert
23
+
24
+ return _convert(
25
+ ef_smirks,
26
+ orbital_class=orbital_class,
27
+ strict_bond_lookup=strict_bond_lookup,
28
+ )
29
+
30
+
31
+ def epd_to_ef_smirks(complete_aam: str, epd: list[list[Any]]) -> str:
32
+ """Convert complete atom-mapped RSMI and EPD records into EF-SMIRKS.
33
+
34
+ See :func:`synkit.Graph.Mech.conversion.epd_to_ef_smirks` for accepted
35
+ generic and typed EPD records.
36
+ """
37
+ from synkit.Graph.Mech.conversion import epd_to_ef_smirks as _convert
38
+
39
+ return _convert(complete_aam, epd)
40
+
41
+
42
+ __all__ = ["ef_smirks_to_epd", "epd_to_ef_smirks"]