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,591 @@
1
+ from copy import copy, deepcopy
2
+ import networkx as nx
3
+ from operator import eq
4
+ from typing import List, Set, Any, Tuple, Iterable, Optional
5
+ from networkx.algorithms.isomorphism import generic_node_match, generic_edge_match
6
+
7
+ from synkit.Graph.Feature.graph_descriptors import GraphDescriptor
8
+
9
+
10
+ def has_XH(G: nx.Graph) -> bool:
11
+ """Check whether the graph contains any heavy atom–hydrogen bond.
12
+
13
+ A heavy atom is any atom whose 'element' attribute is not 'H'.
14
+ This function searches for any edge that connects a heavy atom to a hydrogen atom.
15
+
16
+ :param G: A graph where each node has an 'element' attribute indicating the atom type.
17
+ :type G: nx.Graph
18
+
19
+ :return: True if at least one edge connects a hydrogen atom ('H') to a heavy atom (element ≠ 'H').
20
+ False otherwise.
21
+ :rtype: bool
22
+ """
23
+ for u, v, _ in G.edges(data=True):
24
+ el_u = G.nodes[u].get("element")
25
+ el_v = G.nodes[v].get("element")
26
+ if (el_u != "H" and el_v == "H") or (el_v != "H" and el_u == "H"):
27
+ return True
28
+ return False
29
+
30
+
31
+ def has_HH(G: nx.Graph) -> bool:
32
+ """Check whether the graph contains any heavy atom–hydrogen bond.
33
+
34
+ A heavy atom is any atom whose 'element' attribute is not 'H'.
35
+ This function searches for any edge that connects a heavy atom to a hydrogen atom.
36
+
37
+ :param G: A graph where each node has an 'element' attribute indicating the atom type.
38
+ :type G: nx.Graph
39
+
40
+ :return: True if at least one edge connects a hydrogen atom ('H') to a heavy atom (element ≠ 'H').
41
+ False otherwise.
42
+ :rtype: bool
43
+ """
44
+ for u, v, _ in G.edges(data=True):
45
+ el_u = G.nodes[u].get("element")
46
+ el_v = G.nodes[v].get("element")
47
+ if el_u == el_v == "H":
48
+ return True
49
+ return False
50
+
51
+
52
+ def h_to_implicit(G: nx.Graph) -> nx.Graph:
53
+ """Convert explicit hydrogen atoms to implicit counts on heavy atoms.
54
+
55
+ For each hydrogen atom ('element' == 'H'), its neighbor (assumed to be a heavy atom)
56
+ will have its 'hcount' attribute incremented. The hydrogen nodes are then removed.
57
+
58
+ :param G: Input graph with explicit hydrogen atoms as nodes (element='H').
59
+ Heavy atoms must have 'element' and optionally 'hcount' attributes.
60
+ :type G: nx.Graph
61
+
62
+ :return: A copy of the original graph with hydrogen atoms removed and their counts
63
+ added to the corresponding heavy atoms' 'hcount' attribute.
64
+ :rtype: nx.Graph
65
+ """
66
+ H2 = G.copy()
67
+ h_nodes = [n for n, d in H2.nodes(data=True) if d.get("element") == "H"]
68
+
69
+ for h in h_nodes:
70
+ neighbors = list(H2.neighbors(h))
71
+ for heavy in neighbors:
72
+ if H2.nodes[heavy].get("element") != "H":
73
+ H2.nodes[heavy]["hcount"] = H2.nodes[heavy].get("hcount", 0) + 1
74
+ H2.remove_node(h)
75
+
76
+ return H2
77
+
78
+
79
+ def normalize_edge_orders(G: nx.Graph) -> None:
80
+ """
81
+ In-place normalize all edge attributes in G:
82
+ - If 'order' is a float or int, replace it with (order, order).
83
+ - If 'standard_order' is missing, set it to 0.0.
84
+ """
85
+ for _, _, data in G.edges(data=True):
86
+ o = data.get("order")
87
+ # Wrap scalar orders into tuples
88
+ if isinstance(o, (int, float)):
89
+ data["order"] = (float(o), float(o))
90
+ if "standard_order" not in data:
91
+ data["standard_order"] = 0.0
92
+
93
+
94
+ def h_to_explicit(G: nx.Graph, nodes: List[int] = None, its: bool = False) -> nx.Graph:
95
+ """Convert implicit hydrogen counts on heavy atoms into explicit hydrogen
96
+ nodes.
97
+
98
+ For each node ID in `nodes`, this function reads the node's 'hcount', adds that many
99
+ new hydrogen nodes, connects them to the node with a single bond (order=1.0), and
100
+ decrements the node's 'hcount'. Optionally updates the 'typesGH' field if present.
101
+
102
+ :param G: Input graph with heavy atoms containing 'hcount' indicating implicit hydrogens.
103
+ :type G: nx.Graph
104
+ :param nodes: List of node IDs (typically heavy atoms) on which to expand implicit hydrogens.
105
+ :type nodes: List[int]
106
+
107
+ :return: A copy of the graph with new explicit hydrogen nodes added and connected
108
+ to the specified heavy atoms.
109
+ :rtype: nx.Graph
110
+ """
111
+ if nodes is None or len(nodes) == 0:
112
+ nodes = G.nodes()
113
+ H2 = G.copy()
114
+ max_node = max(H2.nodes) if H2.nodes else 0
115
+
116
+ for heavy in nodes:
117
+ if heavy not in H2:
118
+ continue
119
+ count = H2.nodes[heavy].get("hcount", 0)
120
+ if its and _is_pair_hcount(count):
121
+ max_node = _expand_paired_its_hydrogens(H2, heavy, max_node)
122
+ continue
123
+ if count <= 0:
124
+ continue
125
+
126
+ restored_maps = list(H2.nodes[heavy].pop("_implicit_h_atom_maps", ()))
127
+
128
+ for _ in range(count):
129
+ max_node += 1
130
+ atom_map = restored_maps.pop(0) if restored_maps else 0
131
+ H2.add_node(
132
+ max_node,
133
+ element="H",
134
+ aromatic=False,
135
+ hcount=0,
136
+ charge=0,
137
+ atom_map=atom_map,
138
+ _restored_mapped_h=bool(atom_map),
139
+ typesGH=(("H", False, 0, 0, []), ("H", False, 0, 0, [])),
140
+ )
141
+ H2.add_edge(heavy, max_node, order=1.0)
142
+
143
+ H2.nodes[heavy]["hcount"] -= count
144
+ if restored_maps:
145
+ H2.nodes[heavy]["_implicit_h_atom_maps"] = tuple(restored_maps)
146
+
147
+ # Optionally adjust the typesGH field if it exists
148
+ if "typesGH" in H2.nodes[heavy]:
149
+ tgh = H2.nodes[heavy]["typesGH"]
150
+ tgh_list = [list(row) for row in tgh]
151
+ tgh_list[0][2] -= count # Assume hcount is stored at position [0][2]
152
+ H2.nodes[heavy]["typesGH"] = tuple(tuple(row) for row in tgh_list)
153
+ if its:
154
+ normalize_edge_orders(H2)
155
+
156
+ return H2
157
+
158
+
159
+ def _is_pair_hcount(value: Any) -> bool:
160
+ """Return whether a value is a 2-item integer hydrogen-count pair."""
161
+ return (
162
+ isinstance(value, (list, tuple))
163
+ and len(value) == 2
164
+ and all(isinstance(item, int) for item in value)
165
+ )
166
+
167
+
168
+ def _paired_hydrogen_node_attrs(present: Tuple[bool, bool]) -> dict:
169
+ """Build named paired attrs for a tuple-style ITS hydrogen node."""
170
+ return {
171
+ "element": ("H", "H"),
172
+ "aromatic": (False, False),
173
+ "hcount": (0, 0),
174
+ "charge": (0, 0),
175
+ "radical": (0, 0),
176
+ "lone_pairs": (0, 0),
177
+ "valence_electrons": (1, 1),
178
+ "neighbors": ([], []),
179
+ "atom_map": (0, 0),
180
+ "present": present,
181
+ }
182
+
183
+
184
+ def _expand_paired_its_hydrogens(
185
+ graph: nx.Graph,
186
+ heavy: int,
187
+ max_node: int,
188
+ ) -> int:
189
+ """Expand paired ITS hydrogen counts into shared and side-only H nodes."""
190
+ react_h, prod_h = graph.nodes[heavy]["hcount"]
191
+ shared = min(react_h, prod_h)
192
+ react_only = react_h - shared
193
+ prod_only = prod_h - shared
194
+
195
+ expansion_plan = (
196
+ [((True, True), (1.0, 1.0))] * shared
197
+ + [((True, False), (1.0, 0.0))] * react_only
198
+ + [((False, True), (0.0, 1.0))] * prod_only
199
+ )
200
+
201
+ for present, bond_pair in expansion_plan:
202
+ max_node += 1
203
+ graph.add_node(max_node, **_paired_hydrogen_node_attrs(present))
204
+ graph.add_edge(
205
+ heavy,
206
+ max_node,
207
+ order=bond_pair,
208
+ kekule_order=bond_pair,
209
+ sigma_order=bond_pair,
210
+ pi_order=(0.0, 0.0),
211
+ standard_order=bond_pair[0] - bond_pair[1],
212
+ )
213
+
214
+ graph.nodes[heavy]["hcount"] = (0, 0)
215
+ return max_node
216
+
217
+
218
+ def implicit_hydrogen(
219
+ graph: nx.Graph, preserve_atom_maps: Set[int], reindex: bool = False
220
+ ) -> nx.Graph:
221
+ """Adds implicit hydrogens to a molecular graph and removes non-preserved
222
+ hydrogens. This function operates on a deep copy of the input graph to
223
+ avoid in-place modifications. It counts hydrogen neighbors for each non-
224
+ hydrogen node and adjusts based on hydrogens that need to be preserved.
225
+ Non-preserved hydrogen nodes are removed from the graph.
226
+
227
+ :param graph: A NetworkX graph representing the molecule, where each node has an 'element'
228
+ attribute for the element type (e.g., 'C', 'H') and an 'atom_map' attribute for atom mapping.
229
+ :type graph: nx.Graph
230
+ :param preserve_atom_maps: Set of atom map numbers for hydrogens that should be preserved.
231
+ :type preserve_atom_maps: Set[int]
232
+ :param reindex: If true, reindexes node indices and atom maps sequentially after modifications.
233
+ :type reindex: bool
234
+
235
+ :return: Graph with non-preserved hydrogens removed and hydrogen counts
236
+ adjusted on the remaining atoms.
237
+ :rtype: nx.Graph
238
+ """
239
+ # Create a deep copy of the graph to avoid in-place modifications
240
+ new_graph = copy(graph)
241
+
242
+ # First pass: count hydrogen neighbors for each non-hydrogen node
243
+ for node, data in new_graph.nodes(data=True):
244
+ if data["element"] != "H": # Skip hydrogen atoms
245
+ count_h_explicit = sum(
246
+ 1
247
+ for neighbor in new_graph.neighbors(node)
248
+ if new_graph.nodes[neighbor]["element"] == "H"
249
+ )
250
+ count_h_implicit = data["hcount"]
251
+ new_graph.nodes[node]["hcount"] = count_h_explicit + count_h_implicit
252
+
253
+ # List of hydrogens to preserve based on atom map
254
+ preserved_hydrogens = [
255
+ node
256
+ for node, data in new_graph.nodes(data=True)
257
+ if data["element"] == "H" and data["atom_map"] in preserve_atom_maps
258
+ ]
259
+
260
+ # Adjust hydrogen counts for preserved hydrogens
261
+ for hydrogen in preserved_hydrogens:
262
+ for neighbor in new_graph.neighbors(hydrogen):
263
+ if (
264
+ new_graph.nodes[neighbor]["element"] != "H"
265
+ ): # Only adjust non-hydrogen neighbors
266
+ new_graph.nodes[neighbor]["hcount"] -= 1
267
+
268
+ # Remove non-preserved hydrogen nodes from the graph
269
+ hydrogen_to_remove = [
270
+ node
271
+ for node, data in new_graph.nodes(data=True)
272
+ if data["element"] == "H" and node not in preserved_hydrogens
273
+ ]
274
+ new_graph.remove_nodes_from(hydrogen_to_remove)
275
+
276
+ # Reindex the graph if reindex=True
277
+ if reindex:
278
+ # Create new mapping and update node indices and atom maps
279
+ mapping = {node: idx + 1 for idx, node in enumerate(new_graph.nodes())}
280
+ new_graph = nx.relabel_nodes(new_graph, mapping) # Relabel nodes
281
+
282
+ # Update atom maps to reflect new node indices
283
+ for node, data in new_graph.nodes(data=True):
284
+ data["atom_map"] = node # Sync atom map with node index
285
+
286
+ return new_graph
287
+
288
+
289
+ def _normalize_sequence_at_index(
290
+ seqs: Iterable[Any], index: int = 2, target_min: int = 0
291
+ ) -> Optional[Tuple[Any, ...]]:
292
+ """
293
+ If possible, shift the integer at `index` in each sequence so that the minimum becomes
294
+ `target_min`. Returns a new tuple of sequences if any change is needed, else None.
295
+ """
296
+ # collect valid ints at the index
297
+ valid_vals = [
298
+ t[index]
299
+ for t in seqs
300
+ if isinstance(t, (list, tuple)) and len(t) > index and isinstance(t[index], int)
301
+ ]
302
+ if not valid_vals:
303
+ return None
304
+
305
+ offset = min(valid_vals) - target_min
306
+ if offset == 0:
307
+ return None # already normalized
308
+
309
+ def normalize(t):
310
+ if (
311
+ isinstance(t, (list, tuple))
312
+ and len(t) > index
313
+ and isinstance(t[index], int)
314
+ ):
315
+ t_list = list(t)
316
+ t_list[index] = t_list[index] - offset
317
+ return tuple(t_list)
318
+ return t # leave untouched
319
+
320
+ return tuple(normalize(t) for t in seqs)
321
+
322
+
323
+ def standardize_hydrogen(G: nx.Graph, in_place: bool = False) -> nx.Graph:
324
+ """
325
+ For each node, shift the third element (index 2) of each tuple in 'typesGH' so that the
326
+ minimum among those values becomes zero. Nonconforming entries are preserved.
327
+ """
328
+ target = G if in_place else G.copy()
329
+
330
+ for node, data in target.nodes(data=True):
331
+ typesGH = data.get("typesGH")
332
+ if not typesGH:
333
+ continue
334
+ normalized = _normalize_sequence_at_index(typesGH, index=2, target_min=0)
335
+ if normalized is not None:
336
+ target.nodes[node]["typesGH"] = normalized
337
+
338
+ return target
339
+
340
+
341
+ def check_equivariant_graph(
342
+ its_graphs: List[nx.Graph],
343
+ ) -> Tuple[List[Tuple[int, int]], int]:
344
+ """Checks for isomorphism among a list of ITS graphs.
345
+
346
+ :param its_graphs: A list of ITS graphs.
347
+ :type its_graphs: List[nx.Graph]
348
+
349
+ :return: A list of tuples representing pairs of indices of isomorphic graphs.
350
+ :rtype: List[Tuple[int, int]]
351
+ """
352
+ nodeLabelNames = ["typesGH"]
353
+ nodeLabelDefault = [()]
354
+ nodeLabelOperator = [eq]
355
+ nodeMatch = generic_node_match(nodeLabelNames, nodeLabelDefault, nodeLabelOperator)
356
+ edgeMatch = generic_edge_match("order", 1, eq)
357
+
358
+ classified = []
359
+
360
+ for i in range(1, len(its_graphs)):
361
+ # Compare the first graph with each subsequent graph
362
+ if nx.is_isomorphic(
363
+ its_graphs[0], its_graphs[i], node_match=nodeMatch, edge_match=edgeMatch
364
+ ):
365
+ classified.append((0, i))
366
+ return classified, len(classified)
367
+
368
+
369
+ def check_explicit_hydrogen(graph: nx.Graph) -> tuple:
370
+ """Counts the explicit hydrogen nodes in the given graph and collects their
371
+ IDs.
372
+
373
+ :param graph: The graph to inspect.
374
+ :type graph: nx.Graph
375
+
376
+ :return: A tuple containing the number of hydrogen nodes and a list of their node IDs.
377
+ :rtype: tuple
378
+ """
379
+ hydrogen_nodes = [
380
+ node_id
381
+ for node_id, attr in graph.nodes(data=True)
382
+ if attr.get("element") == "H"
383
+ ]
384
+ return len(hydrogen_nodes), hydrogen_nodes
385
+
386
+
387
+ def check_hcount_change(react_graph: nx.Graph, prod_graph: nx.Graph) -> int:
388
+ """Computes the maximum change in hydrogen count ('hcount') between
389
+ corresponding nodes in the reactant and product graphs. It considers both
390
+ hydrogen formation and breakage.
391
+
392
+ :param react_graph: The graph representing reactants.
393
+ :type react_graph: nx.Graph
394
+ :param prod_graph: The graph representing products.
395
+ :type prod_graph: nx.Graph
396
+
397
+ :return: The maximum hydrogen change observed across all nodes.
398
+ :rtype: int
399
+ """
400
+
401
+ def _coerce_hcount(value: Any) -> int:
402
+ try:
403
+ if isinstance(value, (tuple, list)):
404
+ values = [int(item or 0) for item in value]
405
+ return max(values, default=0)
406
+ return int(value or 0)
407
+ except (TypeError, ValueError):
408
+ return 0
409
+
410
+ hcount_break, _ = check_explicit_hydrogen(react_graph)
411
+ hcount_form, _ = check_explicit_hydrogen(prod_graph)
412
+
413
+ for node_id in set(react_graph.nodes) | set(prod_graph.nodes):
414
+ react_hcount = (
415
+ _coerce_hcount(react_graph.nodes[node_id].get("hcount", 0))
416
+ if node_id in react_graph
417
+ else 0
418
+ )
419
+ prod_hcount = (
420
+ _coerce_hcount(prod_graph.nodes[node_id].get("hcount", 0))
421
+ if node_id in prod_graph
422
+ else 0
423
+ )
424
+
425
+ if react_hcount >= prod_hcount:
426
+ hcount_break += react_hcount - prod_hcount
427
+ else:
428
+ hcount_form += prod_hcount - react_hcount
429
+
430
+ return max(hcount_break, hcount_form)
431
+
432
+
433
+ def get_cycle_member_rings(G: nx.Graph, type="minimal") -> List[int]:
434
+ """Identifies all cycles in the given graph using cycle bases to ensure no
435
+ overlap and returns a list of the sizes of these cycles (member rings),
436
+ sorted in ascending order.
437
+
438
+ :param G: The NetworkX graph to be analyzed.
439
+ :type G: nx.Graph
440
+
441
+ :return: A sorted list of cycle sizes (member rings) found in the graph.
442
+ :rtype: List[int]
443
+ """
444
+ if not isinstance(G, nx.Graph):
445
+ raise TypeError("Input must be a networkx Graph object.")
446
+
447
+ if type == "minimal":
448
+ cycles = nx.minimum_cycle_basis(G)
449
+ else:
450
+ cycles = nx.cycle_basis(G)
451
+ member_rings = [len(cycle) for cycle in cycles]
452
+
453
+ member_rings.sort()
454
+
455
+ return member_rings
456
+
457
+
458
+ def get_priority(reaction_centers: List[Any]) -> List[int]:
459
+ """Evaluate reaction centers for specific graph characteristics, selecting
460
+ indices based on the shortest reaction paths and maximum ring sizes, and
461
+ adjusting for certain graph types by modifying the ring information.
462
+
463
+ :param reaction_centers: List[Any], a list of reaction centers where each center should be
464
+ capable of being analyzed for graph type and ring sizes.
465
+
466
+ :return: Indices selected by shortest reaction path and largest ring size,
467
+ falling back to the shortest-path indices.
468
+ :rtype: List[int]
469
+ """
470
+ # Extract topology types and ring sizes from reaction centers
471
+ topo_type = [
472
+ GraphDescriptor.check_graph_type(center) for center in reaction_centers
473
+ ]
474
+ cyclic = [
475
+ get_cycle_member_rings(center, "fundamental") for center in reaction_centers
476
+ ]
477
+
478
+ # Adjust ring information based on the graph type
479
+ for index, graph_type in enumerate(topo_type):
480
+ if graph_type in ["Acyclic", "Complex Cyclic"]:
481
+ cyclic[index] = [0] + cyclic[index]
482
+
483
+ # Determine minimum reaction steps
484
+ reaction_steps = [len(rings) for rings in cyclic]
485
+ min_reaction_step = min(reaction_steps)
486
+
487
+ # Filter indices with the minimum reaction steps
488
+ indices_shortest = [
489
+ i for i, steps in enumerate(reaction_steps) if steps == min_reaction_step
490
+ ]
491
+
492
+ # Filter indices with the maximum ring size
493
+ max_size = max(
494
+ max(rings) for rings in cyclic if rings
495
+ ) # Safeguard against empty sublists
496
+ prior_indices = [i for i, rings in enumerate(cyclic) if max(rings) == max_size]
497
+
498
+ # Combine criteria for final indices
499
+ final_indices = [index for index in prior_indices if index in indices_shortest]
500
+
501
+ # Fallback to shortest indices if no indices meet both criteria
502
+ if not final_indices:
503
+ return indices_shortest
504
+
505
+ return final_indices
506
+
507
+
508
+ def _normalize_h_pair(h_react: int, h_prod: int) -> Tuple[int, int]:
509
+ """Normalize reactant/product hydrogen counts to relative change form.
510
+
511
+ .. rubric:: Examples
512
+
513
+ (1, 1) -> (0, 0)
514
+ (2, 1) -> (1, 0)
515
+ (1, 2) -> (0, 1)
516
+
517
+ :param h_react: Hydrogen count in reactant state.
518
+ :type h_react: int
519
+ :param h_prod: Hydrogen count in product state.
520
+ :type h_prod: int
521
+ :return: Normalized hydrogen pair.
522
+ :rtype: Tuple[int, int]
523
+ """
524
+ common = min(h_react, h_prod)
525
+ return h_react - common, h_prod - common
526
+
527
+
528
+ def normalize_h_pair_graph(rc_graph: nx.Graph, inplace: bool = False) -> nx.Graph:
529
+ """
530
+ Normalize paired hydrogen counts for all ITS nodes.
531
+
532
+ New-style ITS nodes may store ``hcount`` directly as
533
+ ``(reactant_hcount, product_hcount)``. Legacy ITS nodes may instead store
534
+ hydrogen counts inside ``typesGH``:
535
+
536
+ ``typesGH = (reactant_attr, product_attr)``
537
+
538
+ where each side tuple has the form
539
+ ``(element, aromatic, hydrogen_count, charge, neighbors)``.
540
+ Both representations are normalized when present.
541
+
542
+ :param rc_graph: Reaction-center graph.
543
+ :type rc_graph: nx.Graph
544
+ :param inplace: Whether to modify the input graph in place.
545
+ :type inplace: bool
546
+ :return: Graph with normalized ``typesGH`` hydrogen fields.
547
+ :rtype: nx.Graph
548
+ """
549
+ graph = rc_graph if inplace else deepcopy(rc_graph)
550
+
551
+ for node, data in graph.nodes(data=True):
552
+ hcount = data.get("hcount")
553
+ if (
554
+ isinstance(hcount, (list, tuple))
555
+ and len(hcount) == 2
556
+ and all(isinstance(value, int) for value in hcount)
557
+ ):
558
+ data["hcount"] = _normalize_h_pair(hcount[0], hcount[1])
559
+
560
+ typesgh = data.get("typesGH")
561
+ if typesgh is None:
562
+ continue
563
+
564
+ if len(typesgh) != 2:
565
+ raise ValueError(
566
+ f"Node {node} has invalid typesGH structure: expected length 2, "
567
+ f"got {len(typesgh)}."
568
+ )
569
+
570
+ react_attr, prod_attr = typesgh
571
+
572
+ if len(react_attr) < 3 or len(prod_attr) < 3:
573
+ raise ValueError(
574
+ f"Node {node} has invalid typesGH atom tuples: "
575
+ f"{react_attr}, {prod_attr}"
576
+ )
577
+
578
+ h_react = react_attr[2]
579
+ h_prod = prod_attr[2]
580
+
581
+ new_h_react, new_h_prod = _normalize_h_pair(h_react, h_prod)
582
+
583
+ new_react_attr = list(react_attr)
584
+ new_prod_attr = list(prod_attr)
585
+
586
+ new_react_attr[2] = new_h_react
587
+ new_prod_attr[2] = new_h_prod
588
+
589
+ data["typesGH"] = (tuple(new_react_attr), tuple(new_prod_attr))
590
+
591
+ return graph