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,207 @@
1
+ from rdkit import Chem
2
+ from joblib import Parallel, delayed
3
+ from typing import Dict, Any, List, Union, Tuple, Optional
4
+
5
+
6
+ class Neutralize:
7
+ """Neutralize unbalanced charges in chemical reactions by adding
8
+ counter‑ions.
9
+
10
+ Provides utilities to calculate formal charges, parse reaction
11
+ SMILES, and adjust reactants/products with [Na+] or [Cl‑] to restore
12
+ neutrality.
13
+ """
14
+
15
+ @staticmethod
16
+ def calculate_charge(smiles: str) -> int:
17
+ """Calculate the formal charge of a molecule.
18
+
19
+ :param smiles: SMILES string of the molecule.
20
+ :type smiles: str
21
+ :return: Formal charge of the molecule (0 if invalid SMILES).
22
+ :rtype: int
23
+ """
24
+ mol = Chem.MolFromSmiles(smiles)
25
+ if mol is None:
26
+ return 0
27
+ return Chem.rdmolops.GetFormalCharge(mol)
28
+
29
+ @staticmethod
30
+ def parse_reaction(reaction_smiles: str) -> Tuple[Optional[str], Optional[str]]:
31
+ """Split a reaction SMILES into reactants and products.
32
+
33
+ :param reaction_smiles: Reaction SMILES in 'reactants>>products'
34
+ format.
35
+ :type reaction_smiles: str
36
+ :return: Tuple of (reactants, products) SMILES, or (None, None)
37
+ if parse fails.
38
+ :rtype: Tuple[Optional[str], Optional[str]]
39
+ """
40
+ try:
41
+ reactants, products = reaction_smiles.split(">>")
42
+ return reactants, products
43
+ except ValueError:
44
+ return None, None
45
+
46
+ @staticmethod
47
+ def calculate_charge_dict(
48
+ reaction: Dict[str, Any], reaction_column: str
49
+ ) -> Dict[str, Union[str, int]]:
50
+ """Compute and store the total formal charge of the products in a
51
+ reaction dict.
52
+
53
+ :param reaction: Dictionary containing at least `reaction_column` with a reaction SMILES.
54
+ :type reaction: Dict[str, Any]
55
+ :param reaction_column: Key under which the reaction SMILES is stored.
56
+ :type reaction_column: str
57
+ :return: The same dictionary updated with:
58
+ - 'reactants': reactant SMILES or None
59
+ - 'products': product SMILES or None
60
+ - 'total_charge_in_products': integer sum of product charges or None
61
+ :rtype: Dict[str, Union[str, int]]
62
+ """
63
+ reactants, products = Neutralize.parse_reaction(
64
+ reaction.get(reaction_column, "")
65
+ )
66
+ if reactants is None or products is None:
67
+ reaction.update(
68
+ {"reactants": None, "products": None, "total_charge_in_products": None}
69
+ )
70
+ else:
71
+ reaction["reactants"] = reactants
72
+ reaction["products"] = products
73
+ total = sum(Neutralize.calculate_charge(p) for p in products.split("."))
74
+ reaction["total_charge_in_products"] = total
75
+ return reaction
76
+
77
+ @staticmethod
78
+ def fix_negative_charge(
79
+ reaction_dict: Dict[str, Any],
80
+ charges_column: str = "total_charge_in_products",
81
+ id_column: str = "R-id",
82
+ reaction_column: str = "reactions",
83
+ ) -> Dict[str, Any]:
84
+ """Add [Na+] ions to neutralize negative product charge.
85
+
86
+ :param reaction_dict: Dictionary with 'reactants', 'products', and charge info.
87
+ :type reaction_dict: Dict[str, Any]
88
+ :param charges_column: Key for product total charge. Defaults to 'total_charge_in_products'.
89
+ :type charges_column: str
90
+ :param id_column: Key for reaction identifier. Defaults to 'R-id'.
91
+ :type id_column: str
92
+ :param reaction_column: Key for reaction SMILES to update. Defaults to 'reactions'.
93
+ :type reaction_column: str
94
+ :return: New dictionary with:
95
+ - updated `reaction_column` including added [Na+] ions
96
+ - 'reactants' and 'products' with ions appended
97
+ - charge column set to 0
98
+ :rtype: Dict[str, Any]
99
+ """
100
+ num_to_add = abs(reaction_dict.get(charges_column, 0))
101
+ sodium = "[Na+]"
102
+ addition = ("." + ".".join([sodium] * num_to_add)) if num_to_add else ""
103
+ new_react = reaction_dict["reactants"] + addition
104
+ new_prod = reaction_dict["products"] + addition
105
+ new_reaction = f"{new_react}>>{new_prod}"
106
+
107
+ reaction_dict.update(
108
+ {
109
+ id_column: reaction_dict.get(id_column),
110
+ reaction_column: new_reaction,
111
+ "reactants": new_react,
112
+ "products": new_prod,
113
+ charges_column: 0,
114
+ }
115
+ )
116
+ return reaction_dict
117
+
118
+ @staticmethod
119
+ def fix_positive_charge(
120
+ reaction_dict: Dict[str, Any],
121
+ charges_column: str = "total_charge_in_products",
122
+ id_column: str = "R-id",
123
+ reaction_column: str = "reactions",
124
+ ) -> Dict[str, Any]:
125
+ """Add [Cl‑] ions to neutralize positive product charge.
126
+
127
+ :param reaction_dict: Dictionary with 'reactants', 'products', and charge info.
128
+ :type reaction_dict: Dict[str, Any]
129
+ :param charges_column: Key for product total charge. Defaults to 'total_charge_in_products'.
130
+ :type charges_column: str
131
+ :param id_column: Key for reaction identifier. Defaults to 'R-id'.
132
+ :type id_column: str
133
+ :param reaction_column: Key for reaction SMILES to update. Defaults to 'reactions'.
134
+ :type reaction_column: str
135
+ :return: New dictionary with:
136
+ - updated `reaction_column` including added [Cl‑] ions
137
+ - 'reactants' and 'products' with ions appended
138
+ - charge column set to 0
139
+ :rtype: Dict[str, Any]
140
+ """
141
+ num_to_add = abs(reaction_dict.get(charges_column, 0))
142
+ chloride = "[Cl-]"
143
+ addition = ("." + ".".join([chloride] * num_to_add)) if num_to_add else ""
144
+ new_react = reaction_dict["reactants"] + addition
145
+ new_prod = reaction_dict["products"] + addition
146
+ new_reaction = f"{new_react}>>{new_prod}"
147
+ reaction_dict.update(
148
+ {
149
+ id_column: reaction_dict.get(id_column),
150
+ reaction_column: new_reaction,
151
+ "reactants": new_react,
152
+ "products": new_prod,
153
+ charges_column: 0,
154
+ }
155
+ )
156
+ return reaction_dict
157
+
158
+ @staticmethod
159
+ def fix_unbalanced_charged(
160
+ reaction_dict: Dict[str, Any],
161
+ reaction_column: str,
162
+ ) -> Dict[str, Any]:
163
+ """Detect and neutralize unbalanced product charge by adding
164
+ counter‑ions.
165
+
166
+ :param reaction_dict: Dictionary with raw reaction SMILES under `reaction_column`.
167
+ :type reaction_dict: Dict[str, Any]
168
+ :param reaction_column: Key for reaction SMILES in the input dict.
169
+ :type reaction_column: str
170
+ :return: Dictionary with balanced charges and updated SMILES.
171
+ :rtype: Dict[str, Any]
172
+ """
173
+ rd = Neutralize.calculate_charge_dict(reaction_dict, reaction_column)
174
+ total = rd.get("total_charge_in_products", 0)
175
+ if total > 0:
176
+ return Neutralize.fix_positive_charge(rd)
177
+ if total < 0:
178
+ return Neutralize.fix_negative_charge(rd)
179
+ return rd
180
+
181
+ @classmethod
182
+ def parallel_fix_unbalanced_charge(
183
+ cls,
184
+ reaction_dicts: List[Dict[str, Any]],
185
+ reaction_column: str,
186
+ n_jobs: int = 4,
187
+ ) -> List[Dict[str, Any]]:
188
+ """Neutralize charges in multiple reaction dictionaries in parallel.
189
+
190
+ :param reaction_dicts: List of reaction dictionaries to process.
191
+ :type reaction_dicts: List[Dict[str, Any]]
192
+ :param reaction_column: Key for reaction SMILES in each dict.
193
+ :type reaction_column: str
194
+ :param n_jobs: Number of parallel jobs (use -1 for all cores).
195
+ Defaults to 4.
196
+ :type n_jobs: int
197
+ :return: List of dictionaries with balanced charges and updated
198
+ SMILES.
199
+ :rtype: List[Dict[str, Any]]
200
+ """
201
+ return Parallel(n_jobs=n_jobs)(
202
+ delayed(cls.fix_unbalanced_charged)(
203
+ d,
204
+ reaction_column,
205
+ )
206
+ for d in reaction_dicts
207
+ )
@@ -0,0 +1,224 @@
1
+ from rdkit import Chem
2
+ from rdkit.Chem import SanitizeFlags
3
+ import re
4
+ from typing import Tuple, List, Optional, Dict
5
+
6
+
7
+ def clean_wc(
8
+ rsmi: str, invert: bool = False, max_frag: bool = False, wild_card: bool = True
9
+ ) -> str:
10
+ """Clean wildcard-containing fragments from one side of a reaction SMILES,
11
+ optionally selecting the largest remaining fragment.
12
+
13
+ :param rsmi: Reaction SMILES string in the form 'R>>P'.
14
+ :type rsmi: str
15
+ :param invert: If True, process the reactant side; otherwise the product side.
16
+ :type invert: bool
17
+ :param max_frag: If True, force fragment selection (implies wild_card=True).
18
+ :type max_frag: bool
19
+ :param wild_card: If True, remove fragments containing '*' before selection.
20
+ :type wild_card: bool
21
+ :return: The processed reaction SMILES.
22
+ :rtype: str
23
+ :raises ValueError: If input does not split into reactant and product.
24
+
25
+ .. rubric:: Example
26
+
27
+ >>> clean_wc('A.B>>C.*', invert=False, wild_card=True)
28
+ 'A.B>>C'
29
+ >>> clean_wc('A.B>>C.D', invert=False, max_frag=True)
30
+ 'A.B>>C'
31
+ """
32
+ # Ensure max_frag implies wild_card
33
+ if max_frag:
34
+ wild_card = True
35
+
36
+ # Split into reactant and product
37
+ parts = rsmi.split(">>")
38
+ if len(parts) != 2:
39
+ raise ValueError("Reaction SMILES must contain exactly one '>>'.")
40
+ react, prod = parts
41
+
42
+ # Select side to process
43
+ side = react if invert else prod
44
+
45
+ processed = side
46
+ if wild_card:
47
+ frags = side.split(".")
48
+ # Filter out fragments containing wildcards
49
+ filtered = [frag for frag in frags if "*" not in frag]
50
+ if len(filtered) > 1:
51
+ # select the longest fragment
52
+ processed = max(filtered, key=len)
53
+ elif len(filtered) == 1:
54
+ processed = filtered[0]
55
+ # if no filtered fragments or single fragment, keep original side
56
+
57
+ # Reconstruct and return
58
+ if invert:
59
+ return f"{processed}>>{prod}"
60
+ return f"{react}>>{processed}"
61
+
62
+
63
+ class RadicalWildcardAdder:
64
+ """A utility for adding wildcard dummy atoms ([*]) to radical centers in
65
+ reaction SMILES, with unique incremental atom-map indices and correct
66
+ propagation into products.
67
+
68
+ Each reactive radical atom in the reactant block is identified by its unpaired electron count,
69
+ assigned one or more wildcard map indices, and recorded. The same wildcard(s) are then appended
70
+ to the corresponding atom(s) in the product block, ensuring consistent mapping.
71
+
72
+ :param start_map: If provided, this integer will be the first atom-map index
73
+ used for wildcard dummy atoms; subsequent radicals get incremented indices.
74
+ If None, the next unused index is auto-determined from the input SMILES.
75
+ :type start_map: Optional[int]
76
+
77
+ .. rubric:: Example
78
+
79
+ >>> adder = RadicalWildcardAdder(start_map=8)
80
+ >>> rxn = "[C:2][OH:4].[O:6][H:7]>>[C:2][O:6].[OH:4][H:7]"
81
+ >>> print(adder.transform(rxn))
82
+ [C:2]([OH:4])[*:8].[O:6]([H:7])[*:9]>>[C:2]([O:6][*:9])[*:8].[OH:4][H:7]
83
+ """
84
+
85
+ def __init__(self, start_map: Optional[int] = None) -> None:
86
+ """Initialize the adder with an optional starting map index.
87
+
88
+ :param start_map: Starting atom-map index for wildcards or None
89
+ to auto-pick.
90
+ :type start_map: Optional[int]
91
+ """
92
+ self.start_map = start_map
93
+
94
+ def __repr__(self) -> str:
95
+ """Official representation."""
96
+ return f"<RadicalWildcardAdder(start_map={self.start_map})>"
97
+
98
+ def __str__(self) -> str:
99
+ """User-friendly description."""
100
+ m = self.start_map if self.start_map is not None else "auto"
101
+ return f"RadicalWildcardAdder(start_map={m})"
102
+
103
+ def transform(self, rxn_smiles: str) -> str:
104
+ """Append wildcard dummy atoms to each radical center in the reactant
105
+ block and propagate the same wildcards to the matching atoms in the
106
+ product block.
107
+
108
+ :param rxn_smiles: Reaction SMILES string, two-component or
109
+ three-component.
110
+ :type rxn_smiles: str
111
+ :return: Modified reaction SMILES with consistent wildcard
112
+ attachments.
113
+ :rtype: str
114
+ :raises ValueError: If the SMILES is not valid or fragments fail
115
+ to parse.
116
+ """
117
+ # Split into reactants > agents? > products
118
+ react_blk, agents_blk, prod_blk = self._split_reaction(rxn_smiles)
119
+
120
+ # Determine first wildcard map index
121
+ existing = [int(n) for n in re.findall(r":(\d+)", rxn_smiles)]
122
+ next_map = (
123
+ self.start_map
124
+ if self.start_map is not None
125
+ else max(existing, default=0) + 1
126
+ )
127
+
128
+ # Record mapping: original atom-map -> list of wildcard_maps
129
+ wildcard_map_for: Dict[int, List[int]] = {}
130
+
131
+ # Build sanitizeOps mask (skip H-adjustment)
132
+ keep_ops = SanitizeFlags.SANITIZE_ADJUSTHS
133
+
134
+ # Process one block (helper)
135
+ def _process(frags: List[str], propagate: bool) -> List[str]:
136
+ nonlocal next_map
137
+ out = []
138
+ for smi in frags:
139
+ if not smi:
140
+ continue
141
+ # Load unsanitized then re-sanitize to preserve explicit H
142
+ # mol = Chem.MolFromSmiles(smi, sanitize=False)
143
+ # if mol is None:
144
+ # raise ValueError(f"Cannot parse SMILES fragment: {smi}")
145
+ # Chem.SanitizeMol(mol, sanitizeOps=keep_ops)
146
+ mol = Chem.MolFromSmiles(smi, sanitize=False)
147
+ Chem.SanitizeMol(mol)
148
+ rw = Chem.RWMol(mol)
149
+
150
+ atoms = list(rw.GetAtoms())
151
+ changed = False
152
+
153
+ for atom in atoms:
154
+ rad = atom.GetNumRadicalElectrons()
155
+ orig_map = atom.GetAtomMapNum()
156
+ if rad > 0:
157
+ # Initialize list for this orig_map
158
+ if propagate and orig_map not in wildcard_map_for:
159
+ wildcard_map_for[orig_map] = []
160
+ # For each unpaired electron, attach a wildcard
161
+ for _ in range(rad):
162
+ if propagate:
163
+ wm = next_map
164
+ wildcard_map_for[orig_map].append(wm)
165
+ next_map += 1
166
+ else:
167
+ # in products, use already-recorded wm sequentially
168
+ wm_list = wildcard_map_for.get(orig_map, [])
169
+ if not wm_list:
170
+ continue
171
+ wm = wm_list.pop(0)
172
+ # add dummy wildcard
173
+ dummy = Chem.Atom(0)
174
+ dummy.SetAtomMapNum(wm)
175
+ dummy.SetNoImplicit(True)
176
+ rw.AddAtom(dummy)
177
+ rw.AddBond(
178
+ atom.GetIdx(),
179
+ rw.GetNumAtoms() - 1,
180
+ Chem.BondType.SINGLE,
181
+ )
182
+ changed = True
183
+
184
+ if changed:
185
+ Chem.SanitizeMol(rw.GetMol(), sanitizeOps=keep_ops)
186
+
187
+ out.append(
188
+ Chem.MolToSmiles(
189
+ rw.GetMol(), isomericSmiles=True, allHsExplicit=True
190
+ )
191
+ )
192
+ return out
193
+
194
+ react_frags = react_blk.split(".") if react_blk else []
195
+ new_reacts = _process(react_frags, propagate=True)
196
+
197
+ prod_frags = prod_blk.split(".") if prod_blk else []
198
+ new_prods = _process(prod_frags, propagate=False)
199
+
200
+ react_str = ".".join(new_reacts)
201
+ prod_str = ".".join(new_prods)
202
+ if agents_blk is None:
203
+ return f"{react_str}>>{prod_str}"
204
+ return f"{react_str}>{agents_blk}>{prod_str}"
205
+
206
+ @staticmethod
207
+ def _split_reaction(rxn: str) -> Tuple[str, Optional[str], str]:
208
+ """Split a reaction SMILES into reactants, agents (optional), and
209
+ products.
210
+
211
+ :param rxn: The reaction SMILES string.
212
+ :type rxn: str
213
+ :return: Tuple of (reactants_block, agents_block or None,
214
+ products_block).
215
+ :rtype: Tuple[str, Optional[str], str]
216
+ :raises ValueError: If the SMILES does not contain 2 or 3 '>'
217
+ symbols.
218
+ """
219
+ parts = rxn.split(">")
220
+ if len(parts) == 2:
221
+ return parts[0], None, parts[1]
222
+ if len(parts) == 3:
223
+ return parts[0], parts[1], parts[2]
224
+ raise ValueError("Reaction SMILES must contain 2 or 3 '>' symbols")
@@ -0,0 +1,203 @@
1
+ from typing import List, Optional, Tuple
2
+ from rdkit import Chem
3
+
4
+
5
+ class Standardize:
6
+ """Utilities to normalize and filter reaction and molecule SMILES.
7
+
8
+ This class provides methods to remove atom‑mapping, filter invalid molecules,
9
+ canonicalize reaction SMILES, and a full pipeline via `fit`.
10
+
11
+ :ivar None: Stateless helper class.
12
+ """
13
+
14
+ def __init__(self) -> None:
15
+ """Initialize the Standardize helper.
16
+
17
+ No instance attributes are set.
18
+ """
19
+ pass
20
+
21
+ @staticmethod
22
+ def remove_atom_mapping(reaction_smiles: str, symbol: str = ">>") -> str:
23
+ """Remove atom‑map numbers from a reaction SMILES string.
24
+
25
+ :param reaction_smiles: Reaction SMILES with atom maps, e.g.
26
+ 'C[CH3:1]>>C'.
27
+ :type reaction_smiles: str
28
+ :param symbol: Separator between reactants and products.
29
+ Defaults to '>>'.
30
+ :type symbol: str
31
+ :return: Reaction SMILES without atom‑mapping annotations.
32
+ :rtype: str
33
+ :raises ValueError: If the input format is invalid or contains
34
+ invalid SMILES.
35
+ """
36
+ parts = reaction_smiles.split(symbol)
37
+ if len(parts) != 2:
38
+ raise ValueError(
39
+ "Invalid reaction SMILES format. Expected 'reactants>>products'."
40
+ )
41
+
42
+ def clean_smiles(smi: str) -> str:
43
+ mol = Chem.MolFromSmiles(smi)
44
+ if mol is None:
45
+ raise ValueError(f"Invalid SMILES string: {smi}")
46
+ for atom in mol.GetAtoms():
47
+ atom.SetAtomMapNum(0)
48
+ return Chem.MolToSmiles(mol, canonical=True)
49
+
50
+ react, prod = map(clean_smiles, parts)
51
+ return f"{react}{symbol}{prod}"
52
+
53
+ @staticmethod
54
+ def filter_valid_molecules(smiles_list: List[str]) -> List[Chem.Mol]:
55
+ """Filter and sanitize a list of SMILES, returning only valid Mol
56
+ objects.
57
+
58
+ :param smiles_list: List of SMILES strings to validate.
59
+ :type smiles_list: List[str]
60
+ :return: List of sanitized RDKit Mol objects.
61
+ :rtype: List[rdkit.Chem.Mol]
62
+ """
63
+ valid: List[Chem.Mol] = []
64
+ for smi in smiles_list:
65
+ mol = Chem.MolFromSmiles(smi, sanitize=False)
66
+ if mol:
67
+ try:
68
+ Chem.SanitizeMol(mol)
69
+ valid.append(mol)
70
+ except Exception:
71
+ continue
72
+ return valid
73
+
74
+ @staticmethod
75
+ def _parse_molecule_fragments(
76
+ smiles_list: List[str],
77
+ ) -> Tuple[List[Chem.Mol], bool]:
78
+ """Parse and sanitize SMILES fragments.
79
+
80
+ :param smiles_list: List of SMILES strings to validate.
81
+ :type smiles_list: List[str]
82
+ :return: Tuple of valid molecules and whether any fragment was invalid.
83
+ :rtype: Tuple[List[rdkit.Chem.Mol], bool]
84
+ """
85
+ valid: List[Chem.Mol] = []
86
+ had_invalid = False
87
+ for smi in smiles_list:
88
+ mol = Chem.MolFromSmiles(smi, sanitize=False)
89
+ if mol:
90
+ try:
91
+ Chem.SanitizeMol(mol)
92
+ valid.append(mol)
93
+ except Exception:
94
+ had_invalid = True
95
+ else:
96
+ had_invalid = True
97
+ return valid, had_invalid
98
+
99
+ @staticmethod
100
+ def standardize_rsmi(
101
+ rsmi: str, stereo: bool = False, remove_invalid: bool = True
102
+ ) -> Optional[str]:
103
+ """Normalize a reaction SMILES: validate molecules, sort fragments, optionally keep stereo.
104
+
105
+ :param rsmi: Reaction SMILES in 'reactants>>products' format.
106
+ :type rsmi: str
107
+ :param stereo: If True, include stereochemistry in the output. Defaults to False.
108
+ :type stereo: bool
109
+ :param remove_invalid: If True, drop invalid fragments and standardize
110
+ remaining molecules. If False, return None when any invalid fragment
111
+ exists. Defaults to True.
112
+ :type remove_invalid: bool
113
+ :return: Standardized reaction SMILES or None if no valid molecules remain.
114
+ :rtype: Optional[str]
115
+ :raises ValueError: If the input format is invalid.
116
+ """
117
+ try:
118
+ react_str, prod_str = rsmi.split(">>")
119
+ except ValueError:
120
+ raise ValueError(
121
+ "Invalid reaction SMILES format. Expected 'reactants>>products'."
122
+ )
123
+
124
+ react_mols, react_invalid = Standardize._parse_molecule_fragments(
125
+ react_str.split(".")
126
+ )
127
+ prod_mols, prod_invalid = Standardize._parse_molecule_fragments(
128
+ prod_str.split(".")
129
+ )
130
+
131
+ if not remove_invalid and (react_invalid or prod_invalid):
132
+ return None
133
+
134
+ if not react_mols or not prod_mols:
135
+ return None
136
+
137
+ sorted_react = ".".join(
138
+ sorted(Chem.MolToSmiles(m, isomericSmiles=stereo) for m in react_mols)
139
+ )
140
+ sorted_prod = ".".join(
141
+ sorted(Chem.MolToSmiles(m, isomericSmiles=stereo) for m in prod_mols)
142
+ )
143
+
144
+ return f"{sorted_react}>>{sorted_prod}"
145
+
146
+ def fit(
147
+ self,
148
+ rsmi: str,
149
+ remove_aam: bool = True,
150
+ ignore_stereo: bool = True,
151
+ remove_invalid: bool = True,
152
+ ) -> Optional[str]:
153
+ """Full standardization pipeline: strip atom‑mapping, normalize SMILES, fix hydrogen notation.
154
+
155
+ :param rsmi: Reaction SMILES to process.
156
+ :type rsmi: str
157
+ :param remove_aam: If True, remove atom‑mapping annotations. Defaults to True.
158
+ :type remove_aam: bool
159
+ :param ignore_stereo: If True, drop stereochemistry. Defaults to True.
160
+ :type ignore_stereo: bool
161
+ :param remove_invalid: If True, drop invalid fragments and standardize
162
+ remaining molecules. If False, return None when any invalid fragment
163
+ exists. Defaults to True.
164
+ :type remove_invalid: bool
165
+ :return: The standardized reaction SMILES, or None if standardization fails.
166
+ :rtype: Optional[str]
167
+ """
168
+ std = self.standardize_rsmi(
169
+ rsmi, stereo=not ignore_stereo, remove_invalid=remove_invalid
170
+ )
171
+ if std is None:
172
+ return None
173
+
174
+ if remove_aam:
175
+ std = self.remove_atom_mapping(std)
176
+
177
+ # Format any double‑hydrogen notation
178
+ return std.replace("[HH]", "[H][H]")
179
+
180
+ @staticmethod
181
+ def categorize_reactions(
182
+ reactions: List[str], target_reaction: str
183
+ ) -> Tuple[List[str], List[str]]:
184
+ """Partition reactions into those matching a target and those not.
185
+
186
+ :param reactions: List of reaction SMILES to categorize.
187
+ :type reactions: List[str]
188
+ :param target_reaction: Benchmark reaction SMILES for comparison.
189
+ :type target_reaction: str
190
+ :return: Tuple of (matches, non_matches):
191
+ - matches: reactions equal to standardized target
192
+ - non_matches: all others
193
+ :rtype: Tuple[List[str], List[str]]
194
+ """
195
+ tgt = Standardize.standardize_rsmi(target_reaction, stereo=False)
196
+ matches: List[str] = []
197
+ non_matches: List[str] = []
198
+ for rxn in reactions:
199
+ if rxn == tgt:
200
+ matches.append(rxn)
201
+ else:
202
+ non_matches.append(rxn)
203
+ return matches, non_matches