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,349 @@
1
+ """Immutable graph-morphism values and their composition laws."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+ from typing import Any, Hashable, Mapping
8
+
9
+ from .constraints import ConstraintIssue, WildcardConstraint
10
+
11
+
12
+ class MorphismIssueCode(str, Enum):
13
+ """Stable failure codes for morphism construction and composition."""
14
+
15
+ DUPLICATE_SOURCE = "MORPHISM_DUPLICATE_SOURCE"
16
+ NON_INJECTIVE = "MORPHISM_NON_INJECTIVE"
17
+ OUTSIDE_SOURCE = "MORPHISM_OUTSIDE_SOURCE"
18
+ OUTSIDE_TARGET = "MORPHISM_OUTSIDE_TARGET"
19
+ PARTIAL_MAPPING = "MORPHISM_PARTIAL_MAPPING"
20
+ ENDPOINT_MISMATCH = "MORPHISM_ENDPOINT_MISMATCH"
21
+ MISSING_INTERMEDIATE = "MORPHISM_MISSING_INTERMEDIATE"
22
+ CONSTRAINT_CONTRADICTION = "MORPHISM_CONSTRAINT_CONTRADICTION"
23
+ OWNER_OUTSIDE_SOURCE = "MORPHISM_OWNER_OUTSIDE_SOURCE"
24
+ OWNER_OUTSIDE_IMAGE = "MORPHISM_OWNER_OUTSIDE_IMAGE"
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class MorphismIssue:
29
+ """One construction or composition failure."""
30
+
31
+ code: MorphismIssueCode
32
+ message: str
33
+ context: Mapping[str, Any] = field(default_factory=dict)
34
+ constraint_issues: tuple[ConstraintIssue, ...] = ()
35
+
36
+ def to_dict(self) -> dict[str, Any]:
37
+ return {
38
+ "code": self.code.value,
39
+ "message": self.message,
40
+ "context": dict(self.context),
41
+ "constraint_issues": [issue.to_dict() for issue in self.constraint_issues],
42
+ }
43
+
44
+
45
+ class GraphMorphismError(ValueError):
46
+ """Raised when an invalid morphism would be created or composed."""
47
+
48
+ def __init__(self, *issues: MorphismIssue):
49
+ self.issues = tuple(issues)
50
+ message = "; ".join(issue.message for issue in self.issues)
51
+ super().__init__(message)
52
+
53
+
54
+ def _pairs(value: Any) -> tuple[tuple[Hashable, Any], ...]:
55
+ if isinstance(value, Mapping):
56
+ return tuple(value.items())
57
+ return tuple(value)
58
+
59
+
60
+ def _sorted_pairs(
61
+ value: tuple[tuple[Hashable, Any], ...],
62
+ ) -> tuple[tuple[Hashable, Any], ...]:
63
+ return tuple(sorted(value, key=lambda item: (repr(item[0]), repr(item[1]))))
64
+
65
+
66
+ @dataclass(frozen=True)
67
+ class GraphMorphism:
68
+ """An injective embedding ``f`` with wildcard environment ``theta``.
69
+
70
+ ``source`` and ``target`` identify endpoint objects. ``source_nodes`` and
71
+ ``target_nodes`` make totality and injectivity checkable without retaining
72
+ mutable graph objects. Public mappings are normalized to sorted tuples so
73
+ instances remain immutable and hashable.
74
+ """
75
+
76
+ source: Hashable
77
+ target: Hashable
78
+ source_nodes: frozenset[Hashable]
79
+ target_nodes: frozenset[Hashable]
80
+ f: tuple[tuple[Hashable, Hashable], ...]
81
+ theta: tuple[tuple[Hashable, WildcardConstraint], ...] = ()
82
+
83
+ def __post_init__(self) -> None:
84
+ object.__setattr__(self, "source_nodes", frozenset(self.source_nodes))
85
+ object.__setattr__(self, "target_nodes", frozenset(self.target_nodes))
86
+ pairs = _pairs(self.f)
87
+ substitutions = _pairs(self.theta)
88
+ object.__setattr__(self, "f", _sorted_pairs(pairs))
89
+ object.__setattr__(self, "theta", _sorted_pairs(substitutions))
90
+
91
+ source_keys = tuple(key for key, _ in pairs)
92
+ target_values = tuple(value for _, value in pairs)
93
+ issues: list[MorphismIssue] = []
94
+ if len(set(source_keys)) != len(source_keys):
95
+ issues.append(
96
+ MorphismIssue(
97
+ MorphismIssueCode.DUPLICATE_SOURCE,
98
+ "A source node is mapped more than once.",
99
+ )
100
+ )
101
+ if len(set(target_values)) != len(target_values):
102
+ issues.append(
103
+ MorphismIssue(
104
+ MorphismIssueCode.NON_INJECTIVE,
105
+ "Material source nodes must have distinct target images.",
106
+ )
107
+ )
108
+ outside_source = set(source_keys) - set(self.source_nodes)
109
+ if outside_source:
110
+ issues.append(
111
+ MorphismIssue(
112
+ MorphismIssueCode.OUTSIDE_SOURCE,
113
+ "The embedding contains nodes outside its source.",
114
+ {"nodes": tuple(sorted(map(repr, outside_source)))},
115
+ )
116
+ )
117
+ outside_target = set(target_values) - set(self.target_nodes)
118
+ if outside_target:
119
+ issues.append(
120
+ MorphismIssue(
121
+ MorphismIssueCode.OUTSIDE_TARGET,
122
+ "The embedding contains images outside its target.",
123
+ {"nodes": tuple(sorted(map(repr, outside_target)))},
124
+ )
125
+ )
126
+ missing = set(self.source_nodes) - set(source_keys)
127
+ if missing:
128
+ issues.append(
129
+ MorphismIssue(
130
+ MorphismIssueCode.PARTIAL_MAPPING,
131
+ "A graph morphism must map every material source node.",
132
+ {"nodes": tuple(sorted(map(repr, missing)))},
133
+ )
134
+ )
135
+ theta_keys = tuple(key for key, _ in substitutions)
136
+ if len(set(theta_keys)) != len(theta_keys):
137
+ issues.append(
138
+ MorphismIssue(
139
+ MorphismIssueCode.DUPLICATE_SOURCE,
140
+ "A source wildcard has more than one substitution.",
141
+ )
142
+ )
143
+ outside_theta = set(theta_keys) - set(self.source_nodes)
144
+ if outside_theta:
145
+ issues.append(
146
+ MorphismIssue(
147
+ MorphismIssueCode.OUTSIDE_SOURCE,
148
+ "The substitution environment contains unknown source nodes.",
149
+ {"nodes": tuple(sorted(map(repr, outside_theta)))},
150
+ )
151
+ )
152
+ outside_owners = {
153
+ constraint.owner
154
+ for _, constraint in substitutions
155
+ if constraint.owner is not None
156
+ and constraint.owner not in self.source_nodes
157
+ }
158
+ if outside_owners:
159
+ issues.append(
160
+ MorphismIssue(
161
+ MorphismIssueCode.OWNER_OUTSIDE_SOURCE,
162
+ "Wildcard owners must be material nodes in the morphism source.",
163
+ {"nodes": tuple(sorted(map(repr, outside_owners)))},
164
+ )
165
+ )
166
+ if any(not isinstance(value, WildcardConstraint) for _, value in substitutions):
167
+ raise TypeError("theta values must be WildcardConstraint instances.")
168
+ if issues:
169
+ raise GraphMorphismError(*issues)
170
+
171
+ @property
172
+ def mapping(self) -> dict[Hashable, Hashable]:
173
+ """Return a disposable mapping view of ``f``."""
174
+ return dict(self.f)
175
+
176
+ @property
177
+ def substitutions(self) -> dict[Hashable, WildcardConstraint]:
178
+ """Return a disposable mapping view of ``theta``."""
179
+ return dict(self.theta)
180
+
181
+ @classmethod
182
+ def identity(
183
+ cls,
184
+ object_id: Hashable,
185
+ nodes: frozenset[Hashable] | set[Hashable] | tuple[Hashable, ...],
186
+ theta: Mapping[Hashable, WildcardConstraint] | None = None,
187
+ ) -> "GraphMorphism":
188
+ """Return the identity morphism for one endpoint object."""
189
+ frozen_nodes = frozenset(nodes)
190
+ return cls(
191
+ object_id,
192
+ object_id,
193
+ frozen_nodes,
194
+ frozen_nodes,
195
+ tuple((node, node) for node in frozen_nodes),
196
+ tuple((theta or {}).items()),
197
+ )
198
+
199
+ def then(self, after: "GraphMorphism") -> "GraphMorphism":
200
+ """Return ``after ∘ self`` with normalized constraint intersection."""
201
+ if self.target != after.source or self.target_nodes != after.source_nodes:
202
+ raise GraphMorphismError(
203
+ MorphismIssue(
204
+ MorphismIssueCode.ENDPOINT_MISMATCH,
205
+ "Composable morphisms must share the same intermediate object.",
206
+ {
207
+ "left_target": repr(self.target),
208
+ "right_source": repr(after.source),
209
+ },
210
+ )
211
+ )
212
+
213
+ left_map = self.mapping
214
+ right_map = after.mapping
215
+ composed: dict[Hashable, Hashable] = {}
216
+ for source_node, intermediate in left_map.items():
217
+ if intermediate not in right_map:
218
+ raise GraphMorphismError(
219
+ MorphismIssue(
220
+ MorphismIssueCode.MISSING_INTERMEDIATE,
221
+ "The second morphism does not map an intermediate image.",
222
+ {"node": repr(intermediate)},
223
+ )
224
+ )
225
+ composed[source_node] = right_map[intermediate]
226
+
227
+ left_theta = self.substitutions
228
+ right_theta = after.substitutions
229
+ inverse_left = {target: source for source, target in self.f}
230
+ composed_theta: dict[Hashable, WildcardConstraint] = {}
231
+ for source_node, intermediate in left_map.items():
232
+ left_constraint = left_theta.get(source_node)
233
+ right_constraint = right_theta.get(intermediate)
234
+ if right_constraint is not None:
235
+ if (
236
+ right_constraint.owner is not None
237
+ and right_constraint.owner not in inverse_left
238
+ ):
239
+ raise GraphMorphismError(
240
+ MorphismIssue(
241
+ MorphismIssueCode.OWNER_OUTSIDE_IMAGE,
242
+ "A composed wildcard owner lies outside the first image.",
243
+ {"owner": repr(right_constraint.owner)},
244
+ )
245
+ )
246
+ right_constraint = right_constraint.relabel_owner(inverse_left)
247
+ if left_constraint is None and right_constraint is None:
248
+ continue
249
+ if left_constraint is None:
250
+ composed_theta[source_node] = right_constraint # type: ignore[assignment]
251
+ continue
252
+ if right_constraint is None:
253
+ composed_theta[source_node] = left_constraint
254
+ continue
255
+ result = left_constraint.intersect(right_constraint)
256
+ if not result.valid:
257
+ raise GraphMorphismError(
258
+ MorphismIssue(
259
+ MorphismIssueCode.CONSTRAINT_CONTRADICTION,
260
+ "Wildcard constraints contradict during composition.",
261
+ {"source_node": repr(source_node)},
262
+ result.issues,
263
+ )
264
+ )
265
+ composed_theta[source_node] = result.constraint # type: ignore[assignment]
266
+
267
+ return GraphMorphism(
268
+ self.source,
269
+ after.target,
270
+ self.source_nodes,
271
+ after.target_nodes,
272
+ tuple(composed.items()),
273
+ tuple(composed_theta.items()),
274
+ )
275
+
276
+ def compose(self, after: "GraphMorphism") -> "GraphMorphism":
277
+ """Alias for :meth:`then`; computes ``after ∘ self``."""
278
+ return self.then(after)
279
+
280
+ def relabel(
281
+ self,
282
+ source_labels: Mapping[Hashable, Hashable],
283
+ target_labels: Mapping[Hashable, Hashable],
284
+ *,
285
+ source: Hashable | None = None,
286
+ target: Hashable | None = None,
287
+ ) -> "GraphMorphism":
288
+ """Return an isomorphic morphism under endpoint node bijections."""
289
+ if set(source_labels) != set(self.source_nodes):
290
+ raise ValueError("source_labels must be total on source_nodes.")
291
+ if set(target_labels) != set(self.target_nodes):
292
+ raise ValueError("target_labels must be total on target_nodes.")
293
+ return GraphMorphism(
294
+ self.source if source is None else source,
295
+ self.target if target is None else target,
296
+ frozenset(source_labels.values()),
297
+ frozenset(target_labels.values()),
298
+ tuple(
299
+ (source_labels[left], target_labels[right]) for left, right in self.f
300
+ ),
301
+ tuple(
302
+ (source_labels[node], constraint.relabel_owner(source_labels))
303
+ for node, constraint in self.theta
304
+ ),
305
+ )
306
+
307
+ def canonical_signature(self) -> tuple[Any, ...]:
308
+ """Return a node-numbering-independent contract signature.
309
+
310
+ Sprint 14 morphisms intentionally retain no graph adjacency. Their
311
+ numbering-independent content is therefore embedding cardinality plus
312
+ canonical bundles of normalized constraints and owner incidence.
313
+ Sprint 15 can extend this with graph incidence when it constructs
314
+ fusion diagrams.
315
+ """
316
+ base_by_node: dict[Hashable, tuple[Any, ...] | None] = {
317
+ node: None for node in self.source_nodes
318
+ }
319
+ incoming: dict[Hashable, list[tuple[Any, ...]]] = {
320
+ node: [] for node in self.source_nodes
321
+ }
322
+ for node, constraint in self.theta:
323
+ values = list(constraint.normalized())
324
+ values[6] = None
325
+ base = tuple(values)
326
+ base_by_node[node] = base
327
+ if constraint.owner is not None:
328
+ incoming[constraint.owner].append(base)
329
+ owner_bundles = tuple(
330
+ sorted(
331
+ [
332
+ (
333
+ base_by_node[node],
334
+ tuple(sorted(incoming[node], key=repr)),
335
+ )
336
+ for node in self.source_nodes
337
+ ],
338
+ key=repr,
339
+ )
340
+ )
341
+ return (len(self.source_nodes), len(self.target_nodes), owner_bundles)
342
+
343
+
344
+ __all__ = [
345
+ "GraphMorphism",
346
+ "GraphMorphismError",
347
+ "MorphismIssue",
348
+ "MorphismIssueCode",
349
+ ]
@@ -0,0 +1,258 @@
1
+ """Stereo-reference-frame transport through graph morphisms."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+ from typing import Any, Mapping
8
+
9
+ from synkit.Graph.Stereo.descriptors import (
10
+ Reference,
11
+ StereoValue,
12
+ descriptor_id,
13
+ parse_virtual_reference,
14
+ virtual_reference,
15
+ )
16
+
17
+
18
+ class StereoEffect(str, Enum):
19
+ """Declared orientation effect carried by a reaction rule."""
20
+
21
+ RETAIN = "retain"
22
+ INVERT = "invert"
23
+ UNSPECIFIED = "unspecified"
24
+
25
+
26
+ class StereoTransportIssueCode(str, Enum):
27
+ """Stable stereo-frame transport failure codes."""
28
+
29
+ DELTA_ARITY = "STEREO_DELTA_ARITY"
30
+ DUPLICATE_REFERENCE = "STEREO_DUPLICATE_REFERENCE"
31
+ REFERENCE_NOT_FOUND = "STEREO_REFERENCE_NOT_FOUND"
32
+ OWNER_REPLACEMENT = "STEREO_OWNER_REPLACEMENT"
33
+ MISSING_NODE_MAPPING = "STEREO_MISSING_NODE_MAPPING"
34
+ WRONG_OWNER = "STEREO_WRONG_OWNER"
35
+ NON_INJECTIVE = "STEREO_NON_INJECTIVE"
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class StereoTransportIssue:
40
+ code: StereoTransportIssueCode
41
+ message: str
42
+ context: Mapping[str, Any] = field(default_factory=dict)
43
+
44
+ def to_dict(self) -> dict[str, Any]:
45
+ return {
46
+ "code": self.code.value,
47
+ "message": self.message,
48
+ "context": dict(self.context),
49
+ }
50
+
51
+
52
+ class StereoTransportError(ValueError):
53
+ """Raised when an ordered stereo frame cannot be transported safely."""
54
+
55
+ def __init__(self, issue: StereoTransportIssue):
56
+ self.issue = issue
57
+ super().__init__(issue.message)
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class StereoReferenceDelta:
62
+ """Explicit ligand replacements and their declared stereo effect.
63
+
64
+ Removed references belong to the source frame. Added references belong
65
+ to the target frame; they are therefore not passed through the node map.
66
+ """
67
+
68
+ removed: tuple[Reference, ...] = ()
69
+ added: tuple[Reference, ...] = ()
70
+ effect: StereoEffect = StereoEffect.RETAIN
71
+
72
+ def __post_init__(self) -> None:
73
+ if not isinstance(self.effect, StereoEffect):
74
+ object.__setattr__(self, "effect", StereoEffect(self.effect))
75
+ if len(self.removed) != len(self.added):
76
+ raise StereoTransportError(
77
+ StereoTransportIssue(
78
+ StereoTransportIssueCode.DELTA_ARITY,
79
+ "Removed and added stereo references must pair one-to-one.",
80
+ )
81
+ )
82
+ if len(set(self.removed)) != len(self.removed) or len(set(self.added)) != len(
83
+ self.added
84
+ ):
85
+ raise StereoTransportError(
86
+ StereoTransportIssue(
87
+ StereoTransportIssueCode.DUPLICATE_REFERENCE,
88
+ "Stereo reference deltas cannot contain duplicate endpoints.",
89
+ )
90
+ )
91
+
92
+ @property
93
+ def replacements(self) -> dict[Reference, Reference]:
94
+ return dict(zip(self.removed, self.added, strict=True))
95
+
96
+
97
+ def _owner_positions(descriptor: StereoValue) -> frozenset[int]:
98
+ if descriptor.descriptor_class in {
99
+ "tetrahedral",
100
+ "square_planar",
101
+ "trigonal_bipyramidal",
102
+ "octahedral",
103
+ }:
104
+ return frozenset({0})
105
+ return frozenset({2, 3})
106
+
107
+
108
+ def _transport_reference(
109
+ reference: Reference,
110
+ mapping: Mapping[int, int],
111
+ ) -> Reference:
112
+ if type(reference) is int:
113
+ if reference not in mapping:
114
+ raise StereoTransportError(
115
+ StereoTransportIssue(
116
+ StereoTransportIssueCode.MISSING_NODE_MAPPING,
117
+ "Every retained material stereo reference must be mapped.",
118
+ {"reference": reference},
119
+ )
120
+ )
121
+ return mapping[reference]
122
+ virtual = parse_virtual_reference(reference)
123
+ if virtual is None:
124
+ raise StereoTransportError(
125
+ StereoTransportIssue(
126
+ StereoTransportIssueCode.WRONG_OWNER,
127
+ "Stereo references must be material nodes or typed virtual references.",
128
+ {"reference": repr(reference)},
129
+ )
130
+ )
131
+ if virtual.center not in mapping:
132
+ raise StereoTransportError(
133
+ StereoTransportIssue(
134
+ StereoTransportIssueCode.MISSING_NODE_MAPPING,
135
+ "The owner of a retained virtual stereo reference must be mapped.",
136
+ {"owner": virtual.center},
137
+ )
138
+ )
139
+ return virtual_reference(virtual.kind, mapping[virtual.center])
140
+
141
+
142
+ def transport_stereo_descriptor(
143
+ descriptor: StereoValue,
144
+ mapping: Mapping[int, int],
145
+ delta: StereoReferenceDelta | None = None,
146
+ ) -> StereoValue:
147
+ """Transport an ordered stereo frame through an injective node mapping."""
148
+ change = delta or StereoReferenceDelta()
149
+ replacements = change.replacements
150
+ atoms = descriptor.atoms
151
+ retained_material = {
152
+ reference
153
+ for reference in atoms
154
+ if type(reference) is int and reference not in replacements
155
+ }
156
+ retained_images = [
157
+ mapping[reference] for reference in retained_material if reference in mapping
158
+ ]
159
+ if len(set(retained_images)) != len(retained_images):
160
+ raise StereoTransportError(
161
+ StereoTransportIssue(
162
+ StereoTransportIssueCode.NON_INJECTIVE,
163
+ "Material stereo references must retain distinct graph images.",
164
+ )
165
+ )
166
+ missing = tuple(reference for reference in change.removed if reference not in atoms)
167
+ if missing:
168
+ raise StereoTransportError(
169
+ StereoTransportIssue(
170
+ StereoTransportIssueCode.REFERENCE_NOT_FOUND,
171
+ "A removed ligand is not present in the source stereo frame.",
172
+ {"references": tuple(map(repr, missing))},
173
+ )
174
+ )
175
+ owner_positions = _owner_positions(descriptor)
176
+ replaced_owners = tuple(
177
+ atoms[position]
178
+ for position in owner_positions
179
+ if atoms[position] in replacements
180
+ )
181
+ if replaced_owners:
182
+ raise StereoTransportError(
183
+ StereoTransportIssue(
184
+ StereoTransportIssueCode.OWNER_REPLACEMENT,
185
+ "Reference deltas replace ligands, not descriptor owners.",
186
+ {"owners": tuple(map(repr, replaced_owners))},
187
+ )
188
+ )
189
+
190
+ transported = tuple(
191
+ (
192
+ replacements[reference]
193
+ if reference in replacements
194
+ else _transport_reference(reference, mapping)
195
+ )
196
+ for reference in atoms
197
+ )
198
+ try:
199
+ result = type(descriptor)(transported, descriptor.parity, descriptor.provenance)
200
+ except ValueError as exc:
201
+ raise StereoTransportError(
202
+ StereoTransportIssue(
203
+ StereoTransportIssueCode.WRONG_OWNER,
204
+ "The transported frame violates owner or ligand-slot semantics.",
205
+ {"reason": str(exc)},
206
+ )
207
+ ) from exc
208
+
209
+ if change.effect is StereoEffect.INVERT:
210
+ return result.invert()
211
+ if change.effect is StereoEffect.UNSPECIFIED:
212
+ return type(result)(result.atoms, None, result.provenance)
213
+ return result
214
+
215
+
216
+ def transport_stereo_registry(
217
+ registry: Mapping[str, StereoValue],
218
+ mapping: Mapping[int, int],
219
+ deltas: Mapping[str, StereoReferenceDelta] | None = None,
220
+ ) -> dict[str, StereoValue]:
221
+ """Transport a descriptor registry while preserving deterministic keys."""
222
+ changes = deltas or {}
223
+ unknown = set(changes) - set(registry)
224
+ if unknown:
225
+ raise StereoTransportError(
226
+ StereoTransportIssue(
227
+ StereoTransportIssueCode.REFERENCE_NOT_FOUND,
228
+ "A stereo delta names a descriptor absent from the source registry.",
229
+ {"descriptor_ids": tuple(sorted(unknown))},
230
+ )
231
+ )
232
+ transported: dict[str, StereoValue] = {}
233
+ for source_id in sorted(registry):
234
+ descriptor = transport_stereo_descriptor(
235
+ registry[source_id], mapping, changes.get(source_id)
236
+ )
237
+ target_id = descriptor_id(descriptor)
238
+ if target_id in transported:
239
+ raise StereoTransportError(
240
+ StereoTransportIssue(
241
+ StereoTransportIssueCode.NON_INJECTIVE,
242
+ "Two source descriptors collapse to one target owner.",
243
+ {"descriptor_id": target_id},
244
+ )
245
+ )
246
+ transported[target_id] = descriptor
247
+ return transported
248
+
249
+
250
+ __all__ = [
251
+ "StereoEffect",
252
+ "StereoReferenceDelta",
253
+ "StereoTransportError",
254
+ "StereoTransportIssue",
255
+ "StereoTransportIssueCode",
256
+ "transport_stereo_descriptor",
257
+ "transport_stereo_registry",
258
+ ]