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,137 @@
1
+ """Exact bond-label orbits via point-stabilizer transversals.
2
+
3
+ Only the action on vertices supporting the label is needed. For a base
4
+ b_1,...,b_k of those vertices let H_j fix its first j points. One witnessed
5
+ transversal T_j for H_{j-1}/H_j gives G = T_1 ... T_k H_k. Since H_k fixes the
6
+ label, its orbit is obtained by applying T_k,...,T_1 and deduplicating images.
7
+ Thus irrelevant spectator permutations need never be listed. This uses
8
+ standard group decomposition, not a new graph-isomorphism algorithm.
9
+ """
10
+
11
+ import math
12
+ from time import monotonic
13
+
14
+ import networkx as nx
15
+
16
+ from .bonds import ExactBondEvaluator, IncompleteSymmetry, ScoreWitness, _graph, bond_f1, transport_bonds
17
+
18
+
19
+ class SupportOrbitEvaluator(ExactBondEvaluator):
20
+ """Exact quotient scorer without explicit enumeration of the entire group.
21
+
22
+ Every transporter is a full attributed-graph automorphism. Failure to
23
+ complete any orbit query raises; no partial group is reported as exact.
24
+ Deadlines are cooperative around isomorphism calls and need an external
25
+ process deadline for a hard wall-clock guarantee.
26
+ """
27
+
28
+ def __init__(self, reactant, *, max_label_images=100000, time_limit_seconds=30):
29
+ if (not isinstance(max_label_images, int) or max_label_images < 1
30
+ or not math.isfinite(time_limit_seconds) or time_limit_seconds <= 0):
31
+ raise ValueError("Require positive finite time and label-image limits")
32
+ self.n = len(reactant.atomic_numbers)
33
+ self.graph = _graph(reactant)
34
+ self.identity = tuple(range(self.n))
35
+ self.deadline = monotonic() + time_limit_seconds
36
+ self.max_label_images = max_label_images
37
+ self._orbits = {}
38
+ self._transversals = {}
39
+ self.isomorphism_calls = 0
40
+ self.colors = self._refine_colors()
41
+
42
+ def _check(self):
43
+ if monotonic() > self.deadline:
44
+ raise IncompleteSymmetry("Label-orbit deadline exceeded")
45
+
46
+ def _refine_colors(self):
47
+ def number(signatures):
48
+ numbers = {value: i for i, value in enumerate(sorted(set(signatures)))}
49
+ return tuple(numbers[x] for x in signatures)
50
+ colors = number([self.graph.nodes[i]["color"] for i in range(self.n)])
51
+ for _ in range(self.n):
52
+ self._check()
53
+ refined = number([(colors[i], tuple(sorted(
54
+ (self.graph.edges[i, j]["order"], colors[j]) for j in self.graph[i])))
55
+ for i in range(self.n)])
56
+ if len(set(refined)) == len(set(colors)):
57
+ return refined
58
+ colors = refined
59
+ return colors
60
+
61
+ def _extension(self, fixed, source, target):
62
+ self._check()
63
+ if source == target:
64
+ return self.identity
65
+ left, right = self.graph.copy(), self.graph.copy()
66
+ for i in range(self.n):
67
+ left.nodes[i]["constraint"] = (self.colors[i], -1)
68
+ right.nodes[i]["constraint"] = (self.colors[i], -1)
69
+ for i in fixed:
70
+ left.nodes[i]["constraint"] = right.nodes[i]["constraint"] = (self.colors[i], i)
71
+ left.nodes[source]["constraint"] = (self.colors[source], source)
72
+ right.nodes[target]["constraint"] = (self.colors[target], source)
73
+ matcher = nx.algorithms.isomorphism.GraphMatcher(
74
+ left, right,
75
+ node_match=nx.algorithms.isomorphism.categorical_node_match("constraint", None),
76
+ edge_match=nx.algorithms.isomorphism.categorical_edge_match("order", None),
77
+ )
78
+ self.isomorphism_calls += 1
79
+ mapping = next(matcher.isomorphisms_iter(), None)
80
+ self._check()
81
+ if mapping is None:
82
+ return None
83
+ return tuple(mapping[i] for i in range(self.n))
84
+
85
+ def _transversal(self, fixed, source):
86
+ key = (fixed, source)
87
+ if key not in self._transversals:
88
+ values = []
89
+ for target in range(self.n):
90
+ if target in fixed or self.colors[target] != self.colors[source]:
91
+ continue
92
+ witness = self._extension(fixed, source, target)
93
+ if witness is not None:
94
+ values.append(witness)
95
+ self._transversals[key] = tuple(values)
96
+ return self._transversals[key]
97
+
98
+ def orbit(self, label):
99
+ """Return each distinct image with a verified full-graph transporter."""
100
+ self._check()
101
+ label = self._validate(label)
102
+ if label not in self._orbits:
103
+ base = self._support(label)
104
+ levels = [self._transversal(base[:j], source) for j, source in enumerate(base)]
105
+ images = {label: self.identity}
106
+ for transversal in reversed(levels):
107
+ next_images = {}
108
+ for t in transversal:
109
+ for current, witness in images.items():
110
+ self._check()
111
+ image = self._transport(current, t)
112
+ if image not in next_images:
113
+ next_images[image] = tuple(t[witness[i]] for i in range(self.n))
114
+ if len(next_images) > self.max_label_images:
115
+ raise IncompleteSymmetry("Label-image cap exceeded")
116
+ images = next_images
117
+ self._orbits[label] = images
118
+ return self._orbits[label]
119
+
120
+ def _support(self, label):
121
+ return tuple(sorted({i for pair in label for i in pair}))
122
+
123
+ def _transport(self, label, permutation):
124
+ return transport_bonds(label, permutation)
125
+
126
+ def score(self, prediction, label):
127
+ prediction = self._validate(prediction)
128
+ best = None
129
+ for image, witness in self.orbit(label).items():
130
+ self._check()
131
+ score = bond_f1(prediction, image)
132
+ if best is None or score > best.score:
133
+ best = ScoreWitness(score, witness)
134
+ return best
135
+
136
+ def orbit_key(self, label):
137
+ return min(tuple(sorted(image)) for image in self.orbit(label))
File without changes
@@ -0,0 +1,165 @@
1
+ """Topology-only detection of potential molecular stereo axes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import networkx as nx
6
+ from rdkit import Chem
7
+
8
+ from synkit.Graph.Stereo.descriptors import Reference, virtual_reference
9
+ from synkit.Graph.Stereo.supports import AxisStereoSupport
10
+
11
+
12
+ def _cumulene_end_references(
13
+ atom: Chem.Atom,
14
+ axis_neighbor: int,
15
+ ) -> tuple[Reference, Reference] | None:
16
+ """Return zero-based terminal references for one cumulene end."""
17
+ center = atom.GetIdx()
18
+ references: list[Reference] = [
19
+ neighbor.GetIdx()
20
+ for neighbor in atom.GetNeighbors()
21
+ if neighbor.GetIdx() != axis_neighbor
22
+ ]
23
+ hidden_hydrogens = int(atom.GetNumExplicitHs()) + int(atom.GetNumImplicitHs())
24
+ references.extend(virtual_reference("H", center) for _ in range(hidden_hydrogens))
25
+ if len(references) == 1 and atom.GetAtomicNum() == 15:
26
+ references.append(virtual_reference("LP", center))
27
+ if len(references) != 2 or references[0] == references[1]:
28
+ return None
29
+ return references[0], references[1]
30
+
31
+
32
+ def _potential_cumulene_supports(
33
+ molecule: Chem.Mol,
34
+ ) -> tuple[AxisStereoSupport, ...]:
35
+ """Detect even-cumulene axes without assigning their orientation."""
36
+ double_graph = nx.Graph()
37
+ double_graph.add_edges_from(
38
+ (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
39
+ for bond in molecule.GetBonds()
40
+ if bond.GetBondType() == Chem.BondType.DOUBLE
41
+ )
42
+ supports = []
43
+ for component in nx.connected_components(double_graph):
44
+ axis = double_graph.subgraph(component)
45
+ edge_count = axis.number_of_edges()
46
+ if edge_count < 2 or edge_count % 2 != 0:
47
+ continue
48
+ if edge_count != axis.number_of_nodes() - 1:
49
+ continue
50
+ degrees = dict(axis.degree())
51
+ if any(degree > 2 for degree in degrees.values()):
52
+ continue
53
+ ends = sorted(node for node, degree in degrees.items() if degree == 1)
54
+ if len(ends) != 2:
55
+ continue
56
+ path = nx.shortest_path(axis, ends[0], ends[1])
57
+ if any(molecule.GetAtomWithIdx(node).GetDegree() != 2 for node in path[1:-1]):
58
+ continue
59
+ left_refs = _cumulene_end_references(
60
+ molecule.GetAtomWithIdx(path[0]),
61
+ path[1],
62
+ )
63
+ right_refs = _cumulene_end_references(
64
+ molecule.GetAtomWithIdx(path[-1]),
65
+ path[-2],
66
+ )
67
+ if left_refs is None or right_refs is None:
68
+ continue
69
+ supports.append(AxisStereoSupport(tuple(path), (left_refs, right_refs)))
70
+ return tuple(supports)
71
+
72
+
73
+ def _potential_biaryl_supports(
74
+ molecule: Chem.Mol,
75
+ *,
76
+ include_extended_ring_axes: bool,
77
+ ) -> tuple[AxisStereoSupport, ...]:
78
+ """Detect ring-associated bond axes without orientation or barrier claims."""
79
+ supports = []
80
+ for bond in molecule.GetBonds():
81
+ if bond.GetBondType() not in {
82
+ Chem.BondType.SINGLE,
83
+ Chem.BondType.AROMATIC,
84
+ }:
85
+ continue
86
+ left_atom = bond.GetBeginAtom()
87
+ right_atom = bond.GetEndAtom()
88
+ hybridizations = {
89
+ left_atom.GetHybridization(),
90
+ right_atom.GetHybridization(),
91
+ }
92
+ containing_ring_sizes = tuple(
93
+ len(ring)
94
+ for ring in molecule.GetRingInfo().BondRings()
95
+ if bond.GetIdx() in ring
96
+ )
97
+ aromatic_ring_axis = (
98
+ bond.GetIsAromatic()
99
+ and left_atom.GetIsAromatic()
100
+ and right_atom.GetIsAromatic()
101
+ and any(size > 6 for size in containing_ring_sizes)
102
+ )
103
+ linked_ring_axis = (
104
+ not bond.GetIsAromatic()
105
+ and (left_atom.IsInRing() or right_atom.IsInRing())
106
+ and Chem.HybridizationType.SP2 in hybridizations
107
+ and hybridizations
108
+ <= {
109
+ Chem.HybridizationType.SP2,
110
+ Chem.HybridizationType.SP3,
111
+ }
112
+ )
113
+ standard_biaryl_axis = (
114
+ not bond.GetIsAromatic()
115
+ and left_atom.GetIsAromatic()
116
+ and right_atom.GetIsAromatic()
117
+ )
118
+ if not standard_biaryl_axis and not (
119
+ include_extended_ring_axes and (aromatic_ring_axis or linked_ring_axis)
120
+ ):
121
+ continue
122
+ left, right = left_atom.GetIdx(), right_atom.GetIdx()
123
+ left_refs = tuple(
124
+ neighbor.GetIdx()
125
+ for neighbor in left_atom.GetNeighbors()
126
+ if neighbor.GetIdx() != right_atom.GetIdx()
127
+ )
128
+ right_refs = tuple(
129
+ neighbor.GetIdx()
130
+ for neighbor in right_atom.GetNeighbors()
131
+ if neighbor.GetIdx() != left_atom.GetIdx()
132
+ )
133
+ if len(left_refs) != 2 or len(right_refs) != 2:
134
+ continue
135
+ supports.append(
136
+ AxisStereoSupport(
137
+ (left, right),
138
+ (left_refs, right_refs),
139
+ )
140
+ )
141
+ return tuple(supports)
142
+
143
+
144
+ def detect_potential_axis_supports(
145
+ molecule: Chem.Mol,
146
+ *,
147
+ include_extended_ring_axes: bool = False,
148
+ ) -> tuple[tuple[str, AxisStereoSupport], ...]:
149
+ """Return typed topology supports for potential molecular stereo axes."""
150
+ if molecule is None:
151
+ raise ValueError("Potential stereo-locus detection requires a molecule.")
152
+ working = Chem.Mol(molecule)
153
+ return (
154
+ *(
155
+ ("cumulene_axis", support)
156
+ for support in _potential_cumulene_supports(working)
157
+ ),
158
+ *(
159
+ ("atrop_axis", support)
160
+ for support in _potential_biaryl_supports(
161
+ working,
162
+ include_extended_ring_axes=include_extended_ring_axes,
163
+ )
164
+ ),
165
+ )
@@ -0,0 +1,231 @@
1
+ """Data models and topology-colour helpers for molecular chirality."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import Enum
7
+ from typing import Any, Mapping
8
+
9
+ from synkit.Graph.Stereo.descriptors import Reference
10
+ from synkit.Graph.Stereo.supports import AxisStereoSupport
11
+
12
+
13
+ class MolecularChirality(str, Enum):
14
+ """Global relationship between a molecule and its mirror image."""
15
+
16
+ ACHIRAL = "Achiral"
17
+ CHIRAL = "Chiral"
18
+
19
+
20
+ class MolecularChiralityOutcome(str, Enum):
21
+ """Configuration-aware conclusion for possibly underspecified input."""
22
+
23
+ NECESSARILY_ACHIRAL = "necessarily_achiral"
24
+ NECESSARILY_CHIRAL = "necessarily_chiral"
25
+ CONFIGURATION_DEPENDENT = "configuration_dependent"
26
+ UNSUPPORTED_OR_INCOMPLETE = "unsupported_or_incomplete"
27
+
28
+
29
+ class PotentialStereoLocusType(str, Enum):
30
+ """Topology-supported stereo locus whose configuration is not supplied."""
31
+
32
+ CUMULENE_AXIS = "cumulene_axis"
33
+ ATROP_AXIS = "atrop_axis"
34
+
35
+
36
+ class StereoOrientationState(str, Enum):
37
+ """Information state of a potential stereo locus."""
38
+
39
+ UNSPECIFIED = "unspecified"
40
+
41
+
42
+ class StereoStabilityStatus(str, Enum):
43
+ """Configurational-stability evidence attached to a potential locus."""
44
+
45
+ UNASSESSED = "unassessed"
46
+
47
+
48
+ class UnspecifiedMolecularStereoError(ValueError):
49
+ """Raised when strict binary classification receives unresolved stereo."""
50
+
51
+ def __init__(self, loci: tuple[str, ...]) -> None:
52
+ self.loci = loci
53
+ joined = ", ".join(loci)
54
+ super().__init__(f"Molecular stereochemistry is underspecified at: {joined}")
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class MolecularChiralityResult:
59
+ """Evidence returned by whole-molecule mirror classification."""
60
+
61
+ classification: MolecularChirality
62
+ mirror_isomorphism: tuple[tuple[int, int], ...] | None
63
+ descriptor_count: int
64
+ completed_tetrahedral_centers: tuple[int, ...]
65
+ # Compatibility fields retained for readers of the exploratory report.
66
+ # Sound classification never populates them from 2D connectivity alone.
67
+ completed_extended_tetrahedral_axes: tuple[tuple[int, int], ...] = ()
68
+ completed_biaryl_atrop_axes: tuple[tuple[int, int], ...] = ()
69
+ identity_profile: str = "element-isotope-hydrogen-connectivity"
70
+ decision_method: str = "exact_mirror_isomorphism"
71
+ input_stereo_status: str = "specified"
72
+ unspecified_stereo_loci: tuple[str, ...] = ()
73
+ potential_stereo_loci: tuple["PotentialStereoLocus", ...] = ()
74
+ configured_extended_descriptor_count: int = 0
75
+ stereo_evidence_source: str | None = None
76
+ extended_stability_status: str | None = None
77
+ population_fraction: float | None = None
78
+
79
+ @property
80
+ def is_chiral(self) -> bool:
81
+ """Return ``True`` when no orientation-preserving mirror map exists."""
82
+ return self.classification is MolecularChirality.CHIRAL
83
+
84
+
85
+ @dataclass(frozen=True, init=False)
86
+ class PotentialStereoLocus:
87
+ """A typed candidate locus without an invented configuration.
88
+
89
+ Atom indices and material terminal references are zero-based RDKit atom
90
+ indices. Virtual hydrogen references use ``@H:<owner-index>``. Detection
91
+ from 2D connectivity proves only that the topology can support the locus;
92
+ it supplies neither handedness nor configurational-stability evidence.
93
+ """
94
+
95
+ locus_type: PotentialStereoLocusType
96
+ support: AxisStereoSupport
97
+ orientation_state: StereoOrientationState = StereoOrientationState.UNSPECIFIED
98
+ evidence_provenance: str = "two_dimensional_connectivity"
99
+ stability_status: StereoStabilityStatus = StereoStabilityStatus.UNASSESSED
100
+
101
+ def __init__(
102
+ self,
103
+ locus_type: PotentialStereoLocusType,
104
+ atom_indices: tuple[int, ...] | None = None,
105
+ terminal_references: tuple[tuple[Reference, ...], ...] | None = None,
106
+ orientation_state: StereoOrientationState = StereoOrientationState.UNSPECIFIED,
107
+ evidence_provenance: str = "two_dimensional_connectivity",
108
+ stability_status: StereoStabilityStatus = StereoStabilityStatus.UNASSESSED,
109
+ *,
110
+ support: AxisStereoSupport | None = None,
111
+ ) -> None:
112
+ """Build from typed support or the compatible legacy field pair."""
113
+ if support is None:
114
+ if atom_indices is None or terminal_references is None:
115
+ raise TypeError(
116
+ "Potential stereo loci require axis support or both legacy "
117
+ "atom_indices and terminal_references."
118
+ )
119
+ support = AxisStereoSupport(
120
+ tuple(atom_indices),
121
+ tuple(tuple(frame) for frame in terminal_references), # type: ignore[arg-type]
122
+ )
123
+ elif atom_indices is not None or terminal_references is not None:
124
+ raise TypeError("Supply typed support or legacy support fields, not both.")
125
+ object.__setattr__(self, "locus_type", PotentialStereoLocusType(locus_type))
126
+ object.__setattr__(self, "support", support)
127
+ object.__setattr__(
128
+ self, "orientation_state", StereoOrientationState(orientation_state)
129
+ )
130
+ object.__setattr__(self, "evidence_provenance", evidence_provenance)
131
+ object.__setattr__(
132
+ self, "stability_status", StereoStabilityStatus(stability_status)
133
+ )
134
+
135
+ @property
136
+ def atom_indices(self) -> tuple[int, ...]:
137
+ """Return the compatible axis-path view."""
138
+ return self.support.path
139
+
140
+ @property
141
+ def terminal_references(self) -> tuple[tuple[Reference, Reference], ...]:
142
+ """Return the compatible terminal-frame view."""
143
+ return self.support.terminal_frames
144
+
145
+ @property
146
+ def identifier(self) -> str:
147
+ """Return a deterministic diagnostic identifier."""
148
+ support = "-".join(str(index) for index in self.atom_indices)
149
+ return f"{self.locus_type.value}:{support}"
150
+
151
+
152
+ @dataclass(frozen=True)
153
+ class MolecularChiralityAssessment:
154
+ """Configuration-aware result over every enumerated stereo completion."""
155
+
156
+ outcome: MolecularChiralityOutcome
157
+ observed_classifications: tuple[MolecularChirality, ...]
158
+ input_stereo_status: str
159
+ unspecified_stereo_loci: tuple[str, ...]
160
+ unsupported_stereo_loci: tuple[str, ...]
161
+ theoretical_isomer_upper_bound: int
162
+ evaluated_isomer_count: int
163
+ enumeration_complete: bool
164
+ max_isomers: int
165
+ representative_isomers: tuple[tuple[str, MolecularChirality], ...] = ()
166
+ configured_alternative_count: int = 0
167
+ configured_population_status: str | None = None
168
+ decision_method: str = "stereo_completion_enumeration"
169
+
170
+ @property
171
+ def is_definitive(self) -> bool:
172
+ """Return whether the outcome is proven despite possible truncation."""
173
+ return self.outcome is not MolecularChiralityOutcome.UNSUPPORTED_OR_INCOMPLETE
174
+
175
+
176
+ def molecular_node_match(
177
+ left: Mapping[str, Any],
178
+ right: Mapping[str, Any],
179
+ ) -> bool:
180
+ """Match StereoMolGraph's explicit-H topology without expanding H atoms."""
181
+ return (
182
+ left.get("element") == right.get("element")
183
+ and int(left.get("isotope", 0)) == int(right.get("isotope", 0))
184
+ and int(left.get("hcount", 0)) == int(right.get("hcount", 0))
185
+ and left.get("_molecular_colour") == right.get("_molecular_colour")
186
+ )
187
+
188
+
189
+ def connectivity_edge_match(
190
+ _left: Mapping[str, Any],
191
+ _right: Mapping[str, Any],
192
+ ) -> bool:
193
+ """Use connectivity, not one selected Lewis/resonance bond assignment."""
194
+ return True
195
+
196
+
197
+ def _intern_colours(signatures: Mapping[int, Any]) -> dict[int, int]:
198
+ """Intern comparable signatures into deterministic compact integers."""
199
+ palette = {
200
+ signature: index
201
+ for index, signature in enumerate(sorted(set(signatures.values()), key=repr))
202
+ }
203
+ return {node: palette[signature] for node, signature in signatures.items()}
204
+
205
+
206
+ def molecular_node_colours(graph: Any) -> dict[int, int]:
207
+ """Return map-independent 1-WL molecular identity colours."""
208
+ colours = _intern_colours(
209
+ {
210
+ node: (
211
+ attributes.get("element"),
212
+ int(attributes.get("isotope", 0)),
213
+ int(attributes.get("hcount", 0)),
214
+ )
215
+ for node, attributes in graph.nodes(data=True)
216
+ }
217
+ )
218
+ for _iteration in range(max(1, len(graph))):
219
+ refined = _intern_colours(
220
+ {
221
+ node: (
222
+ colours[node],
223
+ tuple(sorted(colours[neighbor] for neighbor in graph[node])),
224
+ )
225
+ for node in graph
226
+ }
227
+ )
228
+ if refined == colours:
229
+ break
230
+ colours = refined
231
+ return colours