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,584 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Optional
5
+
6
+ import numpy as np
7
+
8
+ from .stoich import right_nullspace, stoichiometric_matrix
9
+
10
+
11
+ @dataclass
12
+ class ThermoSummary:
13
+ """
14
+ Lightweight container summarizing thermodynamic-like stoichiometric
15
+ properties of a chemical reaction network.
16
+
17
+ This dataclass gathers the main outputs of the thermo module into a single
18
+ object for convenient downstream inspection, reporting, or serialization.
19
+ It is intentionally compact and stores only the most interpretable summary
20
+ flags and one example conservation-law vector when available.
21
+
22
+ :param conservative:
23
+ Whether the network is conservative, i.e. whether there exists a
24
+ strictly positive vector :math:`m > 0` such that :math:`m^T S = 0`.
25
+ The value may be ``None`` if the check is inconclusive.
26
+ :type conservative: Optional[bool]
27
+ :param consistent:
28
+ Whether the network is consistent, i.e. whether there exists a strictly
29
+ positive vector :math:`v > 0` such that :math:`S v = 0`. The value may
30
+ be ``None`` if the check is inconclusive.
31
+ :type consistent: Optional[bool]
32
+ :param example_conservation_law:
33
+ Example normalized strictly positive left-kernel vector when one is
34
+ found, otherwise ``None``.
35
+ :type example_conservation_law: Optional[numpy.ndarray]
36
+ :param irreversible_futile_cycles:
37
+ Boolean indicator of whether the right kernel :math:`\\ker(S)` is
38
+ non-trivial. This is used here as a structural proxy for the presence
39
+ of futile-cycle-like steady flux modes.
40
+ :type irreversible_futile_cycles: bool
41
+
42
+ .. code-block:: python
43
+
44
+ from synkit.CRN.Props.thermo import compute_thermo_summary
45
+
46
+ summary = compute_thermo_summary(hg)
47
+ print(summary.conservative)
48
+ print(summary.consistent)
49
+ print(summary.irreversible_futile_cycles)
50
+ print(summary.example_conservation_law)
51
+ """
52
+
53
+ conservative: Optional[bool]
54
+ consistent: Optional[bool]
55
+ example_conservation_law: Optional[np.ndarray]
56
+ irreversible_futile_cycles: bool
57
+
58
+
59
+ def _normalize_positive(vec: np.ndarray, *, eps: float = 1e-8) -> Optional[np.ndarray]:
60
+ """Normalize a strictly signed vector to a positive unit-:math:`\\ell_1` vector.
61
+
62
+ This helper accepts a candidate vector and checks whether all entries are
63
+ strictly positive or strictly negative up to the threshold ``eps``. If the
64
+ vector is strictly negative, it is sign-flipped. A valid vector is then
65
+ normalized to unit 1-norm and returned.
66
+
67
+ This is primarily used to post-process candidate conservation laws or flux
68
+ modes so they are easier to inspect and compare numerically.
69
+
70
+ :param vec:
71
+ Input vector to test and normalize.
72
+ :type vec: numpy.ndarray
73
+ :param eps:
74
+ Absolute threshold used to determine strict positivity or negativity.
75
+ :type eps: float
76
+ :return:
77
+ A strictly positive vector normalized to sum to 1, or ``None`` if the
78
+ input does not have a uniform strict sign.
79
+ :rtype: Optional[numpy.ndarray]
80
+
81
+ .. code-block:: python
82
+
83
+ import numpy as np
84
+ from synkit.CRN.Props.thermo import _normalize_positive
85
+
86
+ v = np.array([2.0, 3.0, 5.0])
87
+ out = _normalize_positive(v)
88
+ print(out) # array summing to 1.0
89
+ """
90
+ v = np.asarray(vec, dtype=float).reshape(-1)
91
+ if np.all(v > eps):
92
+ s = float(np.sum(v))
93
+ if s > 0:
94
+ return v / s
95
+ if np.all(v < -eps):
96
+ v = -v
97
+ s = float(np.sum(v))
98
+ if s > 0:
99
+ return v / s
100
+ return None
101
+
102
+
103
+ def _find_positive_left_kernel_vector(
104
+ S: np.ndarray,
105
+ *,
106
+ eps: float = 1e-8,
107
+ rtol: float = 1e-12,
108
+ ) -> tuple[Optional[bool], Optional[np.ndarray]]:
109
+ """Attempt to find a strictly positive conservation-law vector
110
+ :math:`m > 0` satisfying :math:`m^T S = 0`.
111
+
112
+ This helper implements the main conservativity search logic used by
113
+ :func:`is_conservative` and :func:`compute_conservativity`. The search is
114
+ performed in several stages:
115
+
116
+ 1. compute a basis of :math:`\\ker(S^T)`,
117
+ 2. test whether any basis vector is already strictly positive up to sign,
118
+ 3. project the all-ones vector into the left kernel and test whether the
119
+ projection is strictly positive,
120
+ 4. if SciPy is available, solve a linear feasibility problem enforcing
121
+ :math:`S^T m = 0` and :math:`m_i \\ge \\varepsilon`.
122
+
123
+ This layered approach makes the routine useful both with and without SciPy.
124
+
125
+ :param S:
126
+ Stoichiometric matrix of shape ``(n_species, n_reactions)``.
127
+ :type S: numpy.ndarray
128
+ :param eps:
129
+ Absolute threshold used to test strict positivity.
130
+ :type eps: float
131
+ :param rtol:
132
+ Relative tolerance used in nullspace computations.
133
+ :type rtol: float
134
+ :return:
135
+ A tuple ``(flag, m)`` where ``flag`` is:
136
+
137
+ - ``True`` if a strictly positive conservation law was found,
138
+ - ``False`` if no such law exists,
139
+ - ``None`` if the result is inconclusive,
140
+
141
+ and ``m`` is an example normalized positive conservation law if one was
142
+ found, otherwise ``None``.
143
+ :rtype: Tuple[Optional[bool], Optional[numpy.ndarray]]
144
+
145
+ .. code-block:: python
146
+
147
+ import numpy as np
148
+ from synkit.CRN.Props.thermo import _find_positive_left_kernel_vector
149
+
150
+ S = np.array([[-1.0], [1.0]])
151
+ flag, m = _find_positive_left_kernel_vector(S)
152
+ print(flag)
153
+ print(m)
154
+ """
155
+ S = np.asarray(S, dtype=float)
156
+ n_species, n_reactions = S.shape
157
+
158
+ # No reactions: every species is trivially conserved
159
+ if n_reactions == 0:
160
+ if n_species == 0:
161
+ return True, None
162
+ m = np.ones(n_species, dtype=float)
163
+ m /= np.sum(m)
164
+ return True, m
165
+
166
+ B = left_nullspace_from_matrix(S, rtol=rtol)
167
+ if B is None or B.size == 0:
168
+ return False, None
169
+
170
+ B = np.atleast_2d(B)
171
+
172
+ # 1) quick scan of basis columns
173
+ for j in range(B.shape[1]):
174
+ m = _normalize_positive(B[:, j], eps=eps)
175
+ if m is not None:
176
+ return True, m
177
+
178
+ # 2) projection fallback:
179
+ # project the all-ones vector onto ker(S^T)
180
+ ones = np.ones(n_species, dtype=float)
181
+ # works whether or not B is perfectly orthonormal enough for practice
182
+ coeff = B.T @ ones
183
+ proj = B @ coeff
184
+ m = _normalize_positive(proj, eps=eps)
185
+ if m is not None:
186
+ return True, m
187
+
188
+ # 3) exact LP feasibility check, if SciPy is available
189
+ try:
190
+ from scipy.optimize import linprog # type: ignore
191
+
192
+ c = np.zeros(n_species, dtype=float)
193
+ A_eq = S.T
194
+ b_eq = np.zeros(n_reactions, dtype=float)
195
+ bounds = [(1.0, None) for _ in range(n_species)]
196
+
197
+ res = linprog(c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method="highs")
198
+ if res.success and res.x is not None:
199
+ m = _normalize_positive(np.asarray(res.x, dtype=float), eps=eps)
200
+ if m is not None:
201
+ return True, m
202
+ return False, None
203
+ return False, None
204
+ except Exception:
205
+ pass
206
+
207
+ # Without LP, 1D kernel is definitive; higher-dimensional is otherwise inconclusive.
208
+ if B.shape[1] == 1:
209
+ return False, None
210
+
211
+ return None, None
212
+
213
+
214
+ def left_nullspace_from_matrix(S: np.ndarray, *, rtol: float = 1e-12) -> np.ndarray:
215
+ """Compute a basis for the left kernel :math:`\\ker(S^T)` directly from a
216
+ stoichiometric matrix.
217
+
218
+ This helper is a matrix-level analogue of the graph-based nullspace
219
+ functions in :mod:`stoich`. It is useful when the stoichiometric matrix is
220
+ already available and one wants to avoid reconstructing it from the CRN
221
+ representation.
222
+
223
+ If SciPy is available, the function uses :func:`scipy.linalg.null_space`.
224
+ Otherwise it falls back to an SVD-based implementation using NumPy.
225
+
226
+ :param S:
227
+ Stoichiometric matrix of shape ``(n_species, n_reactions)``.
228
+ :type S: numpy.ndarray
229
+ :param rtol:
230
+ Relative tolerance used to determine the effective numerical rank in
231
+ the nullspace computation.
232
+ :type rtol: float
233
+ :return:
234
+ Matrix whose columns form a basis for :math:`\\ker(S^T)`. The returned
235
+ array has shape ``(n_species, k)``, where ``k`` is the dimension of the
236
+ left kernel.
237
+ :rtype: numpy.ndarray
238
+
239
+ .. code-block:: python
240
+
241
+ import numpy as np
242
+ from synkit.CRN.Props.thermo import left_nullspace_from_matrix
243
+
244
+ S = np.array([[-1.0], [1.0]])
245
+ L = left_nullspace_from_matrix(S)
246
+ print(L.shape)
247
+ """
248
+ from .stoich import _null_space
249
+
250
+ return _null_space(np.asarray(S, dtype=float).T, rtol=rtol)
251
+
252
+
253
+ def is_conservative(
254
+ crn: Any,
255
+ *,
256
+ eps: float = 1e-8,
257
+ rtol: float = 1e-12,
258
+ ) -> Optional[bool]:
259
+ """Check whether the chemical reaction network is conservative.
260
+
261
+ A network is called conservative here if there exists a strictly positive
262
+ vector :math:`m > 0` such that
263
+
264
+ .. math::
265
+
266
+ m^T S = 0,
267
+
268
+ where :math:`S` is the stoichiometric matrix. Such a vector can be
269
+ interpreted as a positive conservation law over species.
270
+
271
+ This function returns only the Boolean-style status of the check. Use
272
+ :func:`compute_conservativity` when an example conservation-law vector is
273
+ also desired.
274
+
275
+ :param crn:
276
+ Hypergraph or bipartite NetworkX graph representing the chemical
277
+ reaction network.
278
+ :type crn: Any
279
+ :param eps:
280
+ Absolute threshold used to test strict positivity of candidate
281
+ conservation-law vectors.
282
+ :type eps: float
283
+ :param rtol:
284
+ Relative tolerance used in nullspace-based computations.
285
+ :type rtol: float
286
+ :return:
287
+ - ``True`` if a strictly positive conservation law exists,
288
+ - ``False`` if no such law exists,
289
+ - ``None`` if the result is inconclusive.
290
+ :rtype: Optional[bool]
291
+
292
+ .. code-block:: python
293
+
294
+ from synkit.CRN.Props.thermo import is_conservative
295
+
296
+ flag = is_conservative(hg)
297
+ print("Conservative?", flag)
298
+ """
299
+ from ..backend import resolve_backend
300
+
301
+ if resolve_backend()[0] == "cpp":
302
+ from ..native_analysis import positive_kernel
303
+
304
+ result = positive_kernel(crn, kind="p")
305
+ return result[0]
306
+ S = stoichiometric_matrix(crn)
307
+ flag, _m = _find_positive_left_kernel_vector(S, eps=eps, rtol=rtol)
308
+ return flag
309
+
310
+
311
+ def compute_conservativity(
312
+ crn: Any,
313
+ *,
314
+ rtol: float = 1e-12,
315
+ eps: float = 1e-8,
316
+ ) -> tuple[Optional[bool], Optional[np.ndarray]]:
317
+ """Compute the conservativity status of a network together with an example
318
+ positive conservation law when available.
319
+
320
+ This is the more informative counterpart of :func:`is_conservative`. It
321
+ checks whether there exists a strictly positive vector :math:`m > 0` such
322
+ that :math:`m^T S = 0`, and if successful it also returns one normalized
323
+ example vector.
324
+
325
+ :param crn:
326
+ Hypergraph or bipartite NetworkX graph representing the chemical
327
+ reaction network.
328
+ :type crn: Any
329
+ :param rtol:
330
+ Relative tolerance used in nullspace-based computations.
331
+ :type rtol: float
332
+ :param eps:
333
+ Absolute threshold used to test strict positivity of candidate
334
+ conservation-law vectors.
335
+ :type eps: float
336
+ :return:
337
+ Tuple ``(flag, m)`` where ``flag`` is the conservativity result and
338
+ ``m`` is an example normalized strictly positive conservation law if
339
+ one was found, otherwise ``None``.
340
+ :rtype: Tuple[Optional[bool], Optional[numpy.ndarray]]
341
+
342
+ .. code-block:: python
343
+
344
+ from synkit.CRN.Props.thermo import compute_conservativity
345
+
346
+ flag, m = compute_conservativity(hg)
347
+ print("Conservative?", flag)
348
+ if m is not None:
349
+ print("Example law:", m)
350
+ """
351
+ from ..backend import resolve_backend
352
+
353
+ if resolve_backend()[0] == "cpp":
354
+ from ..native_analysis import positive_kernel
355
+
356
+ result = positive_kernel(crn, kind="p")
357
+ return result
358
+ S = stoichiometric_matrix(crn)
359
+ return _find_positive_left_kernel_vector(S, eps=eps, rtol=rtol)
360
+
361
+
362
+ def is_consistent(crn: Any, *, eps: float = 1e-8) -> Optional[bool]:
363
+ """Check whether the chemical reaction network is consistent.
364
+
365
+ Consistency is tested here by asking whether there exists a strictly
366
+ positive flux vector :math:`v > 0` such that
367
+
368
+ .. math::
369
+
370
+ S v = 0,
371
+
372
+ where :math:`S` is the stoichiometric matrix. In CRN terminology, this
373
+ corresponds to the existence of a strictly positive right-kernel vector,
374
+ or equivalently a positive T-semiflow.
375
+
376
+ If SciPy is available, the function attempts a linear-programming check.
377
+ Otherwise it falls back to a nullspace-based heuristic.
378
+
379
+ :param crn:
380
+ Hypergraph or bipartite NetworkX graph representing the chemical
381
+ reaction network.
382
+ :type crn: Any
383
+ :param eps:
384
+ Absolute lower bound used to enforce strict positivity of candidate
385
+ flux vectors.
386
+ :type eps: float
387
+ :return:
388
+ - ``True`` if a strictly positive right-kernel vector exists,
389
+ - ``False`` if no such vector exists,
390
+ - ``None`` if the result is inconclusive.
391
+ :rtype: Optional[bool]
392
+
393
+ .. code-block:: python
394
+
395
+ from synkit.CRN.Props.thermo import is_consistent
396
+
397
+ flag = is_consistent(hg)
398
+ print("Consistent?", flag)
399
+ """
400
+ from ..backend import resolve_backend
401
+
402
+ if resolve_backend()[0] == "cpp":
403
+ from ..native_analysis import positive_kernel
404
+
405
+ result = positive_kernel(crn, kind="t")
406
+ return result[0]
407
+ S = stoichiometric_matrix(crn)
408
+ n_species, n_reactions = S.shape
409
+
410
+ if n_reactions == 0:
411
+ return False if n_species > 0 else True
412
+
413
+ try:
414
+ from scipy.optimize import linprog # type: ignore
415
+
416
+ c = np.ones(n_reactions)
417
+ A_eq = S
418
+ b_eq = np.zeros(n_species)
419
+ bounds = [(1.0, None) for _ in range(n_reactions)]
420
+ res = linprog(c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method="highs")
421
+
422
+ if res.success and res.x is not None:
423
+ v = res.x
424
+ residual = S @ v
425
+ max_v = float(np.max(np.abs(v))) or 1.0
426
+ rel_err = np.linalg.norm(residual, ord=np.inf) / max_v
427
+ return bool(rel_err <= 1e-8 and np.all(v >= 1.0 - 1e-7))
428
+ return False
429
+ except Exception:
430
+ pass
431
+
432
+ B = right_nullspace(crn)
433
+ if B is None or B.size == 0:
434
+ return False
435
+
436
+ for k in range(B.shape[1]):
437
+ v = B[:, k]
438
+ if np.all(v > eps) or np.all(v < -eps):
439
+ return True
440
+
441
+ # projection fallback onto ker(S)
442
+ B = np.atleast_2d(B)
443
+ ones = np.ones(B.shape[0], dtype=float)
444
+ coeff = B.T @ ones
445
+ proj = B @ coeff
446
+ if np.all(proj > eps) or np.all(proj < -eps):
447
+ return True
448
+
449
+ return None
450
+
451
+
452
+ def has_irreversible_futile_cycles(crn: Any, *, rtol: float = 1e-12) -> bool:
453
+ """Check whether the network admits non-trivial steady-state flux modes.
454
+
455
+ This function tests whether a nonnegative nonzero right-kernel vector exists.
456
+ This is a structural circulation test and does not establish Gibbs-energy
457
+ feasibility. The legacy function name is retained for compatibility.
458
+
459
+ Previously this tested whether the right kernel :math:`\\ker(S)` is
460
+ non-trivial, i.e. whether there exists a nonzero vector :math:`v` such that
461
+
462
+ .. math::
463
+
464
+ S v = 0.
465
+
466
+ A non-trivial right kernel indicates the presence of flux-mode-like
467
+ directions that do not change net species amounts. In this module, this is
468
+ used as a structural proxy for irreversible futile cycles, although it
469
+ should be interpreted cautiously as a stoichiometric indicator rather than
470
+ a full mechanistic proof.
471
+
472
+ :param crn:
473
+ Hypergraph or bipartite NetworkX graph representing the chemical
474
+ reaction network.
475
+ :type crn: Any
476
+ :param rtol:
477
+ Relative tolerance used in the nullspace computation.
478
+ :type rtol: float
479
+ :return:
480
+ ``True`` if :math:`\\ker(S)` is non-trivial, otherwise ``False``.
481
+ :rtype: bool
482
+
483
+ .. code-block:: python
484
+
485
+ from synkit.CRN.Props.thermo import has_irreversible_futile_cycles
486
+
487
+ has_cycles = has_irreversible_futile_cycles(hg)
488
+ print("Has futile-cycle-like modes?", has_cycles)
489
+ """
490
+ from scipy.optimize import linprog
491
+
492
+ S = stoichiometric_matrix(crn)
493
+ if S.shape[1] == 0:
494
+ return False
495
+ result = linprog(
496
+ np.zeros(S.shape[1]),
497
+ A_eq=np.vstack([S, np.ones((1, S.shape[1]))]),
498
+ b_eq=np.r_[np.zeros(S.shape[0]), 1.0],
499
+ bounds=(0, None),
500
+ method="highs",
501
+ )
502
+ return bool(
503
+ result.success
504
+ and result.x is not None
505
+ and np.min(result.x) >= -1e-9
506
+ and np.max(np.abs(S @ result.x), initial=0) < 1e-8
507
+ )
508
+
509
+
510
+ def has_stoichiometric_dependencies(crn: Any, *, rtol: float = 1e-12) -> bool:
511
+ """Whether reaction vectors are linearly dependent, without sign constraints."""
512
+ return right_nullspace(crn, rtol=rtol).shape[1] > 0
513
+
514
+
515
+ def compute_thermo_summary(
516
+ crn: Any, *, rtol: float = 1e-12, eps: float = 1e-8
517
+ ) -> ThermoSummary:
518
+ """Compute a composite :class:`ThermoSummary` describing key thermodynamic-like
519
+ and structural stoichiometric properties of a chemical reaction network.
520
+
521
+ This helper combines the main thermo-related analyses into a single call:
522
+
523
+ * Conservativity: whether a strictly positive vector :math:`m > 0` exists
524
+ such that :math:`m^T S = 0`.
525
+ * Consistency: whether a strictly positive flux vector :math:`v > 0`
526
+ exists such that :math:`S v = 0`.
527
+ * Irreversible futile-cycle proxy: whether the right kernel
528
+ :math:`\\ker(S)` is non-trivial.
529
+ * Example conservation law: a normalized strictly positive left-kernel
530
+ vector, when one can be found.
531
+
532
+ The returned summary is intended as a lightweight diagnostic object for
533
+ quick inspection of CRN thermodynamic structure without calling each helper
534
+ individually.
535
+
536
+ :param crn:
537
+ Hypergraph or bipartite NetworkX graph representing the chemical
538
+ reaction network.
539
+ :type crn: Any
540
+ :param rtol:
541
+ Relative tolerance used in nullspace-based computations, especially
542
+ when estimating kernel dimensions or checking whether the right kernel
543
+ is non-trivial.
544
+ :type rtol: float
545
+ :param eps:
546
+ Absolute positivity threshold used when testing whether a candidate
547
+ conservation law or flux mode is strictly positive.
548
+ :type eps: float
549
+ :return:
550
+ A :class:`ThermoSummary` instance containing conservativity,
551
+ consistency, an optional example positive conservation law, and a
552
+ Boolean indicator for non-trivial steady-state flux cycles.
553
+ :rtype: ThermoSummary
554
+
555
+ .. code-block:: python
556
+
557
+ from synkit.CRN.Props.thermo import compute_thermo_summary
558
+
559
+ summary = compute_thermo_summary(hg)
560
+
561
+ print("Conservative:", summary.conservative)
562
+ print("Consistent:", summary.consistent)
563
+ print("Has futile-cycle proxy:", summary.irreversible_futile_cycles)
564
+
565
+ if summary.example_conservation_law is not None:
566
+ print("Example conservation law:", summary.example_conservation_law)
567
+
568
+ .. note::
569
+
570
+ The field ``irreversible_futile_cycles`` is used here as a structural
571
+ proxy based on the existence of nonzero vectors in :math:`\\ker(S)`.
572
+ It should be interpreted as a stoichiometric indicator rather than as a
573
+ full mechanistic proof of thermodynamic infeasibility.
574
+ """
575
+ conservative, m = compute_conservativity(crn, rtol=rtol, eps=eps)
576
+ consistent = is_consistent(crn, eps=eps)
577
+ cyc = has_irreversible_futile_cycles(crn, rtol=rtol)
578
+
579
+ return ThermoSummary(
580
+ conservative=conservative,
581
+ consistent=consistent,
582
+ example_conservation_law=m,
583
+ irreversible_futile_cycles=cyc,
584
+ )
@@ -0,0 +1,66 @@
1
+ """KEGG retrieval, parsing and curation utilities for CRN construction.
2
+
3
+ This subpackage is the entry point for reaction networks derived from a curated
4
+ biological pathway rather than from rule-based expansion.
5
+
6
+ .. rubric:: Example
7
+
8
+ .. code-block:: python
9
+
10
+ from synkit.CRN.Query import KEGGExtractor
11
+
12
+ data = KEGGExtractor().build_module_json("M00001")
13
+ print(sorted(data)[:5])
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from .kegg_api import KEGGClient
19
+ from .kegg_extract import KEGGExtractor
20
+ from .kegg_impute import KEGGImputer
21
+ from .kegg_parse import (
22
+ KEGGEquation,
23
+ equation_to_text,
24
+ expand_stoichiometry,
25
+ get_compound_ids_from_equations,
26
+ get_compound_ids_from_text,
27
+ molblock_to_smiles,
28
+ normalize_module_id,
29
+ orient_equation_to_module,
30
+ parse_equation,
31
+ parse_kegg_field_blocks,
32
+ parse_module_reaction_directions,
33
+ parse_side,
34
+ reaction_smiles_from_equation,
35
+ )
36
+ from .to_syncrn import (
37
+ CURRENCY_COMPOUNDS,
38
+ syncrn_from_kegg_equations,
39
+ syncrn_from_kegg_module,
40
+ )
41
+
42
+ __all__ = [
43
+ "KEGGClient",
44
+ "KEGGExtractor",
45
+ "KEGGImputer",
46
+ "KEGGEquation",
47
+ "equation_to_text",
48
+ "expand_stoichiometry",
49
+ "get_compound_ids_from_equations",
50
+ "get_compound_ids_from_text",
51
+ "molblock_to_smiles",
52
+ "normalize_module_id",
53
+ "orient_equation_to_module",
54
+ "parse_equation",
55
+ "parse_kegg_field_blocks",
56
+ "parse_module_reaction_directions",
57
+ "parse_side",
58
+ "reaction_smiles_from_equation",
59
+ "CURRENCY_COMPOUNDS",
60
+ "syncrn_from_kegg_equations",
61
+ "syncrn_from_kegg_module",
62
+ ]
63
+
64
+ from .cache import build_cached_kegg_crn, load_kegg_cache
65
+
66
+ __all__ += ["build_cached_kegg_crn", "load_kegg_cache"]
@@ -0,0 +1,41 @@
1
+ """User-supplied offline KEGG caches, independent of research fixtures."""
2
+
3
+ from __future__ import annotations
4
+ import json
5
+ from pathlib import Path
6
+ from collections.abc import Mapping
7
+ from .to_syncrn import syncrn_from_kegg_equations
8
+
9
+
10
+ def load_kegg_cache(path):
11
+ """Read a KEGG module cache from an explicit path; never fetch data.
12
+
13
+ Expected schema: {"modules": {module_id: {"equations": {...},
14
+ "compound_names": {...}}}}. No manuscript modules or default file are implied.
15
+ """
16
+ data = json.loads(Path(path).read_text(encoding="utf-8"))
17
+ if not isinstance(data, dict) or not isinstance(data.get("modules"), dict):
18
+ raise ValueError("KEGG cache must contain a modules object")
19
+ for module_id, entry in data["modules"].items():
20
+ if not isinstance(entry, dict) or not isinstance(entry.get("equations"), dict):
21
+ raise ValueError(f"{module_id}: expected an equations object")
22
+ if not all(
23
+ isinstance(k, str) and isinstance(v, str)
24
+ for k, v in entry["equations"].items()
25
+ ):
26
+ raise ValueError(f"{module_id}: equations must map ids to equation strings")
27
+ return data
28
+
29
+
30
+ def build_cached_kegg_crn(
31
+ cache, module_id, *, drop_compounds=(), expand_reversible=True
32
+ ):
33
+ """Convert one cached module; retain all participants by default."""
34
+ data = cache if isinstance(cache, Mapping) else load_kegg_cache(cache)
35
+ entry = data["modules"][module_id]
36
+ return syncrn_from_kegg_equations(
37
+ entry["equations"],
38
+ names=entry.get("compound_names"),
39
+ drop_compounds=drop_compounds,
40
+ expand_reversible=expand_reversible,
41
+ )