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,668 @@
1
+ """Finite permutation-orbit semantics for local stereochemical frames.
2
+
3
+ The kernel is deliberately independent of descriptor, RDKit, rule, and graph
4
+ objects. A local configuration is an ordered frame modulo the preserving
5
+ permutation group of its shape. Concrete relation witnesses are retained;
6
+ double cosets are invariant classifications, not composable operations.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import dataclass, field
12
+ from enum import Enum
13
+ from functools import cached_property, lru_cache
14
+ from itertools import permutations
15
+ from typing import Any, Hashable, Mapping, Sequence
16
+
17
+
18
+ def _stable_key(values: Sequence[Hashable]) -> tuple[tuple[str, str], ...]:
19
+ return tuple((type(value).__name__, repr(value)) for value in values)
20
+
21
+
22
+ @dataclass(frozen=True, order=True)
23
+ class Permutation:
24
+ """A finite position permutation using ``result[i] = source[image[i]]``."""
25
+
26
+ image: tuple[int, ...]
27
+
28
+ def __post_init__(self) -> None:
29
+ object.__setattr__(self, "image", tuple(self.image))
30
+ if tuple(sorted(self.image)) != tuple(range(len(self.image))):
31
+ raise ValueError("A permutation image must be a bijection on 0..n-1.")
32
+
33
+ @property
34
+ def degree(self) -> int:
35
+ return len(self.image)
36
+
37
+ @classmethod
38
+ def identity(cls, degree: int) -> "Permutation":
39
+ if degree < 0:
40
+ raise ValueError("Permutation degree must be non-negative.")
41
+ return cls(tuple(range(degree)))
42
+
43
+ def apply(self, values: Sequence[Any]) -> tuple[Any, ...]:
44
+ if len(values) != self.degree:
45
+ raise ValueError("Permutation and frame arities differ.")
46
+ return tuple(values[index] for index in self.image)
47
+
48
+ def then(self, after: "Permutation") -> "Permutation":
49
+ """Sequence tuple reorderings: ``after.apply(self.apply(values))``.
50
+
51
+ The resulting slot image is ``self ∘ after``. Slot-map composition
52
+ and composition of their tuple-reordering operators have opposite order.
53
+ """
54
+ if self.degree != after.degree:
55
+ raise ValueError("Only permutations of equal degree compose.")
56
+ return Permutation(tuple(self.image[index] for index in after.image))
57
+
58
+ def inverse(self) -> "Permutation":
59
+ inverse = [0] * self.degree
60
+ for output, source in enumerate(self.image):
61
+ inverse[source] = output
62
+ return Permutation(tuple(inverse))
63
+
64
+
65
+ @dataclass(frozen=True)
66
+ class PermutationGroup:
67
+ """A validated finite permutation group of one fixed degree."""
68
+
69
+ name: str
70
+ degree: int
71
+ elements: tuple[Permutation, ...]
72
+ _closed_by_construction: bool = field(
73
+ default=False,
74
+ repr=False,
75
+ compare=False,
76
+ )
77
+ _symmetric_positions: tuple[int, ...] | None = field(
78
+ default=None,
79
+ repr=False,
80
+ compare=False,
81
+ )
82
+
83
+ def __post_init__(self) -> None:
84
+ elements = tuple(sorted(set(self.elements)))
85
+ object.__setattr__(self, "elements", elements)
86
+ if self.degree < 0 or not elements:
87
+ raise ValueError("A finite permutation group must be non-empty.")
88
+ if any(element.degree != self.degree for element in elements):
89
+ raise ValueError("Every group element must have the declared degree.")
90
+ images = {element.image for element in elements}
91
+ identity = Permutation.identity(self.degree)
92
+ if identity.image not in images:
93
+ raise ValueError("A permutation group must contain its identity.")
94
+ if any(element.inverse().image not in images for element in elements):
95
+ raise ValueError("A permutation group must contain every inverse.")
96
+ if not self._closed_by_construction:
97
+ for left in elements:
98
+ for right in elements:
99
+ image = tuple(left.image[index] for index in right.image)
100
+ if image not in images:
101
+ raise ValueError("A permutation group must be closed.")
102
+
103
+ def __contains__(self, value: object) -> bool:
104
+ return isinstance(value, Permutation) and value in self.elements
105
+
106
+ def orbit(self, frame: Sequence[Hashable]) -> tuple[tuple[Hashable, ...], ...]:
107
+ if len(frame) != self.degree:
108
+ raise ValueError("Group and frame arities differ.")
109
+ forms = {element.apply(frame) for element in self.elements}
110
+ return tuple(sorted(forms, key=_stable_key))
111
+
112
+ def canonical(self, frame: Sequence[Hashable]) -> tuple[Hashable, ...]:
113
+ if self._symmetric_positions is not None:
114
+ if len(frame) != self.degree:
115
+ raise ValueError("Group and frame arities differ.")
116
+ canonical = list(frame)
117
+ ordered = sorted(
118
+ (frame[position] for position in self._symmetric_positions),
119
+ key=lambda value: (type(value).__name__, repr(value)),
120
+ )
121
+ for position, value in zip(self._symmetric_positions, ordered):
122
+ canonical[position] = value
123
+ return tuple(canonical)
124
+ return self.orbit(frame)[0]
125
+
126
+
127
+ def _lift_permutation(
128
+ degree: int,
129
+ positions: Sequence[int],
130
+ local_image: Sequence[int],
131
+ ) -> Permutation:
132
+ image = list(range(degree))
133
+ for output, local_source in enumerate(local_image):
134
+ image[positions[output]] = positions[local_source]
135
+ return Permutation(tuple(image))
136
+
137
+
138
+ def _symmetric_group(
139
+ name: str,
140
+ degree: int,
141
+ positions: Sequence[int],
142
+ ) -> PermutationGroup:
143
+ elements = tuple(
144
+ _lift_permutation(degree, positions, local_image)
145
+ for local_image in permutations(range(len(positions)))
146
+ )
147
+ # All bijections of a finite position set are closed under composition.
148
+ return PermutationGroup(
149
+ name,
150
+ degree,
151
+ elements,
152
+ _closed_by_construction=True,
153
+ _symmetric_positions=tuple(positions),
154
+ )
155
+
156
+
157
+ def _permutation_sign(image: Sequence[int]) -> int:
158
+ inversions = sum(
159
+ image[left] > image[right]
160
+ for left in range(len(image))
161
+ for right in range(left + 1, len(image))
162
+ )
163
+ return -1 if inversions % 2 else 1
164
+
165
+
166
+ def _alternating_group(
167
+ name: str,
168
+ degree: int,
169
+ positions: Sequence[int],
170
+ ) -> PermutationGroup:
171
+ elements = tuple(
172
+ _lift_permutation(degree, positions, local_image)
173
+ for local_image in permutations(range(len(positions)))
174
+ if _permutation_sign(local_image) == 1
175
+ )
176
+ # Even permutations are the kernel of the sign homomorphism and are closed.
177
+ return PermutationGroup(name, degree, elements, _closed_by_construction=True)
178
+
179
+
180
+ def _group_from_images(
181
+ name: str,
182
+ images: Sequence[Sequence[int]],
183
+ ) -> PermutationGroup:
184
+ elements = tuple(Permutation(tuple(image)) for image in images)
185
+ return PermutationGroup(name, len(elements[0].image), elements)
186
+
187
+
188
+ def _generated_group(
189
+ name: str,
190
+ degree: int,
191
+ generators: Sequence[Permutation],
192
+ ) -> PermutationGroup:
193
+ identity = Permutation.identity(degree)
194
+ discovered = {identity}
195
+ frontier = [identity]
196
+ while frontier:
197
+ current = frontier.pop()
198
+ for generator in generators:
199
+ for candidate in (current.then(generator), generator.then(current)):
200
+ if candidate not in discovered:
201
+ discovered.add(candidate)
202
+ frontier.append(candidate)
203
+ # The fixed-point iteration stops only after the generator closure is complete.
204
+ return PermutationGroup(
205
+ name,
206
+ degree,
207
+ tuple(discovered),
208
+ _closed_by_construction=True,
209
+ )
210
+
211
+
212
+ class StereoSpecification(str, Enum):
213
+ FIXED = "fixed"
214
+ UNSPECIFIED = "unspecified"
215
+
216
+
217
+ class StereoRelationKind(str, Enum):
218
+ EQUIVALENT = "equivalent"
219
+ OPPOSITE = "opposite"
220
+ RECONFIGURED = "reconfigured"
221
+ UNRELATED = "unrelated"
222
+ UNSPECIFIED = "unspecified"
223
+
224
+
225
+ @dataclass(frozen=True)
226
+ class ShapeDefinition:
227
+ """Geometry-specific frame positions and admissible permutation groups."""
228
+
229
+ name: str
230
+ frame_arity: int
231
+ locus_positions: frozenset[int]
232
+ preserving_group: PermutationGroup
233
+ unspecified_group: PermutationGroup
234
+ opposite_permutation: Permutation | None = None
235
+
236
+ def __post_init__(self) -> None:
237
+ object.__setattr__(self, "locus_positions", frozenset(self.locus_positions))
238
+ if self.preserving_group.degree != self.frame_arity:
239
+ raise ValueError("The preserving group has the wrong frame arity.")
240
+ if self.unspecified_group.degree != self.frame_arity:
241
+ raise ValueError("The unspecified group has the wrong frame arity.")
242
+ if not self.locus_positions <= frozenset(range(self.frame_arity)):
243
+ raise ValueError("Locus positions must lie inside the local frame.")
244
+ preserving = set(self.preserving_group.elements)
245
+ unspecified = set(self.unspecified_group.elements)
246
+ if not preserving <= unspecified:
247
+ raise ValueError("The unspecified group must contain the preserving group.")
248
+ if self.opposite_permutation is not None:
249
+ if self.opposite_permutation not in unspecified:
250
+ raise ValueError(
251
+ "An opposite witness must be admissible for the shape."
252
+ )
253
+ if self.opposite_permutation in preserving:
254
+ raise ValueError("An opposite witness cannot preserve configuration.")
255
+
256
+ @property
257
+ def reference_positions(self) -> tuple[int, ...]:
258
+ return tuple(
259
+ position
260
+ for position in range(self.frame_arity)
261
+ if position not in self.locus_positions
262
+ )
263
+
264
+ def group_for(self, specification: StereoSpecification) -> PermutationGroup:
265
+ return (
266
+ self.preserving_group
267
+ if specification is StereoSpecification.FIXED
268
+ else self.unspecified_group
269
+ )
270
+
271
+
272
+ @dataclass(frozen=True)
273
+ class PermutationWitness:
274
+ """A replayable relative permutation between two concrete frames."""
275
+
276
+ shape: str
277
+ permutation: Permutation
278
+
279
+ def apply(self, frame: Sequence[Hashable]) -> tuple[Hashable, ...]:
280
+ return self.permutation.apply(frame)
281
+
282
+ def then(self, after: "PermutationWitness") -> "PermutationWitness":
283
+ if self.shape != after.shape:
284
+ raise ValueError("Stereo witnesses compose only within one shape.")
285
+ return PermutationWitness(
286
+ self.shape,
287
+ self.permutation.then(after.permutation),
288
+ )
289
+
290
+
291
+ @dataclass(frozen=True)
292
+ class StereoRelation:
293
+ kind: StereoRelationKind
294
+ shape: str | None
295
+ class_id: tuple[int, ...] | None = None
296
+ witness: PermutationWitness | None = None
297
+ source_canonical: tuple[Hashable, ...] | None = None
298
+ target_canonical: tuple[Hashable, ...] | None = None
299
+
300
+ @property
301
+ def replayable(self) -> bool:
302
+ return self.witness is not None
303
+
304
+
305
+ @lru_cache(maxsize=None)
306
+ def _cached_double_coset_id(
307
+ shape: str,
308
+ witness_image: tuple[int, ...],
309
+ ) -> tuple[int, ...]:
310
+ """Return ``min(G pi G)`` by direct tuple action, cached per witness."""
311
+ group = SHAPE_DEFINITIONS[shape].preserving_group.elements
312
+ images = {
313
+ tuple(
314
+ left.image[witness_image[right.image[position]]]
315
+ for position in range(len(witness_image))
316
+ )
317
+ for left in group
318
+ for right in group
319
+ }
320
+ return min(images)
321
+
322
+
323
+ @dataclass(frozen=True, eq=False)
324
+ class StereoConfiguration:
325
+ """One local frame modulo the fixed or unspecified group of its shape."""
326
+
327
+ shape: str
328
+ frame: tuple[Hashable, ...]
329
+ specification: StereoSpecification = StereoSpecification.FIXED
330
+
331
+ def __post_init__(self) -> None:
332
+ if not isinstance(self.specification, StereoSpecification):
333
+ object.__setattr__(
334
+ self,
335
+ "specification",
336
+ StereoSpecification(self.specification),
337
+ )
338
+ object.__setattr__(self, "frame", tuple(self.frame))
339
+ definition = self.definition
340
+ if len(self.frame) != definition.frame_arity:
341
+ raise ValueError(
342
+ f"Shape {self.shape!r} requires {definition.frame_arity} frame values."
343
+ )
344
+ try:
345
+ unique = len(set(self.frame))
346
+ except TypeError as exc:
347
+ raise TypeError("Stereo frame references must be hashable.") from exc
348
+ if unique != len(self.frame):
349
+ raise ValueError("Stereo frame references must be distinct.")
350
+
351
+ @property
352
+ def definition(self) -> ShapeDefinition:
353
+ try:
354
+ return SHAPE_DEFINITIONS[self.shape]
355
+ except KeyError as exc:
356
+ raise ValueError(f"Unknown stereo shape {self.shape!r}.") from exc
357
+
358
+ @cached_property
359
+ def canonical_frame(self) -> tuple[Hashable, ...]:
360
+ return self.definition.group_for(self.specification).canonical(self.frame)
361
+
362
+ def canonical_form(self) -> tuple[Any, ...]:
363
+ return self.shape, self.specification.value, self.canonical_frame
364
+
365
+ def same_configuration(self, other: object) -> bool:
366
+ return (
367
+ isinstance(other, StereoConfiguration)
368
+ and self.shape == other.shape
369
+ and self.specification is other.specification
370
+ and self.canonical_frame == other.canonical_frame
371
+ )
372
+
373
+ def __eq__(self, other: object) -> bool:
374
+ return self.same_configuration(other)
375
+
376
+ def __hash__(self) -> int:
377
+ return hash(self.canonical_form())
378
+
379
+ def relabel(self, mapping: Mapping[Hashable, Hashable]) -> "StereoConfiguration":
380
+ return StereoConfiguration(
381
+ self.shape,
382
+ tuple(mapping.get(reference, reference) for reference in self.frame),
383
+ self.specification,
384
+ )
385
+
386
+ def replace_reference(
387
+ self,
388
+ old: Hashable,
389
+ new: Hashable,
390
+ ) -> "StereoConfiguration":
391
+ return self.replace_references({old: new})
392
+
393
+ def replace_references(
394
+ self,
395
+ replacements: Mapping[Hashable, Hashable],
396
+ ) -> "StereoConfiguration":
397
+ unknown = set(replacements) - set(self.frame)
398
+ if unknown:
399
+ raise ValueError(
400
+ f"Replacement sources are absent: {sorted(map(repr, unknown))}."
401
+ )
402
+ protected = {
403
+ self.frame[position] for position in self.definition.locus_positions
404
+ }
405
+ replaced_loci = protected & set(replacements)
406
+ if replaced_loci:
407
+ raise ValueError("Reference replacement cannot replace descriptor loci.")
408
+ return StereoConfiguration(
409
+ self.shape,
410
+ tuple(replacements.get(reference, reference) for reference in self.frame),
411
+ self.specification,
412
+ )
413
+
414
+ def _witness_to(self, other: "StereoConfiguration") -> Permutation | None:
415
+ for permutation in self.definition.unspecified_group.elements:
416
+ if permutation.apply(self.frame) == other.frame:
417
+ return permutation
418
+ return None
419
+
420
+ def _double_coset_id(self, witness: Permutation) -> tuple[int, ...]:
421
+ return _cached_double_coset_id(self.shape, witness.image)
422
+
423
+ def _opposite_class_id(self) -> tuple[int, ...] | None:
424
+ opposite = self.definition.opposite_permutation
425
+ return None if opposite is None else self._double_coset_id(opposite)
426
+
427
+ def relation_to(self, other: object) -> StereoRelation:
428
+ if not isinstance(other, StereoConfiguration) or self.shape != other.shape:
429
+ return StereoRelation(StereoRelationKind.UNRELATED, None)
430
+ witness = self._witness_to(other)
431
+ if witness is None:
432
+ return StereoRelation(
433
+ StereoRelationKind.UNRELATED,
434
+ self.shape,
435
+ source_canonical=self.canonical_frame,
436
+ target_canonical=other.canonical_frame,
437
+ )
438
+ wrapped = PermutationWitness(self.shape, witness)
439
+ if (
440
+ self.specification is StereoSpecification.UNSPECIFIED
441
+ or other.specification is StereoSpecification.UNSPECIFIED
442
+ ):
443
+ return StereoRelation(
444
+ StereoRelationKind.UNSPECIFIED,
445
+ self.shape,
446
+ witness=wrapped,
447
+ source_canonical=self.canonical_frame,
448
+ target_canonical=other.canonical_frame,
449
+ )
450
+ class_id = self._double_coset_id(witness)
451
+ if witness in self.definition.preserving_group:
452
+ kind = StereoRelationKind.EQUIVALENT
453
+ elif class_id == self._opposite_class_id():
454
+ kind = StereoRelationKind.OPPOSITE
455
+ else:
456
+ kind = StereoRelationKind.RECONFIGURED
457
+ return StereoRelation(
458
+ kind,
459
+ self.shape,
460
+ class_id,
461
+ wrapped,
462
+ self.canonical_frame,
463
+ other.canonical_frame,
464
+ )
465
+
466
+ def opposite(self) -> "StereoConfiguration":
467
+ opposite = self.definition.opposite_permutation
468
+ if opposite is None:
469
+ raise ValueError(f"Shape {self.shape!r} has no binary opposite operation.")
470
+ if self.specification is StereoSpecification.UNSPECIFIED:
471
+ return self
472
+ return StereoConfiguration(
473
+ self.shape,
474
+ opposite.apply(self.frame),
475
+ self.specification,
476
+ )
477
+
478
+
479
+ _TETRA_FIXED = _alternating_group("tetrahedral:A4", 5, (1, 2, 3, 4))
480
+ _TETRA_ALL = _symmetric_group("tetrahedral:S4", 5, (1, 2, 3, 4))
481
+ _TETRA_OPPOSITE = Permutation((0, 2, 1, 3, 4))
482
+
483
+ _SQUARE_FIXED = _group_from_images(
484
+ "square_planar:D4",
485
+ (
486
+ (0, 1, 2, 3, 4),
487
+ (0, 2, 3, 4, 1),
488
+ (0, 3, 4, 1, 2),
489
+ (0, 4, 1, 2, 3),
490
+ (0, 4, 3, 2, 1),
491
+ (0, 3, 2, 1, 4),
492
+ (0, 2, 1, 4, 3),
493
+ (0, 1, 4, 3, 2),
494
+ ),
495
+ )
496
+ _SQUARE_ALL = _symmetric_group("square_planar:S4", 5, (1, 2, 3, 4))
497
+
498
+ _TBP_FIXED = _group_from_images(
499
+ "trigonal_bipyramidal:D3",
500
+ (
501
+ (0, 1, 2, 3, 4, 5),
502
+ (0, 1, 2, 5, 3, 4),
503
+ (0, 1, 2, 4, 5, 3),
504
+ (0, 2, 1, 3, 5, 4),
505
+ (0, 2, 1, 5, 4, 3),
506
+ (0, 2, 1, 4, 3, 5),
507
+ ),
508
+ )
509
+ _TBP_ALL = _symmetric_group("trigonal_bipyramidal:S5", 6, (1, 2, 3, 4, 5))
510
+
511
+ _OCT_FIXED = _group_from_images(
512
+ "octahedral:O",
513
+ (
514
+ (0, 1, 2, 3, 4, 5, 6),
515
+ (0, 1, 2, 6, 3, 4, 5),
516
+ (0, 1, 2, 5, 6, 3, 4),
517
+ (0, 1, 2, 4, 5, 6, 3),
518
+ (0, 2, 1, 4, 3, 6, 5),
519
+ (0, 2, 1, 5, 4, 3, 6),
520
+ (0, 2, 1, 6, 5, 4, 3),
521
+ (0, 2, 1, 3, 6, 5, 4),
522
+ (0, 3, 5, 2, 4, 1, 6),
523
+ (0, 3, 5, 6, 2, 4, 1),
524
+ (0, 3, 5, 1, 6, 2, 4),
525
+ (0, 3, 5, 4, 1, 6, 2),
526
+ (0, 5, 3, 1, 4, 2, 6),
527
+ (0, 5, 3, 6, 1, 4, 2),
528
+ (0, 5, 3, 2, 6, 1, 4),
529
+ (0, 5, 3, 4, 2, 6, 1),
530
+ (0, 4, 6, 3, 2, 5, 1),
531
+ (0, 4, 6, 1, 3, 2, 5),
532
+ (0, 4, 6, 5, 1, 3, 2),
533
+ (0, 4, 6, 2, 5, 1, 3),
534
+ (0, 6, 4, 3, 1, 5, 2),
535
+ (0, 6, 4, 2, 3, 1, 5),
536
+ (0, 6, 4, 5, 2, 3, 1),
537
+ (0, 6, 4, 1, 5, 2, 3),
538
+ ),
539
+ )
540
+ _OCT_ALL = _symmetric_group("octahedral:S6", 7, (1, 2, 3, 4, 5, 6))
541
+
542
+ _PLANAR_BOND_FIXED = _group_from_images(
543
+ "planar_bond:V4",
544
+ (
545
+ (0, 1, 2, 3, 4, 5),
546
+ (1, 0, 2, 3, 5, 4),
547
+ (4, 5, 3, 2, 0, 1),
548
+ (5, 4, 3, 2, 1, 0),
549
+ ),
550
+ )
551
+ _PLANAR_BOND_ALL = _generated_group(
552
+ "planar_bond:unknown",
553
+ 6,
554
+ (
555
+ Permutation((1, 0, 2, 3, 5, 4)),
556
+ Permutation((4, 5, 3, 2, 0, 1)),
557
+ Permutation((1, 0, 2, 3, 4, 5)),
558
+ ),
559
+ )
560
+ _BOND_OPPOSITE = Permutation((1, 0, 2, 3, 4, 5))
561
+
562
+ _ATROP_BOND_FIXED = _group_from_images(
563
+ "atrop_bond:V4",
564
+ (
565
+ (0, 1, 2, 3, 4, 5),
566
+ (1, 0, 2, 3, 5, 4),
567
+ (4, 5, 3, 2, 1, 0),
568
+ (5, 4, 3, 2, 0, 1),
569
+ ),
570
+ )
571
+ _ATROP_BOND_ALL = _generated_group(
572
+ "atrop_bond:unknown",
573
+ 6,
574
+ (
575
+ Permutation((1, 0, 2, 3, 5, 4)),
576
+ Permutation((4, 5, 3, 2, 1, 0)),
577
+ Permutation((1, 0, 2, 3, 4, 5)),
578
+ ),
579
+ )
580
+
581
+ _CUMULENE_AXIS_FIXED = _group_from_images(
582
+ "cumulene_axis:V4",
583
+ tuple(permutation.image for permutation in _ATROP_BOND_FIXED.elements),
584
+ )
585
+ _CUMULENE_AXIS_ALL = _generated_group(
586
+ "cumulene_axis:unknown",
587
+ 6,
588
+ (
589
+ Permutation((1, 0, 2, 3, 5, 4)),
590
+ Permutation((4, 5, 3, 2, 1, 0)),
591
+ Permutation((1, 0, 2, 3, 4, 5)),
592
+ ),
593
+ )
594
+
595
+ _EXTENDED_CIS_TRANS_FIXED = _group_from_images(
596
+ "extended_cis_trans:V4",
597
+ tuple(permutation.image for permutation in _PLANAR_BOND_FIXED.elements),
598
+ )
599
+ _EXTENDED_CIS_TRANS_ALL = _generated_group(
600
+ "extended_cis_trans:unknown",
601
+ 6,
602
+ (
603
+ Permutation((1, 0, 2, 3, 5, 4)),
604
+ Permutation((4, 5, 3, 2, 0, 1)),
605
+ Permutation((1, 0, 2, 3, 4, 5)),
606
+ ),
607
+ )
608
+
609
+
610
+ SHAPE_DEFINITIONS: Mapping[str, ShapeDefinition] = {
611
+ "tetrahedral": ShapeDefinition(
612
+ "tetrahedral", 5, frozenset({0}), _TETRA_FIXED, _TETRA_ALL, _TETRA_OPPOSITE
613
+ ),
614
+ "square_planar": ShapeDefinition(
615
+ "square_planar", 5, frozenset({0}), _SQUARE_FIXED, _SQUARE_ALL
616
+ ),
617
+ "trigonal_bipyramidal": ShapeDefinition(
618
+ "trigonal_bipyramidal", 6, frozenset({0}), _TBP_FIXED, _TBP_ALL
619
+ ),
620
+ "octahedral": ShapeDefinition(
621
+ "octahedral", 7, frozenset({0}), _OCT_FIXED, _OCT_ALL
622
+ ),
623
+ "planar_bond": ShapeDefinition(
624
+ "planar_bond",
625
+ 6,
626
+ frozenset({2, 3}),
627
+ _PLANAR_BOND_FIXED,
628
+ _PLANAR_BOND_ALL,
629
+ _BOND_OPPOSITE,
630
+ ),
631
+ "atrop_bond": ShapeDefinition(
632
+ "atrop_bond",
633
+ 6,
634
+ frozenset({2, 3}),
635
+ _ATROP_BOND_FIXED,
636
+ _ATROP_BOND_ALL,
637
+ _BOND_OPPOSITE,
638
+ ),
639
+ "cumulene_axis": ShapeDefinition(
640
+ "cumulene_axis",
641
+ 6,
642
+ frozenset({2, 3}),
643
+ _CUMULENE_AXIS_FIXED,
644
+ _CUMULENE_AXIS_ALL,
645
+ _BOND_OPPOSITE,
646
+ ),
647
+ "extended_cis_trans": ShapeDefinition(
648
+ "extended_cis_trans",
649
+ 6,
650
+ frozenset({2, 3}),
651
+ _EXTENDED_CIS_TRANS_FIXED,
652
+ _EXTENDED_CIS_TRANS_ALL,
653
+ _BOND_OPPOSITE,
654
+ ),
655
+ }
656
+
657
+
658
+ __all__ = [
659
+ "Permutation",
660
+ "PermutationGroup",
661
+ "PermutationWitness",
662
+ "SHAPE_DEFINITIONS",
663
+ "ShapeDefinition",
664
+ "StereoConfiguration",
665
+ "StereoRelation",
666
+ "StereoRelationKind",
667
+ "StereoSpecification",
668
+ ]