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,203 @@
1
+ """Prove normalized full Lewis PMCD without adding or enumerating H atoms.
2
+
3
+ Ordinary terminal H is represented by counts on heavy atoms. For a proposed
4
+ heavy bijection f its exact minimum H cost is sum_i |h_R[i]-h_P[f(i)]|, also
5
+ with unequal H inventories under zero-state dummy padding. This term enters
6
+ the native objective before optimization. No H graph, transport enumeration,
7
+ ITS classification or mapped-reaction rendering is performed.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections import Counter
13
+ from dataclasses import asdict, dataclass
14
+ import math
15
+ from numbers import Real
16
+ import time
17
+
18
+ from rdkit import Chem
19
+
20
+ from synkit.IO.mol_to_graph import MolToGraph
21
+ from ....graph.labeled_graph import LabeledGraph
22
+ from ...slap.lap import _adjacency_and_elements, chemical_distance
23
+ from .candidates import minimize_native_candidates, prepare_native_candidates
24
+ from .search import _profile_seed
25
+
26
+
27
+ class _UnsupportedHydrogen(ValueError):
28
+ pass
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class PMCDProofResult:
33
+ """An optimum proof, separate from complete mapping-class enumeration.
34
+
35
+ heavy_mapping uses the padded heavy-atom order (real atoms, then dummies).
36
+ minimum_cost is set only after a completed proof. The feasible incumbent
37
+ can remain available if the proof is interrupted. Unsupported H states
38
+ are explicit and never silently drop out of the objective.
39
+ """
40
+
41
+ minimum_cost: float | None
42
+ incumbent_cost: float | None
43
+ optimality_proven: bool
44
+ status: str
45
+ reason: str | None
46
+ heavy_mapping: tuple[int, ...] | None
47
+ heavy_atom_counts: tuple[int, int] | None
48
+ hydrogen_counts: tuple[int, int] | None
49
+ search_atoms: int
50
+ visited_nodes: int
51
+ elapsed_seconds: float
52
+ search_result: dict | None = None
53
+ objective: str = "normalized_full_lewis_distance"
54
+ hydrogen_nodes_added: int = 0
55
+ hydrogen_vertices_searched: int = 0
56
+ enumeration_complete: bool = False
57
+
58
+ def as_dict(self):
59
+ return asdict(self)
60
+
61
+
62
+ # Keep hydrogen eligibility, balancing and anchor construction in one reduction.
63
+ def _implicit_quotient_graphs(reaction, balance): # noqa: C901
64
+ """Read endpoint H counts and electron states without Chem.AddHs."""
65
+ if not isinstance(reaction, str):
66
+ raise TypeError("reaction must be reaction SMILES")
67
+ parts = reaction.split(">")
68
+ if len(parts) != 3 or not parts[0] or not parts[2]:
69
+ raise ValueError("Expected reactants>agents>products or reactants>>products")
70
+ endpoints = []
71
+ for side in (parts[0], parts[2]):
72
+ params = Chem.SmilesParserParams()
73
+ params.removeHs = False
74
+ mol = Chem.MolFromSmiles(side, params)
75
+ if mol is None:
76
+ raise ValueError("Could not parse reaction endpoint")
77
+ heavy = []
78
+ for atom in mol.GetAtoms():
79
+ atom.SetAtomMapNum(0)
80
+ if atom.GetAtomicNum() == 0:
81
+ raise ValueError("Wildcard atoms require a concrete element")
82
+ if atom.GetAtomicNum() != 1:
83
+ heavy.append(atom)
84
+ continue
85
+ if atom.GetIsotope():
86
+ raise _UnsupportedHydrogen("isotopic_hydrogen")
87
+ if atom.GetFormalCharge() or atom.GetNumRadicalElectrons():
88
+ raise _UnsupportedHydrogen("nonneutral_or_radical_hydrogen")
89
+ bonds = list(atom.GetBonds())
90
+ if (len(bonds) != 1 or bonds[0].GetBondTypeAsDouble() != 1
91
+ or bonds[0].GetOtherAtom(atom).GetAtomicNum() <= 1):
92
+ raise _UnsupportedHydrogen("nonordinary_terminal_hydrogen")
93
+ labels = [(atom.GetAtomicNum(), atom.GetIsotope()) for atom in heavy]
94
+ hcounts = [MolToGraph._total_h_count(atom) for atom in heavy]
95
+ electrons = [2 * MolToGraph.estimate_lone_pairs(atom)
96
+ + atom.GetNumRadicalElectrons() for atom in heavy]
97
+ endpoints.append((mol, heavy, labels, hcounts, electrons))
98
+ inventories = [Counter(value[2]) for value in endpoints]
99
+ totals = tuple(sum(value[3]) for value in endpoints)
100
+ if balance == "strict" and (inventories[0] != inventories[1] or totals[0] != totals[1]):
101
+ raise ValueError("Unbalanced atom inventories; select balance='dummy' explicitly")
102
+ universe = inventories[0] | inventories[1]
103
+ graphs = []
104
+ for (mol, heavy, labels, hcounts, electrons), inventory in zip(endpoints, inventories):
105
+ positions = {atom.GetIdx(): i for i, atom in enumerate(heavy)}
106
+ missing = sorted((universe - inventory).elements())
107
+ labels = labels + missing
108
+ hcounts = hcounts + [0] * len(missing)
109
+ electrons = electrons + [0] * len(missing)
110
+ size = len(labels)
111
+ adjacency = {i: {} for i in range(size + 2)}
112
+ for bond in mol.GetBonds():
113
+ i, j = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()
114
+ if i in positions and j in positions:
115
+ x, y = positions[i], positions[j]
116
+ adjacency[x][y] = adjacency[y][x] = bond.GetBondTypeAsDouble()
117
+ # Separate forced anchors encode the electron and minimum-H unary terms.
118
+ for i, (count, electron) in enumerate(zip(hcounts, electrons)):
119
+ if electron:
120
+ adjacency[i][size] = adjacency[size][i] = electron / 2
121
+ if count:
122
+ adjacency[i][size + 1] = adjacency[size + 1][i] = count
123
+ graph = LabeledGraph(adjacency, labels + [(0, -1), (0, -2)])
124
+ graph.props["hcounts"] = hcounts + [0, 0]
125
+ graph.props["electrons"] = electrons + [0, 0]
126
+ graphs.append(graph)
127
+ return tuple(graphs), tuple(len(value[1]) for value in endpoints), totals
128
+
129
+
130
+ def prove_reaction_pmcd(
131
+ reaction,
132
+ *,
133
+ library_path,
134
+ balance="strict",
135
+ time_limit_seconds=10.0,
136
+ symmetry=True,
137
+ ):
138
+ """Prove full Lewis PMCD using only heavy vertices and H counts.
139
+
140
+ Supported H atoms are neutral, nonradical, nonisotopic terminal single-bond
141
+ H. Other H states return status='unsupported' without expanding anything.
142
+ Stereo does not need expansion for the existing numerical CD objective:
143
+ it remains an output-class distinction, and this API returns no classes.
144
+ The ordinary map_reaction/Mapper minimum query still enumerates all minima.
145
+ """
146
+ started = time.perf_counter()
147
+ if balance not in {"strict", "dummy"}:
148
+ raise ValueError("balance must be 'strict' or 'dummy'")
149
+ if not isinstance(symmetry, bool):
150
+ raise TypeError("symmetry must be boolean")
151
+ if time_limit_seconds is not None and (
152
+ isinstance(time_limit_seconds, bool) or not isinstance(time_limit_seconds, Real)
153
+ or not math.isfinite(time_limit_seconds) or time_limit_seconds < 0
154
+ ):
155
+ raise ValueError("time limit must be finite and nonnegative")
156
+ deadline = None if time_limit_seconds is None else started + time_limit_seconds
157
+
158
+ def outcome(record=None, *, reason=None, status=None, graphs=(), heavy=None, hydrogens=None):
159
+ proven = record is not None and record["complete"]
160
+ mapping = tuple(record["mapping"][:-2]) if record else None
161
+ return PMCDProofResult(
162
+ minimum_cost=record["minimum_cost"] if proven else None,
163
+ incumbent_cost=record["incumbent_cost"] if record else None,
164
+ optimality_proven=proven,
165
+ status=status or ("proven" if proven else "time_limit"),
166
+ reason=reason if reason is not None else record["reason"] if record else None,
167
+ heavy_mapping=mapping, heavy_atom_counts=heavy, hydrogen_counts=hydrogens,
168
+ search_atoms=len(graphs[0].labels) if graphs else 0,
169
+ visited_nodes=record["visited_nodes"] if record else 0,
170
+ elapsed_seconds=time.perf_counter() - started, search_result=record,
171
+ )
172
+
173
+ try:
174
+ graphs, heavy, hydrogens = _implicit_quotient_graphs(reaction, balance)
175
+ except _UnsupportedHydrogen as error:
176
+ return outcome(status="unsupported", reason=str(error))
177
+ if len(graphs[0].labels) > 256:
178
+ return outcome(status="unsupported", reason="native_node_limit", graphs=graphs,
179
+ heavy=heavy, hydrogens=hydrogens)
180
+ if deadline is not None and time.perf_counter() >= deadline:
181
+ return outcome(status="time_limit", reason="time_limit", graphs=graphs,
182
+ heavy=heavy, hydrogens=hydrogens)
183
+ a, labels = _adjacency_and_elements(graphs[0], False)
184
+ b, product_labels = _adjacency_and_elements(graphs[1], False)
185
+ if len(set(a.ravel()) | set(b.ravel())) > 16:
186
+ return outcome(status="unsupported", reason="native_bond_level_limit", graphs=graphs,
187
+ heavy=heavy, hydrogens=hydrogens)
188
+ seed = _profile_seed(a, b, labels, product_labels)
189
+ prepared = prepare_native_candidates(
190
+ graphs, 0, library_path=library_path, initial_mapping=seed,
191
+ binary=False, symmetry=symmetry, node_properties=(), allow_partial_symmetry=True,
192
+ )
193
+ seconds = 1e100 if deadline is None else max(0, deadline - time.perf_counter())
194
+ record = minimize_native_candidates(
195
+ graphs, library_path=library_path, initial_mapping=seed,
196
+ time_limit_seconds=seconds, _prepared=prepared,
197
+ )
198
+ if chemical_distance(graphs, record["mapping"], False) != record["incumbent_cost"]:
199
+ raise RuntimeError("Native proof witness does not match its reduced Lewis cost")
200
+ return outcome(record, graphs=graphs, heavy=heavy, hydrogens=hydrogens)
201
+
202
+
203
+ __all__ = ["PMCDProofResult", "prove_reaction_pmcd"]
@@ -0,0 +1,40 @@
1
+ """Optional operating-system controls for native mapper workers."""
2
+
3
+ import os
4
+
5
+ WORKER_ADDRESS_SPACE_BYTES = 4 * 1024**3
6
+
7
+
8
+ def limit_worker_address_space(resource):
9
+ """Lower supported soft limits, preserving inherited soft and hard ceilings."""
10
+ if resource is None or not hasattr(resource, "RLIMIT_AS"):
11
+ return None
12
+ try:
13
+ soft, hard = resource.getrlimit(resource.RLIMIT_AS)
14
+ ceilings = [value for value in (soft, hard) if value != resource.RLIM_INFINITY]
15
+ limit = min([WORKER_ADDRESS_SPACE_BYTES, *ceilings])
16
+ resource.setrlimit(resource.RLIMIT_AS, (limit, hard))
17
+ return limit
18
+ except (OSError, ValueError):
19
+ # Some macOS kernels expose RLIMIT_AS but reject setting this limit.
20
+ # This optional control must not prevent worker startup and barriers.
21
+ return None
22
+
23
+
24
+ def worker_cpus(workers):
25
+ """Return available CPU IDs to pin, or an empty list when unsupported."""
26
+ if not hasattr(os, "sched_getaffinity") or not hasattr(os, "sched_setaffinity"):
27
+ return []
28
+ try:
29
+ return sorted(os.sched_getaffinity(0))[:workers]
30
+ except OSError:
31
+ return []
32
+
33
+
34
+ def pin_worker_cpu(cpu):
35
+ """Apply optional CPU pinning without making an OS tuning failure fatal."""
36
+ if cpu is not None and hasattr(os, "sched_setaffinity"):
37
+ try:
38
+ os.sched_setaffinity(0, {cpu})
39
+ except OSError:
40
+ pass
@@ -0,0 +1,294 @@
1
+ """Full-space minimum and distance-range adapters for optional C++ search."""
2
+
3
+ import math
4
+ import time
5
+ from collections import Counter
6
+ from functools import partial
7
+ from numbers import Integral, Real
8
+
9
+ import numpy as np
10
+ from scipy.optimize import linear_sum_assignment
11
+
12
+ from ...slap.lap import _adjacency_and_elements
13
+ from ..distance_search.bounds import atom_profile_costs
14
+ from ..distance_search.records import (
15
+ DistanceEnumerationResult,
16
+ ExactEnumerationLimitError,
17
+ normalize_distance_target,
18
+ )
19
+ from ..pabs.cost_lattice import CostLattice
20
+ from .candidates import (
21
+ enumerate_native_range,
22
+ minimize_native_candidates,
23
+ prepare_native_candidates,
24
+ )
25
+
26
+
27
+ def _profile_seed(a, b, labels, product_labels):
28
+ """Choose a compatible feasible incumbent; its cost is verified in C++."""
29
+ profiles = atom_profile_costs(a, b, labels, product_labels)
30
+ mapping = [-1] * len(labels)
31
+ for element in dict.fromkeys(labels):
32
+ rows = [i for i, value in enumerate(labels) if value == element]
33
+ columns = [i for i, value in enumerate(product_labels) if value == element]
34
+ left, right = linear_sum_assignment(profiles[np.ix_(rows, columns)])
35
+ for i, j in zip(left, right):
36
+ mapping[rows[i]] = columns[j]
37
+ return mapping
38
+
39
+
40
+ def enumerate_cpp_mappings( # noqa: C901
41
+ lgp,
42
+ *,
43
+ library_path,
44
+ CD="minimal",
45
+ CD_mode="exact",
46
+ binary=True,
47
+ initial_mapping=None,
48
+ max_bijections=1_000_000,
49
+ max_mappings=None,
50
+ time_limit_seconds=None,
51
+ collect_mappings=True,
52
+ mapping_callback=None,
53
+ compute_minimum_cost=True,
54
+ tolerance=1e-9,
55
+ symmetry=False,
56
+ node_properties=(),
57
+ separator_config=None,
58
+ ):
59
+ """Prove PMCD and enumerate its full shell, or enumerate a supplied CD.
60
+
61
+ A numeric query defaults to CD_mode='exact'. 'at_most' instead selects
62
+ every distance at or below CD in one traversal. Returned distances and
63
+ callbacks carry each mapping's actual cost.
64
+
65
+ The default preserves every compatible labeled mapping. symmetry=True uses
66
+ verified side automorphisms preserving node_properties; partial subgroup
67
+ discovery only weakens pruning. Chemical frontends still perform exact ITS
68
+ classification and report representative counts separately from labeled
69
+ counts. Requires 1..256 atoms, symmetric loop-free half-integer weights and
70
+ at most 16 bond levels. Compilation remains explicit.
71
+
72
+ Minimum proof and complete enumeration are independent passes sharing one
73
+ deadline. An interrupted proof never publishes its incumbent as PMCD.
74
+ ``separator_config`` explicitly enables an experimental bounded residual
75
+ oracle, with ``residual_limit`` (0..12) and ``max_states`` per call. Unknown
76
+ oracle results retain ordinary search. The default leaves it disabled.
77
+ """
78
+ started = time.perf_counter()
79
+ target = normalize_distance_target(CD)
80
+ minimum_function = minimize_native_candidates
81
+ range_function = enumerate_native_range
82
+ separator_options = separator_statistics = None
83
+ if separator_config is not None:
84
+ from .separator import (
85
+ _normalize_separator_config,
86
+ enumerate_native_range_separator,
87
+ minimize_native_candidates_separator,
88
+ )
89
+
90
+ separator_options = _normalize_separator_config(separator_config)
91
+ minimum_function = partial(minimize_native_candidates_separator, **separator_options)
92
+ range_function = partial(enumerate_native_range_separator, **separator_options)
93
+ separator_statistics = dict.fromkeys(("calls", "known", "pruned", "states"), 0)
94
+ if CD_mode not in {"exact", "at_most"}:
95
+ raise ValueError("CD_mode must be 'exact' or 'at_most'")
96
+ if target == "minimal" and CD_mode != "exact":
97
+ raise ValueError("CD_mode='at_most' requires numeric CD")
98
+ for name, value in (
99
+ ("binary", binary),
100
+ ("collect_mappings", collect_mappings),
101
+ ("compute_minimum_cost", compute_minimum_cost),
102
+ ("symmetry", symmetry),
103
+ ):
104
+ if not isinstance(value, bool):
105
+ raise TypeError(f"{name} must be boolean")
106
+ for name, value in (
107
+ ("max_bijections", max_bijections),
108
+ ("max_mappings", max_mappings),
109
+ ):
110
+ if value is not None and (
111
+ isinstance(value, bool) or not isinstance(value, Integral) or value < 1
112
+ ):
113
+ raise ValueError(f"{name} must be a positive integer or None")
114
+ if time_limit_seconds is not None and (
115
+ isinstance(time_limit_seconds, bool)
116
+ or not isinstance(time_limit_seconds, Real)
117
+ or not math.isfinite(time_limit_seconds)
118
+ or time_limit_seconds < 0
119
+ ):
120
+ raise ValueError("time_limit_seconds must be finite and non-negative")
121
+ if (
122
+ isinstance(tolerance, bool)
123
+ or not isinstance(tolerance, Real)
124
+ or not math.isfinite(tolerance)
125
+ or not 0 <= tolerance < 0.25
126
+ ):
127
+ raise ValueError("C++ tolerance must be finite, nonnegative and less than 0.25")
128
+ if mapping_callback is not None and not callable(mapping_callback):
129
+ raise TypeError("mapping_callback must be callable")
130
+ a, labels = _adjacency_and_elements(lgp[0], binary)
131
+ b, product_labels = _adjacency_and_elements(lgp[1], binary)
132
+ if a.shape != b.shape or Counter(labels) != Counter(product_labels):
133
+ raise ValueError("Endpoints must have equal atom-type inventories")
134
+ total = math.prod(math.factorial(count) for count in Counter(labels).values())
135
+ if max_bijections is not None and total > max_bijections:
136
+ raise ExactEnumerationLimitError(
137
+ f"{total:,} bijections exceed max_bijections={max_bijections:,}"
138
+ )
139
+ maximum = float(np.abs(a).sum() + np.abs(b).sum()) / 2
140
+ if maximum > 250000:
141
+ raise ValueError("C++ total distance range exceeds 250000")
142
+ seed = (
143
+ _profile_seed(a, b, labels, product_labels)
144
+ if initial_mapping is None
145
+ else initial_mapping
146
+ )
147
+ prepared = prepare_native_candidates(
148
+ lgp,
149
+ 0,
150
+ library_path=library_path,
151
+ initial_mapping=seed,
152
+ binary=binary,
153
+ symmetry=symmetry,
154
+ node_properties=node_properties,
155
+ allow_partial_symmetry=True,
156
+ )
157
+ lattice = CostLattice.from_matrices(np.rint(a * 4), np.rint(b * 4))
158
+ deadline = None if time_limit_seconds is None else started + time_limit_seconds
159
+ nodes = leaves = pruned = count = 0
160
+ minimum = reason = proof = None
161
+ mappings, distances = [], []
162
+ first_cost = None
163
+ mixed_costs = False
164
+
165
+ def remaining():
166
+ return 1e100 if deadline is None else max(0, deadline - time.perf_counter())
167
+
168
+ def record_statistics(record):
169
+ nonlocal nodes, leaves, pruned
170
+ nodes += int(record["visited_nodes"])
171
+ leaves += int(record["visited_leaves"])
172
+ pruned += int(record["pruned"])
173
+ if separator_statistics is not None:
174
+ for name in separator_statistics:
175
+ separator_statistics[name] += record["separator_statistics"][name]
176
+
177
+ if target == "minimal" or compute_minimum_cost:
178
+ proof = minimum_function(
179
+ lgp,
180
+ library_path=library_path,
181
+ initial_mapping=seed,
182
+ time_limit_seconds=remaining(),
183
+ _prepared=prepared,
184
+ )
185
+ record_statistics(proof)
186
+ minimum = proof["minimum_cost"]
187
+ reason = proof["reason"]
188
+
189
+ def receive(mapping, cost):
190
+ nonlocal count, first_cost, mixed_costs
191
+ count += 1
192
+ if first_cost is None:
193
+ first_cost = cost
194
+ elif cost != first_cost:
195
+ mixed_costs = True
196
+ if collect_mappings:
197
+ mappings.append(list(mapping))
198
+ distances.append(cost)
199
+ if mapping_callback is not None:
200
+ mapping_callback(list(mapping), cost)
201
+
202
+ selected = minimum if target == "minimal" else float(target)
203
+ if reason is None and selected is not None:
204
+ if CD_mode == "at_most":
205
+ lower = 0.0
206
+ upper = min(
207
+ maximum, math.floor((min(selected, maximum) + tolerance) * 2) / 2
208
+ )
209
+ reachable = lattice.intersects(0, round(upper * 4))
210
+ elif selected > maximum + tolerance:
211
+ reachable = False
212
+ else:
213
+ lower = upper = round(selected * 2) / 2
214
+ reachable = (
215
+ abs(selected - upper) <= tolerance
216
+ and upper <= maximum
217
+ and lattice.intersects(round(upper * 4), round(upper * 4))
218
+ )
219
+ if reachable:
220
+ record = range_function(
221
+ lgp,
222
+ lower,
223
+ upper,
224
+ library_path=library_path,
225
+ time_limit_seconds=remaining(),
226
+ max_mappings=None if max_mappings is None else int(max_mappings),
227
+ callback=receive,
228
+ _prepared=prepared,
229
+ )
230
+ record_statistics(record)
231
+ reason = record["reason"]
232
+ complete = reason is None
233
+ reactant_order, product_order = prepared[6:8]
234
+ group_order = (
235
+ reactant_order * product_order
236
+ if reactant_order is not None and product_order is not None
237
+ else None
238
+ )
239
+ labeled_count = count if count == 0 or not symmetry or group_order == 1 else None
240
+ symmetry_complete = prepared.symmetry_search_complete
241
+ generator_count = len(prepared[4]) + len(prepared[5]) - 2
242
+ return DistanceEnumerationResult(
243
+ target=target,
244
+ cost=first_cost if count and not mixed_costs else None,
245
+ minimum_cost=minimum,
246
+ mappings=mappings,
247
+ distances=distances,
248
+ total_bijections=total,
249
+ maximum_cost_upper_bound=maximum,
250
+ visited_leaves=leaves,
251
+ pruned_branches=pruned,
252
+ visited_nodes=nodes,
253
+ elapsed_seconds=time.perf_counter() - started,
254
+ status=("complete" if count else "no_solutions") if complete else "timeout",
255
+ complete=complete,
256
+ truncation_reason=reason,
257
+ scope=(
258
+ "atom_compatible_assignment_space_modulo_verified_side_symmetry"
259
+ if symmetry
260
+ else "complete_atom_compatible_assignment_space"
261
+ ),
262
+ selected_mapping_count=count,
263
+ selected_labeled_mapping_count=labeled_count,
264
+ symmetry_automorphism_count=generator_count + 1,
265
+ symmetry_search_complete=symmetry_complete,
266
+ symmetry_group_order=group_order,
267
+ symmetry_quotient_complete=complete and symmetry_complete,
268
+ backend="pabs_cpp",
269
+ backend_statistics={
270
+ "method": "PABS",
271
+ "requested_backend": "cpp",
272
+ "implementation": "native_assignment_branch_and_bound",
273
+ "minimum_shell_probes": 0,
274
+ "minimum_optimization": proof,
275
+ "CD_mode": CD_mode,
276
+ "mapping_count_scope": (
277
+ "symmetry_candidates" if symmetry else "labeled_mappings"
278
+ ),
279
+ "symmetry_enabled": symmetry,
280
+ "side_groups_complete": symmetry_complete,
281
+ "symmetry_generator_count": generator_count,
282
+ "library_path": str(library_path),
283
+ "cost_lattice_modulus_quarters": lattice.modulus,
284
+ "cost_lattice_residue_quarters": lattice.residue,
285
+ **(
286
+ {"separator_config": separator_options,
287
+ "separator_statistics": separator_statistics}
288
+ if separator_options is not None else {}
289
+ ),
290
+ },
291
+ )
292
+
293
+
294
+ __all__ = ["enumerate_cpp_mappings"]