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,503 @@
1
+ """Configured extended-stereo evidence derived from validated 3D geometry.
2
+
3
+ Coordinates determine orientation only. They do not establish a rotational
4
+ barrier, configurational stability, or whether an axis is an authorized
5
+ stereogenic carrier.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from math import sqrt
11
+ from typing import Any
12
+
13
+ from rdkit import Chem
14
+
15
+ from synkit.Graph.Stereo import (
16
+ AtropBondStereo,
17
+ AxisStereoSupport,
18
+ CumuleneAxisStereo,
19
+ ExtendedCisTransStereo,
20
+ HelicalStereo,
21
+ PathStereoSupport,
22
+ PlanarBondStereo,
23
+ TetrahedralStereo,
24
+ parse_virtual_reference,
25
+ virtual_reference,
26
+ )
27
+
28
+
29
+ def _vector(left: Any, right: Any) -> tuple[float, float, float]:
30
+ return (
31
+ float(right.x - left.x),
32
+ float(right.y - left.y),
33
+ float(right.z - left.z),
34
+ )
35
+
36
+
37
+ def _cross(
38
+ left: tuple[float, float, float],
39
+ right: tuple[float, float, float],
40
+ ) -> tuple[float, float, float]:
41
+ return (
42
+ left[1] * right[2] - left[2] * right[1],
43
+ left[2] * right[0] - left[0] * right[2],
44
+ left[0] * right[1] - left[1] * right[0],
45
+ )
46
+
47
+
48
+ def _dot(
49
+ left: tuple[float, float, float],
50
+ right: tuple[float, float, float],
51
+ ) -> float:
52
+ return sum(a * b for a, b in zip(left, right))
53
+
54
+
55
+ def _norm(value: tuple[float, float, float]) -> float:
56
+ return sqrt(_dot(value, value))
57
+
58
+
59
+ def _scale(
60
+ value: tuple[float, float, float],
61
+ factor: float,
62
+ ) -> tuple[float, float, float]:
63
+ return tuple(factor * item for item in value) # type: ignore[return-value]
64
+
65
+
66
+ def _subtract(
67
+ left: tuple[float, float, float],
68
+ right: tuple[float, float, float],
69
+ ) -> tuple[float, float, float]:
70
+ return tuple(a - b for a, b in zip(left, right)) # type: ignore[return-value]
71
+
72
+
73
+ def _project_perpendicular(
74
+ value: tuple[float, float, float],
75
+ axis: tuple[float, float, float],
76
+ ) -> tuple[float, float, float]:
77
+ axis_norm = _norm(axis)
78
+ if axis_norm == 0.0:
79
+ return (0.0, 0.0, 0.0)
80
+ unit = _scale(axis, 1.0 / axis_norm)
81
+ return _subtract(value, _scale(unit, _dot(value, unit)))
82
+
83
+
84
+ def _terminal_projection(
85
+ molecule: Chem.Mol,
86
+ *,
87
+ owner: int,
88
+ frame: tuple[int | str, int | str],
89
+ reference: int | str,
90
+ axis: tuple[float, float, float],
91
+ conformer_id: int,
92
+ ) -> tuple[float, float, float]:
93
+ conformer = molecule.GetConformer(conformer_id)
94
+ owner_point = conformer.GetAtomPosition(owner)
95
+ if type(reference) is int:
96
+ return _project_perpendicular(
97
+ _vector(owner_point, conformer.GetAtomPosition(reference)),
98
+ axis,
99
+ )
100
+ virtual = parse_virtual_reference(reference)
101
+ if virtual is None or virtual.kind != "H" or virtual.center != owner:
102
+ raise ValueError(
103
+ "Coordinate terminal frames support material atoms and virtual H."
104
+ )
105
+ material = next(
106
+ (item for item in frame if type(item) is int),
107
+ None,
108
+ )
109
+ if material is None:
110
+ raise ValueError("A virtual terminal reference requires a material partner.")
111
+ material_projection = _project_perpendicular(
112
+ _vector(owner_point, conformer.GetAtomPosition(material)),
113
+ axis,
114
+ )
115
+ return _scale(material_projection, -1.0)
116
+
117
+
118
+ def normalized_atrop_oriented_volume(
119
+ molecule: Chem.Mol,
120
+ support: AxisStereoSupport,
121
+ *,
122
+ conformer_id: int = -1,
123
+ ) -> float:
124
+ """Return a proper-motion-invariant, reflection-sensitive axis volume."""
125
+ if molecule is None:
126
+ raise ValueError("Atrop geometry requires a molecule.")
127
+ if len(support.path) != 2:
128
+ raise ValueError("Atrop geometry requires a two-atom axis.")
129
+ references = tuple(
130
+ reference for frame in support.terminal_frames for reference in frame
131
+ )
132
+ if any(type(reference) is not int for reference in references):
133
+ raise ValueError("Atrop coordinate evidence requires material references.")
134
+ required = set(support.path) | set(references)
135
+ if min(required) < 0 or max(required) >= molecule.GetNumAtoms():
136
+ raise ValueError("Atrop coordinate evidence references an absent atom.")
137
+ conformer = molecule.GetConformer(conformer_id)
138
+ left, right = support.path
139
+ left_frame, right_frame = support.terminal_frames
140
+ left_point = conformer.GetAtomPosition(left)
141
+ right_point = conformer.GetAtomPosition(right)
142
+ axis = _vector(left_point, right_point)
143
+ left_vector = _vector(
144
+ left_point,
145
+ conformer.GetAtomPosition(left_frame[0]), # type: ignore[arg-type]
146
+ )
147
+ right_vector = _vector(
148
+ right_point,
149
+ conformer.GetAtomPosition(right_frame[0]), # type: ignore[arg-type]
150
+ )
151
+ denominator = _norm(axis) * _norm(left_vector) * _norm(right_vector)
152
+ if denominator == 0.0:
153
+ return 0.0
154
+ return _dot(axis, _cross(left_vector, right_vector)) / denominator
155
+
156
+
157
+ def atrop_stereo_from_geometry(
158
+ molecule: Chem.Mol,
159
+ support: AxisStereoSupport,
160
+ *,
161
+ conformer_id: int = -1,
162
+ minimum_oriented_volume: float = 1.0e-5,
163
+ provenance: str = "validated_geometry",
164
+ ) -> AtropBondStereo:
165
+ """Configure one already-authorized atrop support from 3D coordinates.
166
+
167
+ The caller owns the carrier/stability decision. A near-coplanar geometry
168
+ fails closed because its orientation is numerically indeterminate.
169
+ """
170
+ if minimum_oriented_volume <= 0:
171
+ raise ValueError("The minimum oriented volume must be positive.")
172
+ volume = normalized_atrop_oriented_volume(
173
+ molecule,
174
+ support,
175
+ conformer_id=conformer_id,
176
+ )
177
+ if abs(volume) < minimum_oriented_volume:
178
+ raise ValueError("Atrop geometry is coplanar or orientation-indeterminate.")
179
+ left_frame, right_frame = support.terminal_frames
180
+ left, right = support.path
181
+ return AtropBondStereo(
182
+ (*left_frame, left, right, *right_frame),
183
+ 1 if volume > 0 else -1,
184
+ provenance,
185
+ )
186
+
187
+
188
+ def cumulene_axis_stereo_from_geometry(
189
+ molecule: Chem.Mol,
190
+ support: AxisStereoSupport,
191
+ *,
192
+ conformer_id: int = -1,
193
+ minimum_oriented_volume: float = 1.0e-5,
194
+ provenance: str = "validated_geometry",
195
+ ) -> CumuleneAxisStereo:
196
+ """Configure one authorized even-bond cumulene from 3D coordinates."""
197
+ if molecule is None:
198
+ raise ValueError("Cumulene geometry requires a molecule.")
199
+ if len(support.path) < 3 or (len(support.path) - 1) % 2:
200
+ raise ValueError("Axial cumulene geometry requires a nonzero even bond count.")
201
+ if minimum_oriented_volume <= 0:
202
+ raise ValueError("The minimum oriented volume must be positive.")
203
+ required = set(support.path) | {
204
+ reference
205
+ for frame in support.terminal_frames
206
+ for reference in frame
207
+ if type(reference) is int
208
+ }
209
+ if min(required) < 0 or max(required) >= molecule.GetNumAtoms():
210
+ raise ValueError("Cumulene geometry references an absent atom.")
211
+ conformer = molecule.GetConformer(conformer_id)
212
+ left, right = support.path[0], support.path[-1]
213
+ axis = _vector(
214
+ conformer.GetAtomPosition(left),
215
+ conformer.GetAtomPosition(right),
216
+ )
217
+ left_frame, right_frame = support.terminal_frames
218
+ left_vector = _terminal_projection(
219
+ molecule,
220
+ owner=left,
221
+ frame=left_frame,
222
+ reference=left_frame[0],
223
+ axis=axis,
224
+ conformer_id=conformer_id,
225
+ )
226
+ right_vector = _terminal_projection(
227
+ molecule,
228
+ owner=right,
229
+ frame=right_frame,
230
+ reference=right_frame[0],
231
+ axis=axis,
232
+ conformer_id=conformer_id,
233
+ )
234
+ denominator = _norm(axis) * _norm(left_vector) * _norm(right_vector)
235
+ volume = (
236
+ 0.0
237
+ if denominator == 0.0
238
+ else _dot(axis, _cross(left_vector, right_vector)) / denominator
239
+ )
240
+ if abs(volume) < minimum_oriented_volume:
241
+ raise ValueError("Cumulene geometry is orientation-indeterminate.")
242
+ return CumuleneAxisStereo(
243
+ support.path,
244
+ support.terminal_frames,
245
+ 1 if volume > 0 else -1,
246
+ provenance,
247
+ )
248
+
249
+
250
+ def tetrahedral_stereo_from_geometry(
251
+ molecule: Chem.Mol,
252
+ center: int,
253
+ *,
254
+ conformer_id: int = -1,
255
+ minimum_oriented_volume: float = 1.0e-5,
256
+ provenance: str = "validated_geometry",
257
+ ) -> TetrahedralStereo:
258
+ """Configure an authorized tetrahedral center from 3D coordinates."""
259
+ if molecule is None:
260
+ raise ValueError("Tetrahedral geometry requires a molecule.")
261
+ if center < 0 or center >= molecule.GetNumAtoms():
262
+ raise ValueError("Tetrahedral geometry references an absent center.")
263
+ if minimum_oriented_volume <= 0:
264
+ raise ValueError("The minimum oriented volume must be positive.")
265
+ atom = molecule.GetAtomWithIdx(center)
266
+ references: list[int | str] = sorted(
267
+ neighbor.GetIdx() for neighbor in atom.GetNeighbors()
268
+ )
269
+ if len(references) == 3:
270
+ kind = "H" if atom.GetTotalNumHs() else "LP"
271
+ references.append(virtual_reference(kind, center))
272
+ if len(references) != 4:
273
+ raise ValueError(
274
+ "Tetrahedral coordinate evidence requires three or four "
275
+ "material references."
276
+ )
277
+ conformer = molecule.GetConformer(conformer_id)
278
+ center_point = conformer.GetAtomPosition(center)
279
+ vectors: list[tuple[float, float, float] | None] = []
280
+ material_vectors = []
281
+ for reference in references:
282
+ if type(reference) is int:
283
+ value = _vector(
284
+ center_point,
285
+ conformer.GetAtomPosition(reference),
286
+ )
287
+ vectors.append(value)
288
+ material_vectors.append(value)
289
+ else:
290
+ vectors.append(None)
291
+ if sum(value is None for value in vectors) > 1:
292
+ raise ValueError(
293
+ "Tetrahedral geometry cannot infer multiple virtual references."
294
+ )
295
+ inferred = tuple(-sum(components) for components in zip(*material_vectors))
296
+ resolved = tuple(inferred if value is None else value for value in vectors)
297
+ first = _subtract(resolved[0], resolved[3])
298
+ second = _subtract(resolved[1], resolved[3])
299
+ third = _subtract(resolved[2], resolved[3])
300
+ denominator = _norm(first) * _norm(second) * _norm(third)
301
+ volume = (
302
+ 0.0 if denominator == 0.0 else _dot(_cross(first, second), third) / denominator
303
+ )
304
+ if abs(volume) < minimum_oriented_volume:
305
+ raise ValueError("Tetrahedral geometry is orientation-indeterminate.")
306
+ return TetrahedralStereo(
307
+ (center, *references), # type: ignore[arg-type]
308
+ -1 if volume > 0 else 1,
309
+ provenance,
310
+ )
311
+
312
+
313
+ def extended_cis_trans_from_geometry(
314
+ molecule: Chem.Mol,
315
+ support: AxisStereoSupport,
316
+ *,
317
+ conformer_id: int = -1,
318
+ minimum_alignment: float = 1.0e-5,
319
+ provenance: str = "validated_geometry",
320
+ ) -> ExtendedCisTransStereo:
321
+ """Configure an authorized odd-bond cumulene from terminal geometry."""
322
+ if molecule is None:
323
+ raise ValueError("Extended cis/trans geometry requires a molecule.")
324
+ if len(support.path) < 4 or (len(support.path) - 1) % 2 != 1:
325
+ raise ValueError(
326
+ "Extended cis/trans geometry requires an odd-bond cumulene path."
327
+ )
328
+ if minimum_alignment <= 0:
329
+ raise ValueError("The minimum alignment must be positive.")
330
+ required = set(support.path) | {
331
+ reference
332
+ for frame in support.terminal_frames
333
+ for reference in frame
334
+ if type(reference) is int
335
+ }
336
+ if min(required) < 0 or max(required) >= molecule.GetNumAtoms():
337
+ raise ValueError("Extended cis/trans geometry references an absent atom.")
338
+ conformer = molecule.GetConformer(conformer_id)
339
+ left, right = support.path[0], support.path[-1]
340
+ axis = _vector(
341
+ conformer.GetAtomPosition(left),
342
+ conformer.GetAtomPosition(right),
343
+ )
344
+ left_frame, right_frame = support.terminal_frames
345
+ left_vector = _terminal_projection(
346
+ molecule,
347
+ owner=left,
348
+ frame=left_frame,
349
+ reference=left_frame[0],
350
+ axis=axis,
351
+ conformer_id=conformer_id,
352
+ )
353
+ right_vector = _terminal_projection(
354
+ molecule,
355
+ owner=right,
356
+ frame=right_frame,
357
+ reference=right_frame[0],
358
+ axis=axis,
359
+ conformer_id=conformer_id,
360
+ )
361
+ denominator = _norm(left_vector) * _norm(right_vector)
362
+ alignment = (
363
+ 0.0 if denominator == 0.0 else _dot(left_vector, right_vector) / denominator
364
+ )
365
+ if abs(alignment) < minimum_alignment:
366
+ raise ValueError("Extended cis/trans geometry is orientation-indeterminate.")
367
+ oriented_right = right_frame if alignment > 0 else tuple(reversed(right_frame))
368
+ return ExtendedCisTransStereo(
369
+ support.path,
370
+ (left_frame, oriented_right), # type: ignore[arg-type]
371
+ 0,
372
+ provenance,
373
+ )
374
+
375
+
376
+ def planar_bond_stereo_from_geometry(
377
+ molecule: Chem.Mol,
378
+ support: AxisStereoSupport,
379
+ *,
380
+ conformer_id: int = -1,
381
+ minimum_alignment: float = 1.0e-5,
382
+ provenance: str = "validated_geometry",
383
+ ) -> PlanarBondStereo:
384
+ """Configure an authorized double bond from terminal geometry."""
385
+ if molecule is None:
386
+ raise ValueError("Planar-bond geometry requires a molecule.")
387
+ if len(support.path) != 2:
388
+ raise ValueError("Planar-bond geometry requires a two-atom path.")
389
+ if minimum_alignment <= 0:
390
+ raise ValueError("The minimum alignment must be positive.")
391
+ required = set(support.path) | {
392
+ reference
393
+ for frame in support.terminal_frames
394
+ for reference in frame
395
+ if type(reference) is int
396
+ }
397
+ if min(required) < 0 or max(required) >= molecule.GetNumAtoms():
398
+ raise ValueError("Planar-bond geometry references an absent atom.")
399
+ conformer = molecule.GetConformer(conformer_id)
400
+ left, right = support.path
401
+ axis = _vector(
402
+ conformer.GetAtomPosition(left),
403
+ conformer.GetAtomPosition(right),
404
+ )
405
+ left_frame, right_frame = support.terminal_frames
406
+ left_vector = _terminal_projection(
407
+ molecule,
408
+ owner=left,
409
+ frame=left_frame,
410
+ reference=left_frame[0],
411
+ axis=axis,
412
+ conformer_id=conformer_id,
413
+ )
414
+ right_vector = _terminal_projection(
415
+ molecule,
416
+ owner=right,
417
+ frame=right_frame,
418
+ reference=right_frame[0],
419
+ axis=axis,
420
+ conformer_id=conformer_id,
421
+ )
422
+ denominator = _norm(left_vector) * _norm(right_vector)
423
+ alignment = (
424
+ 0.0 if denominator == 0.0 else _dot(left_vector, right_vector) / denominator
425
+ )
426
+ if abs(alignment) < minimum_alignment:
427
+ raise ValueError("Planar-bond geometry is orientation-indeterminate.")
428
+ oriented_right = right_frame if alignment > 0 else tuple(reversed(right_frame))
429
+ return PlanarBondStereo(
430
+ (*left_frame, left, right, *oriented_right),
431
+ 0,
432
+ provenance,
433
+ )
434
+
435
+
436
+ def normalized_helical_oriented_volume(
437
+ molecule: Chem.Mol,
438
+ support: PathStereoSupport,
439
+ *,
440
+ conformer_id: int = -1,
441
+ ) -> float:
442
+ """Return the mean normalized triple product along a helical path."""
443
+ if molecule is None:
444
+ raise ValueError("Helical geometry requires a molecule.")
445
+ if len(support.path) < 4:
446
+ raise ValueError("Helical geometry requires at least four path atoms.")
447
+ if min(support.path) < 0 or max(support.path) >= molecule.GetNumAtoms():
448
+ raise ValueError("Helical geometry references an absent atom.")
449
+ conformer = molecule.GetConformer(conformer_id)
450
+ bonds = tuple(
451
+ _vector(
452
+ conformer.GetAtomPosition(left),
453
+ conformer.GetAtomPosition(right),
454
+ )
455
+ for left, right in zip(support.path, support.path[1:])
456
+ )
457
+ terms = []
458
+ for first, second, third in zip(bonds, bonds[1:], bonds[2:]):
459
+ denominator = _norm(first) * _norm(second) * _norm(third)
460
+ if denominator == 0.0:
461
+ terms.append(0.0)
462
+ else:
463
+ terms.append(_dot(_cross(first, second), third) / denominator)
464
+ return sum(terms) / len(terms)
465
+
466
+
467
+ def helical_stereo_from_geometry(
468
+ molecule: Chem.Mol,
469
+ support: PathStereoSupport,
470
+ *,
471
+ conformer_id: int = -1,
472
+ minimum_oriented_volume: float = 1.0e-5,
473
+ provenance: str = "validated_geometry",
474
+ ) -> HelicalStereo:
475
+ """Configure one already-authorized helical path from 3D coordinates."""
476
+ if minimum_oriented_volume <= 0:
477
+ raise ValueError("The minimum oriented volume must be positive.")
478
+ volume = normalized_helical_oriented_volume(
479
+ molecule,
480
+ support,
481
+ conformer_id=conformer_id,
482
+ )
483
+ if abs(volume) < minimum_oriented_volume:
484
+ raise ValueError("Helical geometry is orientation-indeterminate.")
485
+ return HelicalStereo(
486
+ support.path,
487
+ 1 if volume > 0 else -1,
488
+ provenance,
489
+ support.cyclic,
490
+ (support.path[0], support.path[-1]),
491
+ )
492
+
493
+
494
+ __all__ = [
495
+ "atrop_stereo_from_geometry",
496
+ "cumulene_axis_stereo_from_geometry",
497
+ "extended_cis_trans_from_geometry",
498
+ "helical_stereo_from_geometry",
499
+ "normalized_atrop_oriented_volume",
500
+ "normalized_helical_oriented_volume",
501
+ "planar_bond_stereo_from_geometry",
502
+ "tetrahedral_stereo_from_geometry",
503
+ ]
@@ -0,0 +1,165 @@
1
+ """Derived local names bound to one exact configured-stereograph assignment.
2
+
3
+ Naming is a one-way reporting layer. It consumes the exact assignment
4
+ certificate produced by :mod:`synkit.Graph.Stereo.enumeration`, validates that
5
+ the certificate and fixed descriptor population agree, and delegates local
6
+ CIP projection to :mod:`synkit.Chem.Molecule.cip_assignment`. No name is
7
+ written back to a descriptor, molecule, canonical code, or identity key.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections import Counter
13
+ from dataclasses import dataclass
14
+ from hashlib import sha256
15
+ from typing import Any, Mapping
16
+
17
+ from rdkit import Chem
18
+
19
+ from synkit.Chem.Molecule.cip_assignment import (
20
+ CIPAssignment,
21
+ assign_cip_labels,
22
+ )
23
+ from synkit.Graph.Stereo import (
24
+ STEREOGRAPH_SCHEMA,
25
+ StereoAssignment,
26
+ StereoSpecification,
27
+ )
28
+
29
+ DERIVED_STEREO_NAMING_SCHEMA = "synkit.derived-stereo-naming/1"
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class DerivedStereoNamingResult:
34
+ """Immutable local-name report for one exact assignment certificate."""
35
+
36
+ schema: str
37
+ source_schema: str
38
+ source_canonical_digest: str
39
+ source_mirror_status: str
40
+ registry_keys: tuple[str, ...]
41
+ assignments: tuple[CIPAssignment, ...]
42
+
43
+ @property
44
+ def complete(self) -> bool:
45
+ """Whether every configured locus received a derived local name."""
46
+ return all(assignment.assigned for assignment in self.assignments)
47
+
48
+ @property
49
+ def labels(self) -> tuple[tuple[str, str], ...]:
50
+ """Return assigned labels keyed by their source registry handles."""
51
+ return tuple(
52
+ (key, assignment.label)
53
+ for key, assignment in zip(
54
+ self.registry_keys,
55
+ self.assignments,
56
+ )
57
+ if assignment.assigned and assignment.label is not None
58
+ )
59
+
60
+ @property
61
+ def status_counts(self) -> tuple[tuple[str, int], ...]:
62
+ """Return deterministic status counts for reporting."""
63
+ counts = Counter(assignment.status.value for assignment in self.assignments)
64
+ return tuple(sorted(counts.items()))
65
+
66
+ def to_dict(self) -> dict[str, Any]:
67
+ """Return a report payload that keeps names outside identity."""
68
+ return {
69
+ "schema": self.schema,
70
+ "source_schema": self.source_schema,
71
+ "source_canonical_digest": self.source_canonical_digest,
72
+ "source_mirror_status": self.source_mirror_status,
73
+ "complete": self.complete,
74
+ "labels": [list(value) for value in self.labels],
75
+ "status_counts": dict(self.status_counts),
76
+ "assignments": [
77
+ {
78
+ "registry_key": key,
79
+ **assignment.to_dict(),
80
+ }
81
+ for key, assignment in zip(
82
+ self.registry_keys,
83
+ self.assignments,
84
+ )
85
+ ],
86
+ }
87
+
88
+
89
+ def _validate_exact_assignment(assignment: StereoAssignment) -> str:
90
+ if not isinstance(assignment, StereoAssignment):
91
+ raise TypeError("Derived naming requires an exact StereoAssignment.")
92
+ source_schema, separator, _body = assignment.canonical_code.partition("\n")
93
+ if not separator or source_schema != STEREOGRAPH_SCHEMA:
94
+ raise ValueError(
95
+ "Derived naming requires a complete configured-stereograph certificate."
96
+ )
97
+ observed_digest = sha256(assignment.canonical_code.encode("utf-8")).hexdigest()
98
+ if observed_digest != assignment.canonical_digest:
99
+ raise ValueError("Stereo-assignment canonical digest is inconsistent.")
100
+ if any(
101
+ descriptor.specification is StereoSpecification.UNSPECIFIED
102
+ for _key, descriptor in assignment.registry_items
103
+ ):
104
+ raise ValueError("Derived naming requires a complete fixed stereo assignment.")
105
+ return source_schema
106
+
107
+
108
+ def derive_stereo_names(
109
+ molecule: Chem.Mol,
110
+ assignment: StereoAssignment,
111
+ *,
112
+ reference_to_index: Mapping[int, int] | None = None,
113
+ ) -> DerivedStereoNamingResult:
114
+ """Derive witnessed local labels from one exact stereo assignment."""
115
+ if molecule is None:
116
+ raise ValueError("Derived stereo naming requires a molecule.")
117
+ source_schema = _validate_exact_assignment(assignment)
118
+ keys = tuple(key for key, _descriptor in assignment.registry_items)
119
+ descriptors = tuple(descriptor for _key, descriptor in assignment.registry_items)
120
+ names = assign_cip_labels(
121
+ molecule,
122
+ descriptors,
123
+ reference_to_index=reference_to_index,
124
+ )
125
+ return DerivedStereoNamingResult(
126
+ DERIVED_STEREO_NAMING_SCHEMA,
127
+ source_schema,
128
+ assignment.canonical_digest,
129
+ assignment.mirror_status.value,
130
+ keys,
131
+ names,
132
+ )
133
+
134
+
135
+ def _rdkit_reference_to_index(molecule: Chem.Mol) -> dict[int, int]:
136
+ maps = tuple(int(atom.GetAtomMapNum()) for atom in molecule.GetAtoms())
137
+ fully_mapped = (
138
+ bool(maps) and all(value > 0 for value in maps) and len(set(maps)) == len(maps)
139
+ )
140
+ return {
141
+ (
142
+ int(atom.GetAtomMapNum()) if fully_mapped else atom.GetIdx() + 1
143
+ ): atom.GetIdx()
144
+ for atom in molecule.GetAtoms()
145
+ }
146
+
147
+
148
+ def derive_rdkit_stereo_names(
149
+ molecule: Chem.Mol,
150
+ assignment: StereoAssignment,
151
+ ) -> DerivedStereoNamingResult:
152
+ """Derive names using the namespace chosen by RDKit enumeration."""
153
+ return derive_stereo_names(
154
+ molecule,
155
+ assignment,
156
+ reference_to_index=_rdkit_reference_to_index(molecule),
157
+ )
158
+
159
+
160
+ __all__ = [
161
+ "DERIVED_STEREO_NAMING_SCHEMA",
162
+ "DerivedStereoNamingResult",
163
+ "derive_rdkit_stereo_names",
164
+ "derive_stereo_names",
165
+ ]