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,345 @@
1
+ """Narrow chemistry policies used during reactor mapping."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import networkx as nx
8
+ from networkx.algorithms.isomorphism import (
9
+ GraphMatcher,
10
+ categorical_edge_match,
11
+ categorical_node_match,
12
+ )
13
+
14
+ _PRIMITIVE_TYPES = frozenset((str, int, float, bool, type(None)))
15
+
16
+
17
+ def _freeze(
18
+ value: Any,
19
+ cache: dict[int, tuple[Any, Any]] | None = None,
20
+ ) -> Any:
21
+ if type(value) in _PRIMITIVE_TYPES:
22
+ return value
23
+ cache_key = id(value)
24
+ if cache is not None:
25
+ cached = cache.get(cache_key)
26
+ if cached is not None and cached[0] is value:
27
+ return cached[1]
28
+ if isinstance(value, dict):
29
+ result = tuple(
30
+ sorted((key, _freeze(item, cache)) for key, item in value.items())
31
+ )
32
+ elif isinstance(value, (list, tuple)):
33
+ shallow = tuple(value)
34
+ try:
35
+ hash(shallow)
36
+ except TypeError:
37
+ result = tuple(_freeze(item, cache) for item in value)
38
+ else:
39
+ # Every recursively mutable child makes the shallow tuple
40
+ # unhashable. If hashing succeeds, recursive normalization would
41
+ # preserve each child and produce exactly this tuple.
42
+ result = shallow
43
+ elif isinstance(value, set):
44
+ result = tuple(sorted((_freeze(item, cache) for item in value), key=repr))
45
+ else:
46
+ result = value
47
+ if cache is not None:
48
+ cache[cache_key] = (value, result)
49
+ return result
50
+
51
+
52
+ def contextual_electron_pattern_graph(
53
+ pattern: nx.Graph,
54
+ *,
55
+ reaction_center: nx.Graph,
56
+ template_format: str | None,
57
+ ) -> nx.Graph:
58
+ """Record query attributes made unknown by stripped local context."""
59
+ if template_format != "tuple":
60
+ return pattern
61
+
62
+ decorated = None
63
+ for node, attrs in pattern.nodes(data=True):
64
+ neighbors = attrs.get("neighbors", ())
65
+ explicit_hydrogens = sum(
66
+ pattern.nodes[neighbor].get("element") == "H"
67
+ for neighbor in pattern.neighbors(node)
68
+ )
69
+ hidden_hydrogen = (
70
+ isinstance(neighbors, (list, tuple))
71
+ and neighbors.count("H") > explicit_hydrogens
72
+ )
73
+ rc_attrs = reaction_center.nodes.get(node, {})
74
+ radical = rc_attrs.get("radical")
75
+ radical_changes = (
76
+ isinstance(radical, tuple)
77
+ and len(radical) == 2
78
+ and radical[0] != radical[1]
79
+ )
80
+ if not hidden_hydrogen or radical_changes:
81
+ continue
82
+ if decorated is None:
83
+ decorated = pattern.copy()
84
+ policies = dict(decorated.nodes[node].get("_query_attribute_policies", {}))
85
+ policies["radical"] = "unknown"
86
+ decorated.nodes[node]["_query_attribute_policies"] = policies
87
+ return decorated or pattern
88
+
89
+
90
+ def has_heavy_cross_component_correlation(
91
+ pattern: nx.Graph,
92
+ reaction_center: nx.Graph,
93
+ ) -> bool:
94
+ """Return whether product bonds jointly couple heavy source components."""
95
+ components = [
96
+ frozenset(component) for component in nx.connected_components(pattern)
97
+ ]
98
+ if len(components) < 2:
99
+ return False
100
+ component_index = {
101
+ node: index for index, component in enumerate(components) for node in component
102
+ }
103
+ heavy_components = {
104
+ index
105
+ for index, component in enumerate(components)
106
+ if any(pattern.nodes[node].get("element") != "H" for node in component)
107
+ }
108
+ for left, right, attrs in reaction_center.edges(data=True):
109
+ if left not in component_index or right not in component_index:
110
+ continue
111
+ left_component = component_index[left]
112
+ right_component = component_index[right]
113
+ if (
114
+ left_component == right_component
115
+ or left_component not in heavy_components
116
+ or right_component not in heavy_components
117
+ ):
118
+ continue
119
+ order: Any = attrs.get("order")
120
+ if (
121
+ isinstance(order, tuple)
122
+ and len(order) == 2
123
+ and float(order[0]) == 0.0
124
+ and float(order[1]) > 0.0
125
+ ):
126
+ return True
127
+ return False
128
+
129
+
130
+ def _wl_proves_transition_asymmetric(transition: nx.Graph) -> bool:
131
+ """Return whether exact color refinement proves a trivial automorphism group.
132
+
133
+ Every attributed automorphism preserves each 1-WL color class. Therefore,
134
+ if refinement makes every vertex color unique, only the identity
135
+ automorphism can remain. A non-discrete partition proves nothing and keeps
136
+ the complete GraphMatcher path.
137
+ """
138
+ if len(transition) < 2:
139
+ return True
140
+
141
+ node_palette: dict[Any, int] = {}
142
+ colors = {}
143
+ for node, attrs in transition.nodes(data=True):
144
+ role = attrs.get("_transition_node_role", ())
145
+ color = node_palette.get(role)
146
+ if color is None:
147
+ color = len(node_palette) + 1
148
+ node_palette[role] = color
149
+ colors[node] = color
150
+ if len(set(colors.values())) == len(transition):
151
+ return True
152
+
153
+ edge_palette: dict[Any, int] = {}
154
+ edge_colors = {}
155
+ for left, right, attrs in transition.edges(data=True):
156
+ role = attrs.get("_transition_role", ())
157
+ color = edge_palette.get(role)
158
+ if color is None:
159
+ color = len(edge_palette) + 1
160
+ edge_palette[role] = color
161
+ edge_colors[frozenset((left, right))] = color
162
+
163
+ for _ in range(len(transition)):
164
+ signatures = {
165
+ node: (
166
+ colors[node],
167
+ tuple(
168
+ sorted(
169
+ (
170
+ edge_colors[frozenset((node, neighbor))],
171
+ colors[neighbor],
172
+ )
173
+ for neighbor in transition.neighbors(node)
174
+ )
175
+ ),
176
+ )
177
+ for node in transition
178
+ }
179
+ palette: dict[Any, int] = {}
180
+ refined = {}
181
+ for node, signature in signatures.items():
182
+ color = palette.get(signature)
183
+ if color is None:
184
+ color = len(palette) + 1
185
+ palette[signature] = color
186
+ refined[node] = color
187
+ if len(palette) == len(transition):
188
+ return True
189
+ if all(refined[node] == colors[node] for node in transition):
190
+ return False
191
+ if len(set(refined.values())) == len(set(colors.values())):
192
+ return False
193
+ colors = refined
194
+ return False
195
+
196
+
197
+ def deduplicate_joint_rule_mappings( # noqa: C901
198
+ mappings: list[dict[Any, Any]],
199
+ pattern: nx.Graph,
200
+ reaction_center: nx.Graph,
201
+ *,
202
+ node_attrs: list[str],
203
+ edge_attrs: list[str],
204
+ fixed_nodes: frozenset[Any] = frozenset(),
205
+ max_automorphisms: int = 256,
206
+ ) -> list[dict[Any, Any]]:
207
+ """Quotient mappings only by complete transition-graph automorphisms."""
208
+ if len(mappings) < 2:
209
+ return mappings
210
+ pattern_nodes = frozenset(pattern)
211
+ if any(not pattern_nodes.issubset(mapping) for mapping in mappings):
212
+ # Partial-template mappings are not closed under whole-rule
213
+ # automorphisms, so the group action below is undefined for them.
214
+ return mappings
215
+
216
+ transition = pattern.copy()
217
+ identity_cache: dict[int, tuple[Any, Any]] = {}
218
+ transition_node_keys = (
219
+ "element",
220
+ "aromatic",
221
+ "hcount",
222
+ "charge",
223
+ "radical",
224
+ "neighbors",
225
+ "lone_pairs",
226
+ "valence_electrons",
227
+ "present",
228
+ "charge_model_consistent",
229
+ )
230
+ for node, attrs in transition.nodes(data=True):
231
+ reaction_attrs = reaction_center.nodes.get(node, {})
232
+ attrs["_transition_node_role"] = _freeze(
233
+ (
234
+ "source",
235
+ tuple((key, attrs.get(key)) for key in node_attrs),
236
+ "reaction_center",
237
+ tuple((key, reaction_attrs.get(key)) for key in transition_node_keys),
238
+ ),
239
+ identity_cache,
240
+ )
241
+
242
+ # An attributed automorphism must preserve every node role. If those
243
+ # roles already form a discrete partition, every chemical pattern node
244
+ # is fixed. Any later virtual hydrogen-pair nodes can then permute only
245
+ # among themselves and cannot change a mapping orbit.
246
+ if len(
247
+ {attrs["_transition_node_role"] for _, attrs in transition.nodes(data=True)}
248
+ ) == len(transition):
249
+ return mappings
250
+ transition_edge_keys = (
251
+ "order",
252
+ "kekule_order",
253
+ "sigma_order",
254
+ "pi_order",
255
+ "aromatic",
256
+ "standard_order",
257
+ )
258
+ for left, right, attrs in reaction_center.edges(data=True):
259
+ if left not in transition or right not in transition:
260
+ continue
261
+ role = _freeze(
262
+ (
263
+ "reaction_center",
264
+ tuple((key, attrs.get(key)) for key in transition_edge_keys),
265
+ ),
266
+ identity_cache,
267
+ )
268
+ if transition.has_edge(left, right):
269
+ transition.edges[left, right]["_transition_role"] = role
270
+ else:
271
+ transition.add_edge(
272
+ left,
273
+ right,
274
+ _transition_role=role,
275
+ )
276
+
277
+ # Explicit-H transfer pair IDs are provenance labels, but their incidence
278
+ # relation is chemical. Encode that relation with anonymous virtual nodes
279
+ # so automorphisms may rename a pair while preserving its donor/recipient
280
+ # connectivity exactly.
281
+ pair_incidence: dict[Any, dict[Any, set[str]]] = {}
282
+ for node, attrs in reaction_center.nodes(data=True):
283
+ for side, key in (("left", "h_pairs_left"), ("right", "h_pairs_right")):
284
+ for pair_id in attrs.get(key, ()):
285
+ pair_incidence.setdefault(pair_id, {}).setdefault(node, set()).add(side)
286
+ for ordinal, (_, incidence) in enumerate(
287
+ sorted(pair_incidence.items(), key=lambda item: repr(item[0]))
288
+ ):
289
+ pair_node = ("_synkit_h_pair_role", ordinal)
290
+ transition.add_node(
291
+ pair_node,
292
+ _transition_node_role=("hydrogen_pair",),
293
+ )
294
+ for node, sides in incidence.items():
295
+ if node in transition:
296
+ transition.add_edge(
297
+ pair_node,
298
+ node,
299
+ _transition_role=("hydrogen_pair", tuple(sorted(sides))),
300
+ )
301
+ for _, _, attrs in transition.edges(data=True):
302
+ attrs.setdefault(
303
+ "_transition_role",
304
+ _freeze(
305
+ (
306
+ "source",
307
+ tuple((key, attrs.get(key)) for key in edge_attrs),
308
+ ),
309
+ identity_cache,
310
+ ),
311
+ )
312
+
313
+ if _wl_proves_transition_asymmetric(transition):
314
+ return mappings
315
+
316
+ matcher = GraphMatcher(
317
+ transition,
318
+ transition,
319
+ node_match=categorical_node_match("_transition_node_role", ()),
320
+ edge_match=categorical_edge_match("_transition_role", ()),
321
+ )
322
+ automorphisms = []
323
+ for automorphism in matcher.isomorphisms_iter():
324
+ if any(automorphism[node] != node for node in fixed_nodes):
325
+ continue
326
+ automorphisms.append(automorphism)
327
+ if len(automorphisms) > max_automorphisms:
328
+ return mappings
329
+
330
+ nodes = sorted(pattern.nodes, key=repr)
331
+ seen = set()
332
+ unique = []
333
+ for mapping in mappings:
334
+ signature = min(
335
+ (
336
+ tuple(mapping[automorphism[node]] for node in nodes)
337
+ for automorphism in automorphisms
338
+ ),
339
+ key=repr,
340
+ )
341
+ if signature in seen:
342
+ continue
343
+ seen.add(signature)
344
+ unique.append(mapping)
345
+ return unique
@@ -0,0 +1,309 @@
1
+ """Exact mapping quotients used by the synthesis reactor."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import defaultdict
6
+ from typing import Any, Dict, List, Mapping, Tuple
7
+
8
+ import networkx as nx
9
+
10
+ from synkit.Graph.Matcher.subgraph_matcher import electron_aware_edge_match
11
+
12
+ MappingDict = Dict[Any, Any]
13
+
14
+
15
+ def deduplicate_port_witness_mappings(
16
+ mappings: List[MappingDict],
17
+ structural_pattern: nx.Graph,
18
+ ) -> List[MappingDict]:
19
+ """Project existential stereo-port witnesses from accepted mappings."""
20
+ structural_nodes = frozenset(structural_pattern)
21
+ if len(mappings) < 2 or not any(
22
+ set(mapping) - structural_nodes for mapping in mappings
23
+ ):
24
+ return mappings
25
+ seen = set()
26
+ unique = []
27
+ for mapping in mappings:
28
+ signature = tuple(
29
+ sorted(
30
+ ((node, mapping[node]) for node in structural_nodes if node in mapping),
31
+ key=repr,
32
+ )
33
+ )
34
+ if signature in seen:
35
+ continue
36
+ seen.add(signature)
37
+ unique.append(mapping)
38
+ return unique
39
+
40
+
41
+ def deduplicate_exact_pattern_mappings(
42
+ mappings: List[MappingDict],
43
+ pattern: nx.Graph,
44
+ *,
45
+ node_attrs: List[str],
46
+ edge_attrs: List[str],
47
+ max_automorphisms: int = 256,
48
+ ) -> List[MappingDict]:
49
+ """Quotient complete mappings by the exact attributed group action."""
50
+ if len(mappings) < 2 or pattern.is_multigraph():
51
+ return mappings
52
+ pattern_nodes = tuple(sorted(pattern, key=repr))
53
+ if any(not set(pattern_nodes).issubset(mapping) for mapping in mappings):
54
+ return mappings
55
+
56
+ def node_match(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
57
+ return all(
58
+ left.get(attr, 0 if attr in {"hcount", "lone_pairs"} else None)
59
+ == right.get(attr, 0 if attr in {"hcount", "lone_pairs"} else None)
60
+ for attr in node_attrs
61
+ )
62
+
63
+ def edge_match(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
64
+ return all(left.get(attr) == right.get(attr) for attr in edge_attrs)
65
+
66
+ matcher_cls = (
67
+ nx.algorithms.isomorphism.DiGraphMatcher
68
+ if pattern.is_directed()
69
+ else nx.algorithms.isomorphism.GraphMatcher
70
+ )
71
+ matcher = matcher_cls(
72
+ pattern,
73
+ pattern,
74
+ node_match=node_match,
75
+ edge_match=edge_match,
76
+ )
77
+ automorphisms = []
78
+ for automorphism in matcher.isomorphisms_iter():
79
+ automorphisms.append(automorphism)
80
+ if len(automorphisms) > max_automorphisms:
81
+ return mappings
82
+
83
+ seen = set()
84
+ unique = []
85
+ for mapping in mappings:
86
+ signature = min(
87
+ (
88
+ tuple(mapping[automorphism[node]] for node in pattern_nodes)
89
+ for automorphism in automorphisms
90
+ ),
91
+ key=repr,
92
+ )
93
+ if signature in seen:
94
+ continue
95
+ seen.add(signature)
96
+ unique.append(mapping)
97
+ return unique
98
+
99
+
100
+ def deduplicate_free_host_component_mappings(
101
+ mappings: List[MappingDict],
102
+ host: nx.Graph,
103
+ *,
104
+ node_attrs: List[str],
105
+ edge_attrs: List[str],
106
+ max_automorphisms: int = 256,
107
+ ) -> List[MappingDict]:
108
+ """Quotient by exact automorphisms outside the largest host component."""
109
+ if len(mappings) < 2 or host.is_multigraph():
110
+ return mappings
111
+ component_nodes = list(
112
+ nx.weakly_connected_components(host)
113
+ if host.is_directed()
114
+ else nx.connected_components(host)
115
+ )
116
+ if len(component_nodes) < 2:
117
+ return mappings
118
+ anchor_index = max(
119
+ range(len(component_nodes)),
120
+ key=lambda index: (len(component_nodes[index]), -index),
121
+ )
122
+ component_index = {
123
+ node: index
124
+ for index, component in enumerate(component_nodes)
125
+ for node in component
126
+ }
127
+
128
+ def node_match(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
129
+ return all(
130
+ left.get(attr, 0 if attr in {"hcount", "lone_pairs"} else None)
131
+ == right.get(attr, 0 if attr in {"hcount", "lone_pairs"} else None)
132
+ for attr in node_attrs
133
+ )
134
+
135
+ def edge_match(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
136
+ return electron_aware_edge_match(
137
+ left, right, edge_attrs
138
+ ) and electron_aware_edge_match(right, left, edge_attrs)
139
+
140
+ automorphisms = {}
141
+ matcher_cls = (
142
+ nx.algorithms.isomorphism.DiGraphMatcher
143
+ if host.is_directed()
144
+ else nx.algorithms.isomorphism.GraphMatcher
145
+ )
146
+ for index, nodes in enumerate(component_nodes):
147
+ if index == anchor_index:
148
+ continue
149
+ component = host.subgraph(nodes)
150
+ group = []
151
+ matcher = matcher_cls(
152
+ component,
153
+ component,
154
+ node_match=node_match,
155
+ edge_match=edge_match,
156
+ )
157
+ for automorphism in matcher.isomorphisms_iter():
158
+ group.append(automorphism)
159
+ if len(group) > max_automorphisms:
160
+ return mappings
161
+ automorphisms[index] = group
162
+
163
+ seen = set()
164
+ unique = []
165
+ for mapping in mappings:
166
+ fixed = tuple(
167
+ sorted(
168
+ (
169
+ (pattern_node, host_node)
170
+ for pattern_node, host_node in mapping.items()
171
+ if component_index[host_node] == anchor_index
172
+ ),
173
+ key=repr,
174
+ )
175
+ )
176
+ free = []
177
+ for index, group in automorphisms.items():
178
+ placements = tuple(
179
+ (pattern_node, host_node)
180
+ for pattern_node, host_node in mapping.items()
181
+ if component_index[host_node] == index
182
+ )
183
+ variants = [
184
+ tuple(
185
+ sorted(
186
+ (
187
+ (pattern_node, automorphism[host_node])
188
+ for pattern_node, host_node in placements
189
+ ),
190
+ key=repr,
191
+ )
192
+ )
193
+ for automorphism in group
194
+ ]
195
+ free.append(min(variants, key=repr))
196
+ signature = fixed, tuple(free)
197
+ if signature in seen:
198
+ continue
199
+ seen.add(signature)
200
+ unique.append(mapping)
201
+ return unique
202
+
203
+
204
+ def deduplicate_pure_coupling_mappings( # noqa: C901
205
+ mappings: List[MappingDict],
206
+ pattern: nx.Graph,
207
+ rule: Any,
208
+ *,
209
+ node_attrs: List[str],
210
+ edge_attrs: List[str],
211
+ max_automorphisms: int = 256,
212
+ ) -> List[MappingDict]:
213
+ """Deduplicate equivalent applications of a pure stereo coupling rule."""
214
+ if (
215
+ len(mappings) < 2
216
+ or not rule.stereo_couplings
217
+ or rule.stereo_guards
218
+ or rule.stereo_effects
219
+ or rule.stereo_outcomes
220
+ ):
221
+ return mappings
222
+
223
+ pattern_by_map = {}
224
+ for node, attrs in pattern.nodes(data=True):
225
+ atom_map = attrs.get("atom_map", node)
226
+ if isinstance(atom_map, int):
227
+ pattern_by_map[atom_map] = node
228
+
229
+ dependencies = {
230
+ atom_map
231
+ for coupling in rule.stereo_couplings.values()
232
+ for atom_map in coupling.dependencies
233
+ }
234
+ changed_maps = set()
235
+ for left, right, attrs in rule.rc.raw.edges(data=True):
236
+ order = attrs.get("order")
237
+ if not (isinstance(order, tuple) and len(order) == 2 and order[0] != order[1]):
238
+ continue
239
+ for node in (left, right):
240
+ atom_map = rule.rc.raw.nodes[node].get("atom_map", node)
241
+ if isinstance(atom_map, tuple):
242
+ atom_map = atom_map[0]
243
+ if isinstance(atom_map, int):
244
+ changed_maps.add(atom_map)
245
+ if not changed_maps or not changed_maps <= dependencies:
246
+ return mappings
247
+ if not dependencies <= set(pattern_by_map):
248
+ return mappings
249
+
250
+ decorated = pattern.copy()
251
+ coupling_roles: Dict[Any, List[Tuple[str, str]]] = defaultdict(list)
252
+ coupling_nodes = []
253
+ for key, coupling in sorted(rule.stereo_couplings.items()):
254
+ centers = tuple(pattern_by_map[value] for value in coupling.centers)
255
+ ligands = tuple(pattern_by_map[value] for value in coupling.ligands)
256
+ coupling_nodes.append((key, coupling, centers, ligands))
257
+ for node in centers:
258
+ coupling_roles[node].append((key, "center"))
259
+ for node in ligands:
260
+ coupling_roles[node].append((key, "ligand"))
261
+ for node in decorated:
262
+ decorated.nodes[node]["_coupling_role"] = tuple(
263
+ sorted(coupling_roles.get(node, ()))
264
+ )
265
+
266
+ exact_node_attrs = [*node_attrs, "_coupling_role"]
267
+
268
+ def node_match(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
269
+ return all(left.get(attr) == right.get(attr) for attr in exact_node_attrs)
270
+
271
+ def edge_match(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
272
+ return all(left.get(attr) == right.get(attr) for attr in edge_attrs)
273
+
274
+ matcher = nx.algorithms.isomorphism.GraphMatcher(
275
+ decorated,
276
+ decorated,
277
+ node_match=node_match,
278
+ edge_match=edge_match,
279
+ )
280
+ automorphisms = []
281
+ for automorphism in matcher.isomorphisms_iter():
282
+ automorphisms.append(automorphism)
283
+ if len(automorphisms) > max_automorphisms:
284
+ return mappings
285
+
286
+ seen = set()
287
+ unique = []
288
+ for mapping in mappings:
289
+ variants = []
290
+ for automorphism in automorphisms:
291
+ coupling_signature = []
292
+ for key, coupling, centers, ligands in coupling_nodes:
293
+ mapped_locus = tuple(
294
+ (
295
+ mapping[automorphism[center]],
296
+ mapping[automorphism[ligand]],
297
+ )
298
+ for center, ligand in zip(centers, ligands)
299
+ )
300
+ coupling_signature.append(
301
+ (key, coupling.kind, coupling.relation, mapped_locus)
302
+ )
303
+ variants.append(tuple(coupling_signature))
304
+ signature = min(variants, key=repr)
305
+ if signature in seen:
306
+ continue
307
+ seen.add(signature)
308
+ unique.append(mapping)
309
+ return unique
@@ -0,0 +1 @@
1
+ """Product serialization and exact application deduplication."""