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,520 @@
1
+ from __future__ import annotations
2
+
3
+ """Representation-aware visual adapters for SynKit graphs.
4
+
5
+ This module is intentionally lightweight: it detects the graph representation
6
+ and converts raw NetworkX attributes into stable labels/colors that drawing
7
+ backends can consume. The adapters never mutate the input graph.
8
+ """
9
+
10
+ from dataclasses import dataclass, field
11
+ from typing import Any, Dict, Hashable, Iterable, Literal, Mapping
12
+
13
+ import networkx as nx
14
+
15
+ VisualKind = Literal[
16
+ "molecule",
17
+ "legacy_its",
18
+ "tuple_its",
19
+ "compact_mtg",
20
+ "mechanism_dag",
21
+ "unknown",
22
+ ]
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class VisualNode:
27
+ """Drawing-ready node information."""
28
+
29
+ node_id: Hashable
30
+ label: str
31
+ element: str | None = None
32
+ atom_map: int | None = None
33
+ badges: tuple[str, ...] = ()
34
+ changed: bool = False
35
+ raw: Mapping[str, Any] = field(default_factory=dict)
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class VisualEdge:
40
+ """Drawing-ready edge information."""
41
+
42
+ source: Hashable
43
+ target: Hashable
44
+ label: str = ""
45
+ state: str = "unchanged"
46
+ color: str = "#2f3437"
47
+ width: float = 2.0
48
+ raw: Mapping[str, Any] = field(default_factory=dict)
49
+
50
+
51
+ @dataclass(frozen=True)
52
+ class VisualGraph:
53
+ """A compact, immutable view of graph content for renderers."""
54
+
55
+ kind: VisualKind
56
+ nodes: tuple[VisualNode, ...]
57
+ edges: tuple[VisualEdge, ...]
58
+ title: str = ""
59
+ metadata: Mapping[str, Any] = field(default_factory=dict)
60
+
61
+
62
+ BOND_SYMBOLS = {
63
+ None: "∅",
64
+ 0: "∅",
65
+ 0.0: "∅",
66
+ 1: "—",
67
+ 1.0: "—",
68
+ 1.5: ":",
69
+ 2: "=",
70
+ 2.0: "=",
71
+ 3: "≡",
72
+ 3.0: "≡",
73
+ }
74
+
75
+ EDGE_COLORS = {
76
+ "unchanged": "#6b7280",
77
+ "formed": "#15803d",
78
+ "broken": "#b91c1c",
79
+ "order_changed": "#ca8a04",
80
+ "transient": "#7c3aed",
81
+ "unknown": "#2f3437",
82
+ }
83
+
84
+ NODE_TIMELINE_ATTRS = (
85
+ "aromatic",
86
+ "hcount",
87
+ "charge",
88
+ "radical",
89
+ "lone_pairs",
90
+ "present",
91
+ )
92
+ EDGE_TIMELINE_ATTRS = ("order", "kekule_order", "sigma_order", "pi_order")
93
+ ELECTRON_NODE_ATTRS = ("charge", "hcount", "lone_pairs", "radical")
94
+
95
+
96
+ def detect_visual_kind(graph: nx.Graph) -> VisualKind:
97
+ """Return the visualization representation kind for ``graph``.
98
+
99
+ :param graph: NetworkX graph to inspect.
100
+ :type graph: nx.Graph
101
+ :return: Detected graph kind.
102
+ :rtype: VisualKind
103
+ """
104
+
105
+ if not isinstance(graph, nx.Graph):
106
+ return "unknown"
107
+
108
+ if _looks_like_mechanism_dag(graph):
109
+ return "mechanism_dag"
110
+ if _looks_like_compact_mtg(graph):
111
+ return "compact_mtg"
112
+ if _looks_like_tuple_its(graph):
113
+ return "tuple_its"
114
+ if _looks_like_legacy_its(graph):
115
+ return "legacy_its"
116
+ if _looks_like_molecule(graph):
117
+ return "molecule"
118
+ return "unknown"
119
+
120
+
121
+ def to_visual_graph(
122
+ graph: nx.Graph,
123
+ *,
124
+ kind: VisualKind | None = None,
125
+ mode: Literal["compact", "electron", "sigma_pi", "timeline"] = "compact",
126
+ show_atom_map: bool = True,
127
+ title: str = "",
128
+ ) -> VisualGraph:
129
+ """Adapt a SynKit graph to drawing-ready labels.
130
+
131
+ :param graph: NetworkX graph to adapt.
132
+ :type graph: nx.Graph
133
+ :param kind: Optional explicit representation kind.
134
+ :type kind: Optional[VisualKind]
135
+ :param mode: Label density. ``sigma_pi`` and ``timeline`` are mostly useful
136
+ for tuple ITS and compact MTG.
137
+ :type mode: str
138
+ :param show_atom_map: Include atom-map numbers in node labels when present.
139
+ :type show_atom_map: bool
140
+ :param title: Optional title carried to renderer metadata.
141
+ :type title: str
142
+ :return: Immutable visual graph model.
143
+ :rtype: VisualGraph
144
+ """
145
+
146
+ detected = kind or detect_visual_kind(graph)
147
+ nodes = tuple(
148
+ _adapt_node(node_id, attrs, detected, mode=mode, show_atom_map=show_atom_map)
149
+ for node_id, attrs in graph.nodes(data=True)
150
+ )
151
+ edges = tuple(
152
+ _adapt_edge(u, v, attrs, detected, mode=mode)
153
+ for u, v, attrs in graph.edges(data=True)
154
+ )
155
+ return VisualGraph(
156
+ kind=detected,
157
+ nodes=nodes,
158
+ edges=edges,
159
+ title=title,
160
+ metadata={
161
+ "mode": mode,
162
+ "node_count": graph.number_of_nodes(),
163
+ "edge_count": graph.number_of_edges(),
164
+ },
165
+ )
166
+
167
+
168
+ def summarize_visual_graph(visual: VisualGraph) -> Dict[str, Any]:
169
+ """Return a notebook-friendly summary of a visual graph."""
170
+
171
+ return {
172
+ "kind": visual.kind,
173
+ "title": visual.title,
174
+ "metadata": dict(visual.metadata),
175
+ "nodes": [
176
+ {
177
+ "id": node.node_id,
178
+ "label": node.label,
179
+ "badges": list(node.badges),
180
+ "changed": node.changed,
181
+ }
182
+ for node in visual.nodes
183
+ ],
184
+ "edges": [
185
+ {
186
+ "source": edge.source,
187
+ "target": edge.target,
188
+ "label": edge.label,
189
+ "state": edge.state,
190
+ "color": edge.color,
191
+ }
192
+ for edge in visual.edges
193
+ ],
194
+ }
195
+
196
+
197
+ def _looks_like_molecule(graph: nx.Graph) -> bool:
198
+ return bool(graph.nodes) and all(
199
+ "element" in attrs and not _is_pair(attrs.get("element"))
200
+ for _, attrs in graph.nodes(data=True)
201
+ )
202
+
203
+
204
+ def _looks_like_legacy_its(graph: nx.Graph) -> bool:
205
+ if not graph.edges:
206
+ return False
207
+ has_pair_order = any(
208
+ _is_pair(attrs.get("order")) for _, _, attrs in graph.edges(data=True)
209
+ )
210
+ has_tuple_electron_edges = any(
211
+ key in attrs
212
+ for _, _, attrs in graph.edges(data=True)
213
+ for key in ("sigma_order", "pi_order", "kekule_order")
214
+ )
215
+ return has_pair_order and not has_tuple_electron_edges
216
+
217
+
218
+ def _looks_like_tuple_its(graph: nx.Graph) -> bool:
219
+ if not graph.nodes and not graph.edges:
220
+ return False
221
+ node_pair = any(
222
+ _is_pair(attrs.get(key))
223
+ for _, attrs in graph.nodes(data=True)
224
+ for key in ("element", "hcount", "charge", "lone_pairs", "radical", "present")
225
+ )
226
+ edge_pair = any(
227
+ _is_pair(attrs.get(key))
228
+ for _, _, attrs in graph.edges(data=True)
229
+ for key in ("sigma_order", "pi_order", "kekule_order")
230
+ )
231
+ return node_pair or edge_pair
232
+
233
+
234
+ def _looks_like_compact_mtg(graph: nx.Graph) -> bool:
235
+ graph_steps = graph.graph.get("steps")
236
+ if isinstance(graph_steps, int) and graph_steps >= 2:
237
+ return True
238
+ has_steps_attr = any(
239
+ "steps" in attrs for _, attrs in graph.nodes(data=True)
240
+ ) or any("steps" in attrs for _, _, attrs in graph.edges(data=True))
241
+ if not has_steps_attr:
242
+ return False
243
+ has_timeline = any(
244
+ _is_timeline(attrs.get(key))
245
+ for _, attrs in graph.nodes(data=True)
246
+ for key in NODE_TIMELINE_ATTRS
247
+ ) or any(
248
+ _is_timeline(attrs.get(key))
249
+ for _, _, attrs in graph.edges(data=True)
250
+ for key in EDGE_TIMELINE_ATTRS
251
+ )
252
+ return has_timeline
253
+
254
+
255
+ def _looks_like_mechanism_dag(graph: nx.Graph) -> bool:
256
+ if not graph.is_directed():
257
+ return False
258
+ graph_kind = str(graph.graph.get("kind", "")).lower()
259
+ if graph_kind in {"mechanism_dag", "mechanism", "reaction_dag"}:
260
+ return True
261
+ return any(
262
+ attrs.get("kind") in {"reaction", "step", "species"}
263
+ for _, attrs in graph.nodes(data=True)
264
+ )
265
+
266
+
267
+ def _adapt_node(
268
+ node_id: Hashable,
269
+ attrs: Mapping[str, Any],
270
+ kind: VisualKind,
271
+ *,
272
+ mode: str,
273
+ show_atom_map: bool,
274
+ ) -> VisualNode:
275
+ element = _first_present(attrs.get("element"))
276
+ atom_map = _first_present(attrs.get("atom_map"))
277
+ label = str(element or node_id)
278
+ if show_atom_map and atom_map not in (None, 0):
279
+ label = f"{label}:{atom_map}"
280
+ elif show_atom_map and atom_map == 0:
281
+ label = f"{label}:{node_id}"
282
+
283
+ badges = _node_badges(attrs, kind, mode)
284
+ changed = bool(badges) or any(
285
+ _is_changed_pair(attrs.get(key)) for key in ELECTRON_NODE_ATTRS
286
+ )
287
+ return VisualNode(
288
+ node_id=node_id,
289
+ label=label,
290
+ element=str(element) if element is not None else None,
291
+ atom_map=int(atom_map) if isinstance(atom_map, int) else None,
292
+ badges=tuple(badges),
293
+ changed=changed,
294
+ raw=dict(attrs),
295
+ )
296
+
297
+
298
+ def _adapt_edge(
299
+ u: Hashable,
300
+ v: Hashable,
301
+ attrs: Mapping[str, Any],
302
+ kind: VisualKind,
303
+ *,
304
+ mode: str,
305
+ ) -> VisualEdge:
306
+ if kind == "compact_mtg":
307
+ label = _mtg_edge_label(attrs, mode)
308
+ state = _timeline_edge_state(attrs)
309
+ elif kind == "tuple_its":
310
+ label = _tuple_its_edge_label(attrs, mode)
311
+ state = _pair_edge_state(_preferred_edge_pair(attrs))
312
+ elif kind == "legacy_its":
313
+ pair = attrs.get("order", (None, None))
314
+ label = _pair_label(pair)
315
+ state = _pair_edge_state(pair)
316
+ else:
317
+ order = attrs.get("order")
318
+ label = _bond_symbol(order)
319
+ state = "unchanged"
320
+
321
+ return VisualEdge(
322
+ source=u,
323
+ target=v,
324
+ label=label,
325
+ state=state,
326
+ color=EDGE_COLORS.get(state, EDGE_COLORS["unknown"]),
327
+ width=(
328
+ 3.0 if state in {"formed", "broken", "order_changed", "transient"} else 2.0
329
+ ),
330
+ raw=dict(attrs),
331
+ )
332
+
333
+
334
+ def _node_badges(attrs: Mapping[str, Any], kind: VisualKind, mode: str) -> list[str]:
335
+ badges: list[str] = []
336
+ if kind in {"tuple_its", "compact_mtg"}:
337
+ for key in ELECTRON_NODE_ATTRS:
338
+ value = attrs.get(key)
339
+ if kind == "compact_mtg" and _is_timeline(value):
340
+ if _timeline_changes(value) or mode in {"electron", "timeline"}:
341
+ badges.append(f"{_short_node_key(key)}:{_format_timeline(value)}")
342
+ elif _is_pair(value):
343
+ if value[0] != value[1] or mode in {"electron", "timeline"}:
344
+ badges.append(f"{_short_node_key(key)}:{_format_pair(value)}")
345
+ elif mode in {"electron", "timeline"} and value not in (None, 0, False):
346
+ badges.append(f"{_short_node_key(key)}:{value}")
347
+ elif kind == "molecule":
348
+ for key in ("charge", "radical", "lone_pairs"):
349
+ value = attrs.get(key)
350
+ if value not in (None, 0, False):
351
+ badges.append(f"{_short_node_key(key)}:{value}")
352
+ return badges
353
+
354
+
355
+ def _tuple_its_edge_label(attrs: Mapping[str, Any], mode: str) -> str:
356
+ if mode == "sigma_pi":
357
+ sigma = attrs.get("sigma_order")
358
+ pi = attrs.get("pi_order")
359
+ return f"σ{_format_pair(sigma)} π{_format_pair(pi)}"
360
+ pair = attrs.get("kekule_order", attrs.get("order"))
361
+ return _pair_label(pair)
362
+
363
+
364
+ def _mtg_edge_label(attrs: Mapping[str, Any], mode: str) -> str:
365
+ if mode == "sigma_pi":
366
+ parts = []
367
+ for key in ("sigma_order", "pi_order"):
368
+ value = attrs.get(key)
369
+ if _is_timeline(value) and (_timeline_changes(value) or mode == "timeline"):
370
+ parts.append(f"{_short_edge_key(key)}:{_format_timeline(value)}")
371
+ return " ".join(parts) or _format_timeline(
372
+ attrs.get("kekule_order", attrs.get("order"))
373
+ )
374
+ if mode == "timeline":
375
+ parts = []
376
+ for key in EDGE_TIMELINE_ATTRS:
377
+ value = attrs.get(key)
378
+ if _is_timeline(value):
379
+ parts.append(f"{_short_edge_key(key)}:{_format_timeline(value)}")
380
+ return " ".join(parts)
381
+ value = attrs.get("kekule_order", attrs.get("order"))
382
+ return _format_timeline(value) if _is_timeline(value) else _bond_symbol(value)
383
+
384
+
385
+ def _preferred_edge_pair(attrs: Mapping[str, Any]) -> Any:
386
+ return attrs.get("kekule_order", attrs.get("order"))
387
+
388
+
389
+ def _pair_edge_state(pair: Any) -> str:
390
+ if not _is_pair(pair):
391
+ return "unknown"
392
+ before, after = pair
393
+ before = _none_order(before)
394
+ after = _none_order(after)
395
+ if before == after:
396
+ return "unchanged"
397
+ if before == 0 and after > 0:
398
+ return "formed"
399
+ if before > 0 and after == 0:
400
+ return "broken"
401
+ return "order_changed"
402
+
403
+
404
+ def _timeline_edge_state(attrs: Mapping[str, Any]) -> str:
405
+ timeline = attrs.get("kekule_order", attrs.get("order"))
406
+ if not _is_timeline(timeline):
407
+ return "unknown"
408
+ numeric = [_none_order(v) for v in timeline if _is_order_value(v)]
409
+ if not numeric or len(set(numeric)) == 1:
410
+ return "unchanged"
411
+ if numeric[0] == numeric[-1] and len(set(numeric)) > 1:
412
+ return "transient"
413
+ if numeric[0] == 0 and numeric[-1] > 0:
414
+ return "formed"
415
+ if numeric[0] > 0 and numeric[-1] == 0:
416
+ return "broken"
417
+ return "order_changed"
418
+
419
+
420
+ def _pair_label(pair: Any) -> str:
421
+ if not _is_pair(pair):
422
+ return _bond_symbol(pair)
423
+ return f"{_bond_symbol(pair[0])}>{_bond_symbol(pair[1])}"
424
+
425
+
426
+ def _format_pair(pair: Any) -> str:
427
+ if not _is_pair(pair):
428
+ return str(pair)
429
+ return f"{_format_value(pair[0])}>{_format_value(pair[1])}"
430
+
431
+
432
+ def _format_timeline(value: Any) -> str:
433
+ if not _is_timeline(value):
434
+ return str(value)
435
+ return "-".join(_format_value(item) for item in value)
436
+
437
+
438
+ def _format_value(value: Any) -> str:
439
+ if value is None:
440
+ return "∅"
441
+ if isinstance(value, float) and value.is_integer():
442
+ return str(int(value))
443
+ return str(value)
444
+
445
+
446
+ def _bond_symbol(order: Any) -> str:
447
+ return BOND_SYMBOLS.get(order, _format_value(order))
448
+
449
+
450
+ def _short_node_key(key: str) -> str:
451
+ return {
452
+ "charge": "q",
453
+ "hcount": "H",
454
+ "lone_pairs": "lp",
455
+ "radical": "rad",
456
+ }.get(key, key)
457
+
458
+
459
+ def _short_edge_key(key: str) -> str:
460
+ return {
461
+ "order": "ord",
462
+ "kekule_order": "kek",
463
+ "sigma_order": "σ",
464
+ "pi_order": "π",
465
+ }.get(key, key)
466
+
467
+
468
+ def _is_pair(value: Any) -> bool:
469
+ return (
470
+ isinstance(value, tuple)
471
+ and len(value) == 2
472
+ and not any(isinstance(item, (set, list, tuple, dict)) for item in value)
473
+ )
474
+
475
+
476
+ def _is_timeline(value: Any) -> bool:
477
+ return (
478
+ isinstance(value, tuple)
479
+ and len(value) >= 3
480
+ and not any(isinstance(item, (set, list, tuple, dict)) for item in value)
481
+ )
482
+
483
+
484
+ def _is_changed_pair(value: Any) -> bool:
485
+ return _is_pair(value) and value[0] != value[1]
486
+
487
+
488
+ def _timeline_changes(value: Any) -> bool:
489
+ return _is_timeline(value) and len(set(value)) > 1
490
+
491
+
492
+ def _is_order_value(value: Any) -> bool:
493
+ return value is None or isinstance(value, (int, float))
494
+
495
+
496
+ def _none_order(value: Any) -> float:
497
+ return 0.0 if value is None else float(value)
498
+
499
+
500
+ def _first_present(value: Any) -> Any:
501
+ if _is_pair(value):
502
+ return value[0] if value[0] is not None else value[1]
503
+ if _is_timeline(value):
504
+ for item in value:
505
+ if item is not None:
506
+ return item
507
+ return None
508
+ return value
509
+
510
+
511
+ def iter_changed_edges(visual: VisualGraph) -> Iterable[VisualEdge]:
512
+ """Yield edges whose visual state is not unchanged."""
513
+
514
+ return (edge for edge in visual.edges if edge.state != "unchanged")
515
+
516
+
517
+ def iter_changed_nodes(visual: VisualGraph) -> Iterable[VisualNode]:
518
+ """Yield nodes with at least one visual badge/change marker."""
519
+
520
+ return (node for node in visual.nodes if node.changed)
synkit/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .version import __version__
2
+
3
+ __all__ = ["__version__"]
synkit/_native.py ADDED
@@ -0,0 +1,91 @@
1
+ """Shared discovery and installed-file verification for bundled C ABI libraries."""
2
+
3
+ import base64
4
+ from functools import lru_cache
5
+ import hashlib
6
+ from importlib.metadata import distribution
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ import sys
11
+
12
+
13
+ def bundled_library(package_dir, stem):
14
+ """Locate one packaged library without compiling or downloading anything."""
15
+ name = (
16
+ stem + ".dll"
17
+ if sys.platform == "win32"
18
+ else (
19
+ "lib" + stem + ".dylib"
20
+ if sys.platform == "darwin"
21
+ else "lib" + stem + ".so"
22
+ )
23
+ )
24
+ path = Path(package_dir).resolve() / "lib" / name
25
+ if not path.is_file():
26
+ raise FileNotFoundError(f"No bundled {stem} library is installed")
27
+ return path
28
+
29
+
30
+ @lru_cache(maxsize=8)
31
+ def _conda_record_digest(library_file):
32
+ """Read the owning Conda package's checksum after prefix relocation."""
33
+ package = Path(__file__).resolve().parent
34
+ library_file.relative_to(package)
35
+ for prefix in package.parents:
36
+ metadata = prefix / "conda-meta"
37
+ if metadata.is_dir():
38
+ return _conda_prefix_digest(prefix, library_file)
39
+ return None
40
+
41
+
42
+ def _conda_prefix_digest(prefix, library_file):
43
+ relative = os.path.normcase(library_file.relative_to(prefix).as_posix())
44
+ for filename in sorted((prefix / "conda-meta").glob("synkit-*.json")):
45
+ try:
46
+ record = json.loads(filename.read_text(encoding="utf-8"))
47
+ except (OSError, ValueError) as exc:
48
+ raise RuntimeError("Cannot read installed SynKit Conda metadata") from exc
49
+ if record.get("name") != "synkit":
50
+ continue
51
+ for entry in record.get("paths_data", {}).get("paths", ()):
52
+ if os.path.normcase(entry.get("_path", "")) != relative:
53
+ continue
54
+ # Conda and Mamba record bytes after relocation/code signing here.
55
+ digest = entry.get("sha256_in_prefix") or entry.get("sha256")
56
+ if (
57
+ isinstance(digest, str)
58
+ and len(digest) == 64
59
+ and all(c in "0123456789abcdefABCDEF" for c in digest)
60
+ ):
61
+ return digest.lower()
62
+ raise RuntimeError(f"The bundled library has no installed Conda SHA-256 record: {relative}")
63
+ return None
64
+
65
+
66
+ @lru_cache(maxsize=8)
67
+ def _wheel_record_digest(library_file):
68
+ installed = distribution("synkit")
69
+ relative = (
70
+ "synkit/" + library_file.relative_to(Path(__file__).resolve().parent).as_posix()
71
+ )
72
+ for entry in installed.files or ():
73
+ if (
74
+ str(entry) == relative
75
+ and Path(installed.locate_file(entry)).resolve() == library_file
76
+ ):
77
+ if entry.hash is not None and entry.hash.mode == "sha256":
78
+ return base64.urlsafe_b64decode(entry.hash.value + "==").hex()
79
+ raise RuntimeError(
80
+ f"The bundled library has no installed wheel SHA-256 record: {relative}"
81
+ )
82
+
83
+
84
+ def verify_wheel_library(path):
85
+ """Check final installed bytes against their Conda or wheel SHA-256 record."""
86
+ path = Path(path).resolve()
87
+ expected = _conda_record_digest(path) or _wheel_record_digest(path)
88
+ actual = hashlib.sha256(path.read_bytes()).hexdigest()
89
+ if actual != expected:
90
+ raise RuntimeError(f"Bundled native library checksum mismatch: {path.name}")
91
+ return actual
synkit/examples.py ADDED
@@ -0,0 +1,50 @@
1
+ # synkit/examples.py
2
+
3
+ from __future__ import annotations
4
+
5
+ from functools import lru_cache
6
+ from importlib.resources import files, as_file
7
+
8
+ from synkit.IO import load_database # adjust if the import path differs
9
+
10
+
11
+ def _sanitize_slug(slug: str) -> str:
12
+ if ".." in slug or slug.startswith(("/", "\\")):
13
+ raise ValueError(f"Invalid example name: {slug!r}")
14
+ return slug
15
+
16
+
17
+ def list_examples() -> list[str]:
18
+ """
19
+ Returns all available example slugs (without extensions), e.g. ['paracetamol', ...]
20
+ """
21
+ data_dir = files("synkit").joinpath("Data")
22
+ slugs: set[str] = set()
23
+ for p in data_dir.iterdir():
24
+ if not p.is_file():
25
+ continue
26
+ if p.name.endswith(".json.gz"):
27
+ slugs.add(p.name[: -len(".json.gz")])
28
+ elif p.name.endswith(".json"):
29
+ slugs.add(p.name[: -len(".json")])
30
+ return sorted(slugs)
31
+
32
+
33
+ @lru_cache(maxsize=32)
34
+ def load_example(slug: str):
35
+ """
36
+ Load an example by slug, preferring compressed (.json.gz) over plain (.json).
37
+ Delegates actual parsing to synkit.IO.load_database.
38
+ """
39
+ slug = _sanitize_slug(slug)
40
+ data_dir = files("synkit").joinpath("Data")
41
+ candidates = [f"{slug}.json.gz", f"{slug}.json"]
42
+ for name in candidates:
43
+ resource = data_dir.joinpath(name)
44
+ if resource.is_file():
45
+ # importlib.resources may keep resources inside archives; as_file gives a real path
46
+ with as_file(resource) as real_path:
47
+ return load_database(real_path)
48
+ raise FileNotFoundError(
49
+ f"Example '{slug}' not found (looked for {', '.join(candidates)})"
50
+ )
synkit/version.py ADDED
@@ -0,0 +1,23 @@
1
+ """Installed and source-checkout version discovery."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+ from pathlib import Path
5
+
6
+ try:
7
+ import tomllib
8
+ except ModuleNotFoundError:
9
+ import tomli as tomllib
10
+
11
+ try:
12
+ # A source checkout can coexist with an older installed distribution.
13
+ # Prefer its adjacent project metadata; installed wheels do not include
14
+ # the repository-level pyproject and therefore fall through naturally.
15
+ pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml"
16
+ __version__ = tomllib.loads(pyproject.read_text(encoding="utf-8"))["project"][
17
+ "version"
18
+ ]
19
+ except (KeyError, OSError, tomllib.TOMLDecodeError):
20
+ try:
21
+ __version__ = version("synkit")
22
+ except PackageNotFoundError:
23
+ __version__ = "1.6.5"