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,167 @@
1
+ """Topology-only perception of helicene-like molecular path carriers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import networkx as nx
6
+ from rdkit import Chem
7
+
8
+ from synkit.Graph.Stereo.supports import PathStereoSupport
9
+
10
+
11
+ def _aromatic_six_rings(molecule: Chem.Mol) -> tuple[tuple[int, ...], ...]:
12
+ return tuple(
13
+ tuple(ring)
14
+ for ring in molecule.GetRingInfo().AtomRings()
15
+ if len(ring) == 6
16
+ and all(molecule.GetAtomWithIdx(atom).GetIsAromatic() for atom in ring)
17
+ )
18
+
19
+
20
+ def _ring_edge_index(ring: tuple[int, ...], edge: frozenset[int]) -> int:
21
+ for index, left in enumerate(ring):
22
+ if frozenset((left, ring[(index + 1) % len(ring)])) == edge:
23
+ return index
24
+ raise ValueError("Fused aromatic-ring atoms do not form a ring edge.")
25
+
26
+
27
+ def _is_angular_chain(
28
+ ring_order: tuple[int, ...],
29
+ rings: tuple[tuple[int, ...], ...],
30
+ fusion_edges: dict[frozenset[int], frozenset[int]],
31
+ ) -> bool:
32
+ for position, ring_index in enumerate(ring_order[1:-1], start=1):
33
+ left_edge = fusion_edges[frozenset((ring_order[position - 1], ring_index))]
34
+ right_edge = fusion_edges[frozenset((ring_index, ring_order[position + 1]))]
35
+ if left_edge & right_edge:
36
+ return False
37
+ ring = rings[ring_index]
38
+ left_index = _ring_edge_index(ring, left_edge)
39
+ right_index = _ring_edge_index(ring, right_edge)
40
+ separation = abs(left_index - right_index)
41
+ separation = min(separation, len(ring) - separation)
42
+ if separation != 2:
43
+ return False
44
+ return True
45
+
46
+
47
+ def _terminal_candidates(
48
+ molecule_graph: nx.Graph,
49
+ ring: tuple[int, ...],
50
+ fusion_edge: frozenset[int],
51
+ ) -> tuple[int, int] | None:
52
+ left, right = tuple(fusion_edge)
53
+ perimeter = molecule_graph.subgraph(ring).copy()
54
+ perimeter.remove_edge(left, right)
55
+ try:
56
+ free_path = nx.shortest_path(perimeter, left, right)
57
+ except (nx.NetworkXNoPath, nx.NodeNotFound):
58
+ return None
59
+ if len(free_path) != 6:
60
+ return None
61
+ return free_path[1], free_path[-2]
62
+
63
+
64
+ def _unique_shortest_path(
65
+ graph: nx.Graph,
66
+ start: int,
67
+ end: int,
68
+ ) -> tuple[int, ...] | None:
69
+ try:
70
+ paths = nx.all_shortest_paths(graph, start, end)
71
+ first = tuple(next(paths))
72
+ except (nx.NetworkXNoPath, nx.NodeNotFound):
73
+ return None
74
+ try:
75
+ next(paths)
76
+ except StopIteration:
77
+ return first
78
+ return None
79
+
80
+
81
+ def _fusion_topology(
82
+ molecule: Chem.Mol,
83
+ rings: tuple[tuple[int, ...], ...],
84
+ ) -> tuple[nx.Graph, dict[frozenset[int], frozenset[int]]]:
85
+ """Build the ring-fusion graph and retain each material fusion edge."""
86
+ fusion_graph = nx.Graph()
87
+ fusion_graph.add_nodes_from(range(len(rings)))
88
+ fusion_edges = {}
89
+ for left in range(len(rings)):
90
+ for right in range(left + 1, len(rings)):
91
+ shared = frozenset(rings[left]) & frozenset(rings[right])
92
+ if len(shared) != 2:
93
+ continue
94
+ first, second = tuple(shared)
95
+ if molecule.GetBondBetweenAtoms(first, second) is None:
96
+ continue
97
+ fusion_graph.add_edge(left, right)
98
+ fusion_edges[frozenset((left, right))] = shared
99
+ return fusion_graph, fusion_edges
100
+
101
+
102
+ def detect_helicene_supports(
103
+ molecule: Chem.Mol,
104
+ ) -> tuple[PathStereoSupport, ...]:
105
+ """Return curled, angular, fused-aromatic path carriers.
106
+
107
+ A candidate is a chain of at least five edge-fused aromatic six-rings.
108
+ Every internal fusion must be angular, and the two terminal rings must
109
+ expose one unique closest pair joined by one unique shortest molecular
110
+ path. This distinguishes a curled helicene-like topology from linear or
111
+ ambiguous fused-ring chains without assigning handedness or stability.
112
+ """
113
+ if molecule is None:
114
+ raise ValueError("Helical carrier detection requires a molecule.")
115
+ rings = _aromatic_six_rings(molecule)
116
+ if len(rings) < 5:
117
+ return ()
118
+ molecular_graph = nx.Graph(
119
+ (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()) for bond in molecule.GetBonds()
120
+ )
121
+ fusion_graph, fusion_edges = _fusion_topology(molecule, rings)
122
+
123
+ supports = set()
124
+ for component in nx.connected_components(fusion_graph):
125
+ chain = fusion_graph.subgraph(component)
126
+ if (
127
+ len(component) < 5
128
+ or chain.number_of_edges() != len(component) - 1
129
+ or any(degree > 2 for _, degree in chain.degree())
130
+ ):
131
+ continue
132
+ terminals = sorted(node for node, degree in chain.degree() if degree == 1)
133
+ if len(terminals) != 2:
134
+ continue
135
+ ring_order = tuple(nx.shortest_path(chain, *terminals))
136
+ if not _is_angular_chain(ring_order, rings, fusion_edges):
137
+ continue
138
+ left_candidates = _terminal_candidates(
139
+ molecular_graph,
140
+ rings[ring_order[0]],
141
+ fusion_edges[frozenset(ring_order[:2])],
142
+ )
143
+ right_candidates = _terminal_candidates(
144
+ molecular_graph,
145
+ rings[ring_order[-1]],
146
+ fusion_edges[frozenset(ring_order[-2:])],
147
+ )
148
+ if left_candidates is None or right_candidates is None:
149
+ continue
150
+ distances = {
151
+ (left, right): nx.shortest_path_length(molecular_graph, left, right)
152
+ for left in left_candidates
153
+ for right in right_candidates
154
+ }
155
+ minimum = min(distances.values())
156
+ closest = [pair for pair, distance in distances.items() if distance == minimum]
157
+ if len(closest) != 1:
158
+ continue
159
+ path = _unique_shortest_path(molecular_graph, *closest[0])
160
+ if path is None or len(path) < len(component) + 1:
161
+ continue
162
+ canonical_path = min(path, tuple(reversed(path)))
163
+ supports.add(PathStereoSupport(canonical_path))
164
+ return tuple(sorted(supports, key=lambda support: support.path))
165
+
166
+
167
+ __all__ = ["detect_helicene_supports"]
@@ -0,0 +1,202 @@
1
+ """Exact constitutional evidence for broad molecular stereo-axis candidates."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import Enum
6
+
7
+ import networkx as nx
8
+ from networkx.algorithms.isomorphism import (
9
+ GraphMatcher,
10
+ categorical_edge_match,
11
+ categorical_node_match,
12
+ )
13
+ from rdkit import Chem
14
+
15
+ from synkit.Graph.Stereo.descriptors import Reference, virtual_reference
16
+ from synkit.Graph.Stereo.supports import AxisStereoSupport
17
+
18
+
19
+ class StereoCarrierStatus(str, Enum):
20
+ """Constitutional conclusion for a perceived carrier.
21
+
22
+ ``CONFIRMED`` means only that the represented constitution has
23
+ distinguishable carrier references. It is not a configurational-stability
24
+ claim. ``SYMMETRY_RELATED`` retains a broad topology candidate while
25
+ recording why it must not be promoted to a confirmed stereo carrier.
26
+ """
27
+
28
+ CONFIRMED = "confirmed"
29
+ SYMMETRY_RELATED = "symmetry_related"
30
+
31
+
32
+ def validated_carrier_status(
33
+ value: StereoCarrierStatus | str,
34
+ reason: str | None,
35
+ ) -> StereoCarrierStatus:
36
+ """Normalize a carrier status and enforce its diagnostic invariant."""
37
+ status = StereoCarrierStatus(value)
38
+ if status is StereoCarrierStatus.SYMMETRY_RELATED and not reason:
39
+ raise ValueError(
40
+ "Symmetry-related stereo carriers require a diagnostic reason."
41
+ )
42
+ return status
43
+
44
+
45
+ _NODE_ATTRIBUTES = (
46
+ "atomic_number",
47
+ "isotope",
48
+ "formal_charge",
49
+ "radical_electrons",
50
+ "hcount",
51
+ "aromatic",
52
+ "stereo_anchor",
53
+ "stereo_marker",
54
+ "axis_anchor",
55
+ "ligand_probe",
56
+ )
57
+ _EDGE_ATTRIBUTES = ("bond_type", "aromatic")
58
+ _NODE_DEFAULTS = (0, 0, 0, 0, 0, False, False, None, None, False)
59
+ _EDGE_DEFAULTS = ("", False)
60
+
61
+
62
+ def _refinement_fingerprint(graph: nx.Graph) -> str:
63
+ """Return an isomorphism-invariant rejection fingerprint.
64
+
65
+ Unequal Weisfeiler-Lehman fingerprints prove that the rooted attributed
66
+ graphs cannot be isomorphic. Equal fingerprints remain inconclusive and
67
+ therefore continue to the exact VF2 witness check.
68
+ """
69
+ node_label = "_synkit_symmetry_node_label"
70
+ edge_label = "_synkit_symmetry_edge_label"
71
+ for _node, attributes in graph.nodes(data=True):
72
+ attributes[node_label] = repr(
73
+ tuple(
74
+ attributes.get(name, default)
75
+ for name, default in zip(_NODE_ATTRIBUTES, _NODE_DEFAULTS)
76
+ )
77
+ )
78
+ for _left, _right, attributes in graph.edges(data=True):
79
+ attributes[edge_label] = repr(
80
+ tuple(
81
+ attributes.get(name, default)
82
+ for name, default in zip(_EDGE_ATTRIBUTES, _EDGE_DEFAULTS)
83
+ )
84
+ )
85
+ return nx.weisfeiler_lehman_graph_hash(
86
+ graph,
87
+ node_attr=node_label,
88
+ edge_attr=edge_label,
89
+ iterations=max(1, graph.number_of_nodes()),
90
+ )
91
+
92
+
93
+ def cumulene_terminal_references(
94
+ molecule: Chem.Mol,
95
+ owner: int,
96
+ path_neighbor: int,
97
+ ) -> tuple[Reference, Reference] | None:
98
+ """Return two represented references at one cumulene endpoint."""
99
+ atom = molecule.GetAtomWithIdx(owner)
100
+ references: list[Reference] = [
101
+ neighbor.GetIdx()
102
+ for neighbor in atom.GetNeighbors()
103
+ if neighbor.GetIdx() != path_neighbor
104
+ ]
105
+ hidden_hydrogens = int(atom.GetNumExplicitHs()) + int(atom.GetNumImplicitHs())
106
+ references.extend(virtual_reference("H", owner) for _ in range(hidden_hydrogens))
107
+ if len(references) == 1 and atom.GetAtomicNum() == 15:
108
+ references.append(virtual_reference("LP", owner))
109
+ if len(references) != 2 or references[0] == references[1]:
110
+ return None
111
+ return references[0], references[1]
112
+
113
+
114
+ def _axis_fixed_reference_symmetry_witness(
115
+ graph: nx.Graph,
116
+ support: AxisStereoSupport,
117
+ left: Reference,
118
+ right: Reference,
119
+ ) -> tuple[tuple[int, int], ...] | None:
120
+ """Return an exact terminal-reference automorphism witness, if one exists."""
121
+ if type(left) is not int or type(right) is not int:
122
+ return None
123
+ left_rooted = graph.copy()
124
+ right_rooted = graph.copy()
125
+ for rooted, probe in ((left_rooted, left), (right_rooted, right)):
126
+ nx.set_node_attributes(rooted, None, "axis_anchor")
127
+ nx.set_node_attributes(rooted, False, "ligand_probe")
128
+ for position, atom in enumerate(support.path):
129
+ rooted.nodes[atom]["axis_anchor"] = position
130
+ rooted.nodes[probe]["ligand_probe"] = True
131
+ if _refinement_fingerprint(left_rooted) != _refinement_fingerprint(right_rooted):
132
+ return None
133
+ matcher = GraphMatcher(
134
+ left_rooted,
135
+ right_rooted,
136
+ node_match=categorical_node_match(
137
+ _NODE_ATTRIBUTES,
138
+ _NODE_DEFAULTS,
139
+ ),
140
+ edge_match=categorical_edge_match(
141
+ _EDGE_ATTRIBUTES,
142
+ _EDGE_DEFAULTS,
143
+ ),
144
+ )
145
+ mapping = next(matcher.isomorphisms_iter(), None)
146
+ if mapping is None:
147
+ return None
148
+ return tuple(
149
+ sorted((int(source), int(target)) for source, target in mapping.items())
150
+ )
151
+
152
+
153
+ def axis_terminal_symmetry_witnesses(
154
+ graph: nx.Graph,
155
+ support: AxisStereoSupport,
156
+ ) -> tuple[tuple[tuple[int, int], ...] | None, ...]:
157
+ """Return one exact symmetry witness for each terminal reference pair.
158
+
159
+ Axis atoms are fixed in path order and one terminal ligand probe is mapped
160
+ to the other. A non-``None`` witness proves terminal-reference equivalence
161
+ under that constitutional stabilizer. The same map can exchange the other
162
+ terminal pair as well, preserving a configured axial orientation. These
163
+ witnesses alone do not decide whole-configuration mirror equivalence or
164
+ rotational barriers.
165
+ """
166
+ return tuple(
167
+ _axis_fixed_reference_symmetry_witness(
168
+ graph,
169
+ support,
170
+ frame[0],
171
+ frame[1],
172
+ )
173
+ for frame in support.terminal_frames
174
+ )
175
+
176
+
177
+ def axis_carrier_status(
178
+ graph: nx.Graph,
179
+ element_type: str,
180
+ support: AxisStereoSupport,
181
+ ) -> tuple[StereoCarrierStatus, str | None]:
182
+ """Return exact terminal-symmetry evidence for a broad axis candidate."""
183
+ if any(
184
+ witness is not None
185
+ for witness in axis_terminal_symmetry_witnesses(graph, support)
186
+ ):
187
+ reason = (
188
+ "symmetry_related_terminal_paths"
189
+ if element_type == "atrop_axis"
190
+ else "duplicate_terminal_ligands"
191
+ )
192
+ return StereoCarrierStatus.SYMMETRY_RELATED, reason
193
+ return StereoCarrierStatus.CONFIRMED, None
194
+
195
+
196
+ __all__ = [
197
+ "StereoCarrierStatus",
198
+ "axis_carrier_status",
199
+ "axis_terminal_symmetry_witnesses",
200
+ "cumulene_terminal_references",
201
+ "validated_carrier_status",
202
+ ]
@@ -0,0 +1,193 @@
1
+ """Internal non-tetrahedral stereo-element detection helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import networkx as nx
6
+ from rdkit import Chem
7
+
8
+ from synkit.Graph.Stereo.supports import (
9
+ AxisStereoSupport,
10
+ BondStereoSupport,
11
+ PathStereoSupport,
12
+ )
13
+
14
+ from ._helical_loci import detect_helicene_supports
15
+ from ._stereo_axis_evidence import (
16
+ StereoCarrierStatus,
17
+ axis_carrier_status,
18
+ cumulene_terminal_references,
19
+ )
20
+ from .stereo_perception import (
21
+ PotentialStereoElement,
22
+ StereoConfigurationState,
23
+ StereoElementType,
24
+ _configuration_state,
25
+ _constitutional_graph,
26
+ _cumulated_double_bonds,
27
+ )
28
+
29
+
30
+ def rdkit_double_bond_elements(
31
+ molecule: Chem.Mol,
32
+ ) -> tuple[PotentialStereoElement, ...]:
33
+ """Project and complete double-bond perception as typed support evidence."""
34
+ cumulated_bonds = _cumulated_double_bonds(molecule)
35
+ elements = []
36
+ perceived_bonds = set()
37
+ for info in Chem.FindPotentialStereo(molecule):
38
+ centered_on = int(info.centeredOn)
39
+ if info.type != Chem.StereoType.Bond_Double:
40
+ continue
41
+ if centered_on in cumulated_bonds:
42
+ continue
43
+ perceived_bonds.add(centered_on)
44
+ bond = molecule.GetBondWithIdx(centered_on)
45
+ elements.append(
46
+ PotentialStereoElement(
47
+ StereoElementType.DOUBLE_BOND,
48
+ BondStereoSupport(
49
+ bond.GetBeginAtomIdx(),
50
+ bond.GetEndAtomIdx(),
51
+ ),
52
+ _configuration_state(info),
53
+ "rdkit_find_potential_stereo",
54
+ f"Bond_Double:{centered_on}",
55
+ )
56
+ )
57
+ for bond in molecule.GetBonds():
58
+ bond_index = bond.GetIdx()
59
+ if (
60
+ bond.GetBondType() != Chem.BondType.DOUBLE
61
+ or bond_index in cumulated_bonds
62
+ or bond_index in perceived_bonds
63
+ ):
64
+ continue
65
+ left, right = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()
66
+ left_refs = cumulene_terminal_references(molecule, left, right)
67
+ right_refs = cumulene_terminal_references(molecule, right, left)
68
+ if left_refs is None or right_refs is None:
69
+ continue
70
+ if not any(
71
+ type(reference) is int
72
+ and molecule.GetAtomWithIdx(reference).GetIsotope() != 0
73
+ for frame in (left_refs, right_refs)
74
+ for reference in frame
75
+ ):
76
+ continue
77
+ support = AxisStereoSupport((left, right), (left_refs, right_refs))
78
+ status, _reason = axis_carrier_status(
79
+ _constitutional_graph(molecule, left),
80
+ StereoElementType.DOUBLE_BOND.value,
81
+ support,
82
+ )
83
+ if status is not StereoCarrierStatus.CONFIRMED:
84
+ continue
85
+ elements.append(
86
+ PotentialStereoElement(
87
+ StereoElementType.DOUBLE_BOND,
88
+ BondStereoSupport(left, right),
89
+ StereoConfigurationState.UNSPECIFIED,
90
+ "synkit_double_bond_exact_terminal_symmetry",
91
+ f"Bond_Double:{bond_index}",
92
+ )
93
+ )
94
+ return tuple(elements)
95
+
96
+
97
+ def extended_cis_trans_elements(
98
+ molecule: Chem.Mol,
99
+ ) -> tuple[PotentialStereoElement, ...]:
100
+ """Detect odd-bond extended cumulene E/Z supports without inventing state."""
101
+ double_graph = nx.Graph()
102
+ double_graph.add_edges_from(
103
+ (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
104
+ for bond in molecule.GetBonds()
105
+ if bond.GetBondType() == Chem.BondType.DOUBLE
106
+ )
107
+ elements = []
108
+ for component in nx.connected_components(double_graph):
109
+ path_graph = double_graph.subgraph(component)
110
+ edge_count = path_graph.number_of_edges()
111
+ if edge_count < 3 or edge_count % 2 != 1:
112
+ continue
113
+ if edge_count != path_graph.number_of_nodes() - 1:
114
+ continue
115
+ if any(degree > 2 for _, degree in path_graph.degree()):
116
+ continue
117
+ ends = sorted(node for node, degree in path_graph.degree() if degree == 1)
118
+ if len(ends) != 2:
119
+ continue
120
+ path = tuple(nx.shortest_path(path_graph, ends[0], ends[1]))
121
+ if any(molecule.GetAtomWithIdx(node).GetDegree() != 2 for node in path[1:-1]):
122
+ continue
123
+ left = cumulene_terminal_references(molecule, path[0], path[1])
124
+ right = cumulene_terminal_references(molecule, path[-1], path[-2])
125
+ if left is None or right is None:
126
+ continue
127
+ support = AxisStereoSupport(path, (left, right))
128
+ carrier_status, carrier_reason = axis_carrier_status(
129
+ _constitutional_graph(molecule, support.path[0]),
130
+ StereoElementType.EXTENDED_CIS_TRANS.value,
131
+ support,
132
+ )
133
+ elements.append(
134
+ PotentialStereoElement(
135
+ StereoElementType.EXTENDED_CIS_TRANS,
136
+ support,
137
+ StereoConfigurationState.UNSPECIFIED,
138
+ "synkit_odd_cumulene_path_perception",
139
+ "Extended_CisTrans:" + "-".join(str(atom) for atom in path),
140
+ carrier_status=carrier_status,
141
+ carrier_reason=carrier_reason,
142
+ )
143
+ )
144
+ return tuple(elements)
145
+
146
+
147
+ def axis_elements(
148
+ molecule: Chem.Mol,
149
+ *,
150
+ include_extended_ring_axes: bool,
151
+ ) -> tuple[PotentialStereoElement, ...]:
152
+ """Adapt the conservative axial-locus detector to typed elements."""
153
+ from .chirality import detect_potential_stereo_loci
154
+
155
+ elements = []
156
+ for locus in detect_potential_stereo_loci(
157
+ molecule,
158
+ include_extended_ring_axes=include_extended_ring_axes,
159
+ ):
160
+ element_type = StereoElementType(locus.locus_type.value)
161
+ carrier_status, carrier_reason = axis_carrier_status(
162
+ _constitutional_graph(molecule, locus.support.path[0]),
163
+ element_type.value,
164
+ locus.support,
165
+ )
166
+ elements.append(
167
+ PotentialStereoElement(
168
+ element_type,
169
+ locus.support,
170
+ StereoConfigurationState.UNSPECIFIED,
171
+ locus.evidence_provenance,
172
+ locus.identifier,
173
+ carrier_status=carrier_status,
174
+ carrier_reason=carrier_reason,
175
+ )
176
+ )
177
+ return tuple(elements)
178
+
179
+
180
+ def helical_elements(
181
+ molecule: Chem.Mol,
182
+ ) -> tuple[PotentialStereoElement, ...]:
183
+ """Return helicene-like path carriers without orientation claims."""
184
+ return tuple(
185
+ PotentialStereoElement(
186
+ StereoElementType.HELICAL,
187
+ PathStereoSupport(support.path, support.cyclic),
188
+ StereoConfigurationState.UNSPECIFIED,
189
+ "synkit_angular_fused_aromatic_helicene_topology",
190
+ "Helical:" + "-".join(str(atom) for atom in support.path),
191
+ )
192
+ for support in detect_helicene_supports(molecule)
193
+ )