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,8 @@
1
+ import warnings
2
+
3
+ warnings.warn(
4
+ "⚠️ This module is under active development and may be unstable. "
5
+ "APIs, behaviors, or outputs are subject to change without notice.",
6
+ category=UserWarning,
7
+ stacklevel=2,
8
+ )
@@ -0,0 +1,223 @@
1
+ import re
2
+ import networkx as nx
3
+ from typing import Tuple, List, Dict
4
+
5
+
6
+ class GMLToGraph:
7
+ """Parses a GML-like reaction rule into three NetworkX graphs: reactant (left),
8
+ conserved context (context), and product (right). Preserves atom-map indices
9
+ and original SMARTS labels, and attaches placeholder constraints (both
10
+ table-style and multi-block Rest-style) to node and edge attributes.
11
+
12
+ :param gml_text: The GML-like reaction rule text, containing 'left', 'context', 'right',
13
+ and 'constrainLabelAny' sections.
14
+ :type gml_text: str
15
+
16
+ :ivar graphs: A mapping of section names ('left', 'context', 'right') to the
17
+ corresponding parsed graphs.
18
+ :vartype graphs: Dict[str, nx.Graph]
19
+ :ivar placeholder_constraints: A mapping from placeholder labels (e.g. '_X') to their allowed values,
20
+ extracted from the 'constrainLabelAny' block.
21
+ :vartype placeholder_constraints: Dict[str, List[str]]
22
+ """
23
+
24
+ def __init__(self, gml_text: str):
25
+ """Initialize the parser with the full GML text.
26
+
27
+ :param gml_text: GML-like rule text to be parsed.
28
+ :type gml_text: str
29
+
30
+ :raises ValueError: If the provided gml_text is empty.
31
+ """
32
+ if not gml_text:
33
+ raise ValueError("gml_text must be a non-empty string")
34
+ self.gml_text = gml_text
35
+ self.graphs: Dict[str, nx.Graph] = {
36
+ sec: nx.Graph() for sec in ("left", "context", "right")
37
+ }
38
+ self.placeholder_constraints: Dict[str, List[str]] = {}
39
+
40
+ def _parse_element(self, line: str, sec: str) -> None:
41
+ """Parse a single GML line describing a node or an edge and insert it
42
+ into the specified graph section.
43
+
44
+ :param line: A line starting with 'node' or 'edge', e.g., 'node [ id 1 label "C" ]'.
45
+ :type line: str
46
+ :param sec: The target section in 'left', 'context', or 'right'.
47
+ :type sec: str
48
+
49
+ :raises ValueError: If `sec` is not one of 'left', 'context', or 'right'.
50
+ """
51
+ if sec not in self.graphs:
52
+ raise ValueError(f"Unknown section: {sec}")
53
+ tokens = line.split()
54
+ order_map = {"-": 1, ":": 1.5, "=": 2, "#": 3}
55
+ if tokens[0] == "node":
56
+ # Extract node attributes
57
+ nid = int(tokens[tokens.index("id") + 1])
58
+ raw_label = tokens[tokens.index("label") + 1].strip('"')
59
+ m = re.fullmatch(r"([A-Za-z*_]+?)(\d+)?([+-])?", raw_label)
60
+ if m:
61
+ element = m.group(1)
62
+ charge = int(m.group(2)) if m.group(2) else 1 if m.group(3) else 0
63
+ if m.group(3) == "-":
64
+ charge = -charge
65
+ else:
66
+ element = raw_label
67
+ charge = 0
68
+ attrs = {
69
+ "element": element,
70
+ "charge": charge,
71
+ "atom_map": nid,
72
+ "hcount": 0,
73
+ "label": raw_label,
74
+ }
75
+ self.graphs[sec].add_node(nid, **attrs)
76
+ elif tokens[0] == "edge":
77
+ # Extract edge attributes
78
+ src = int(tokens[tokens.index("source") + 1])
79
+ tgt = int(tokens[tokens.index("target") + 1])
80
+ lbl = tokens[tokens.index("label") + 1].strip('"')
81
+ order = order_map.get(lbl, 0)
82
+ self.graphs[sec].add_edge(src, tgt, order=order, label=lbl)
83
+
84
+ def _synchronize(self) -> None:
85
+ """
86
+ Ensure that every node and edge in the 'context' graph also appears in
87
+ both 'left' and 'right' graphs, carrying over node and edge attributes.
88
+ """
89
+ ctx = self.graphs["context"]
90
+ # Nodes
91
+ for n, data in ctx.nodes(data=True):
92
+ for sec in ("left", "right"):
93
+ if n not in self.graphs[sec]:
94
+ self.graphs[sec].add_node(n, **data)
95
+ else:
96
+ self.graphs[sec].nodes[n].update(data)
97
+ # Edges
98
+ for u, v, data in ctx.edges(data=True):
99
+ for sec in ("left", "right"):
100
+ if not self.graphs[sec].has_edge(u, v):
101
+ self.graphs[sec].add_edge(u, v, **data)
102
+
103
+ def _parse_constraints(self, lines: List[str], idx: int) -> int:
104
+ """Parse placeholder constraints from the 'constrainLabelAny' block,
105
+ supporting both table and multi-block Rest styles.
106
+
107
+ :param lines: All lines of the GML text.
108
+ :type lines: List[str]
109
+ :param idx: The index of the first line inside the '[' of the block.
110
+ :type idx: int
111
+
112
+ :return: The index of the closing ']' line of the block.
113
+ :rtype: int
114
+ """
115
+ while idx < len(lines):
116
+ line = lines[idx].strip()
117
+ if line.startswith("]"):
118
+ return idx
119
+ m = re.match(r'label\s+"[^\(]+\(([^)]+)\)"', line)
120
+ if m:
121
+ placeholders = [p.strip() for p in m.group(1).split(",")]
122
+ # Table style if multiple placeholders
123
+ if len(placeholders) > 1:
124
+ table: List[Tuple[str, ...]] = []
125
+ idx += 1
126
+ # Find rows
127
+ while idx < len(lines) and "labels [" not in lines[idx]:
128
+ idx += 1
129
+ while idx < len(lines):
130
+ row_line = lines[idx].strip()
131
+ matches = re.findall(r'label\s+"[^\(]+\(([^)]+)\)"', row_line)
132
+ for row in matches:
133
+ table.append(tuple(val.strip() for val in row.split(",")))
134
+ if "]" in row_line:
135
+ break
136
+ idx += 1
137
+ for j, ph in enumerate(placeholders):
138
+ self.placeholder_constraints[ph] = [row[j] for row in table]
139
+ idx += 1
140
+ continue
141
+ # Multi-block Rest style
142
+ ph = placeholders[0]
143
+ self.placeholder_constraints[ph] = []
144
+ idx += 1
145
+ while idx < len(lines) and "labels [" not in lines[idx]:
146
+ idx += 1
147
+ if idx < len(lines):
148
+ while idx < len(lines):
149
+ lbl_line = lines[idx].strip()
150
+ matches = re.findall(r'label\s+"[^\(]+\(([^)]+)\)"', lbl_line)
151
+ self.placeholder_constraints[ph].extend(matches)
152
+ if "]" in lbl_line:
153
+ break
154
+ idx += 1
155
+ idx += 1
156
+ continue
157
+ idx += 1
158
+ return idx
159
+
160
+ def _attach_constraints(self) -> None:
161
+ """
162
+ Attach the parsed placeholder constraints to nodes (as 'constraint')
163
+ and edges (as 'bond_constraint') across all graphs, and store the
164
+ raw mapping on the context graph's .graph metadata.
165
+ """
166
+ pc = self.placeholder_constraints
167
+ for graph in self.graphs.values():
168
+ for n, data in graph.nodes(data=True):
169
+ lbl = data.get("label")
170
+ if lbl in pc:
171
+ data["constraint"] = pc[lbl]
172
+ for u, v, data in graph.edges(data=True):
173
+ lbl = data.get("label")
174
+ if lbl in pc:
175
+ data["bond_constraint"] = pc[lbl]
176
+ self.graphs["context"].graph["placeholder_constraints"] = pc
177
+
178
+ def transform(self) -> Tuple[nx.Graph, nx.Graph, nx.Graph]:
179
+ """Parse the GML text, build the left, right, and context graphs, and return them.
180
+
181
+ :return: A tuple (left_graph, right_graph, context_graph), each with attached constraints.
182
+ :rtype: Tuple[nx.Graph, nx.Graph, nx.Graph]
183
+ """
184
+ lines = self.gml_text.splitlines()
185
+ section: str = ""
186
+ i = 0
187
+ while i < len(lines):
188
+ line = lines[i].strip()
189
+ if line.startswith("constrainLabelAny"):
190
+ while i < len(lines) and not lines[i].strip().endswith("["):
191
+ i += 1
192
+ i = self._parse_constraints(lines, i + 1)
193
+ elif any(line.startswith(x) for x in ("left", "right", "context")):
194
+ section = line.split("[")[0].strip()
195
+ elif line.startswith(("node", "edge")) and section:
196
+ self._parse_element(line, section)
197
+ i += 1
198
+ self._synchronize()
199
+ self._attach_constraints()
200
+ return (self.graphs["left"], self.graphs["right"], self.graphs["context"])
201
+
202
+ def __repr__(self) -> str:
203
+ """Return a summary indicating the number of nodes in each graph.
204
+
205
+ :return: A brief representation with node counts.
206
+ :rtype: str
207
+ """
208
+ return (
209
+ f"<GMLToGraph left={self.graphs['left'].number_of_nodes()} nodes, "
210
+ f"right={self.graphs['right'].number_of_nodes()} nodes, "
211
+ f"context={self.graphs['context'].number_of_nodes()} nodes>"
212
+ )
213
+
214
+ def help(self) -> str:
215
+ """Return a usage summary for the GMLToGraph parser.
216
+
217
+ :return: Multi-line help text explaining the API.
218
+ :rtype: str
219
+ """
220
+ return (
221
+ "GMLToGraph(gml_text) -> (left, right, context) graphs\n"
222
+ "Supports Nuc-style and Rest-style constraint parsing."
223
+ )
@@ -0,0 +1,280 @@
1
+ import networkx as nx
2
+ from typing import Dict, List, Tuple, Any, Set
3
+
4
+
5
+ class GraphToGML:
6
+ """Convert two NetworkX graphs into a minimal GML reaction rule string,
7
+ using canonical context detection and SynKit-style constraint annotations.
8
+
9
+ This class identifies the conserved context (nodes/edges unchanged between
10
+ reactant and product graphs), extracts minimal changing portions,
11
+ and generates a GML block including left, context, right, and placeholder constraints.
12
+
13
+ :param left: Graph representing the reactant state.
14
+ :type left: nx.Graph
15
+ :param right: Graph representing the product state.
16
+ :type right: nx.Graph
17
+ :param rule_id: Identifier for the reaction rule (default: "1").
18
+ :type rule_id: str
19
+ :raises ValueError: If input graphs have mismatched mapping nodes.
20
+
21
+ .. rubric:: Examples
22
+
23
+ >>> from networkx import Graph
24
+ >>> G1, G2 = Graph(), Graph()
25
+ >>> # populate G1, G2 with atom_map nodes, constraints, etc.
26
+ >>> g2g = GraphToGML(G1, G2, rule_id="rxn1")
27
+ >>> gml = g2g.to_gml()
28
+ >>> print(gml)
29
+ """
30
+
31
+ def __init__(self, left: nx.Graph, right: nx.Graph, rule_id: str = "1") -> None:
32
+ """Initialize the GraphToGML converter.
33
+
34
+ :param left: Reactant graph with node and edge attributes.
35
+ :type left: nx.Graph
36
+ :param right: Product graph with node and edge attributes.
37
+ :type right: nx.Graph
38
+ :param rule_id: Unique identifier for the rule output.
39
+ :type rule_id: str
40
+ :return: None
41
+ :rtype: None
42
+ :raises ValueError: If graphs have nodes without atom_map attribute.
43
+ """
44
+ self.left: nx.Graph = left
45
+ self.right: nx.Graph = right
46
+ self.rule_id: str = rule_id
47
+
48
+ self.context_nodes: Set[int] = set()
49
+ self.context_edges: Set[Tuple[int, int]] = set()
50
+ self.left_nodes: Set[int] = set()
51
+ self.right_nodes: Set[int] = set()
52
+ self.left_edges: List[Tuple[int, int, Dict[str, Any]]] = []
53
+ self.right_edges: List[Tuple[int, int, Dict[str, Any]]] = []
54
+ self.context: nx.Graph = nx.Graph()
55
+ self.constraint_dict: Dict[str, List[str]] = {}
56
+
57
+ @staticmethod
58
+ def same_node(nl: Dict[str, Any], nr: Dict[str, Any]) -> bool:
59
+ """Compare two node attribute dictionaries, ignoring 'atom_map'.
60
+
61
+ :param nl: Node attribute dict from left graph.
62
+ :type nl: Dict[str, Any]
63
+ :param nr: Node attribute dict from right graph.
64
+ :type nr: Dict[str, Any]
65
+ :return: True if all attributes (except 'atom_map') match.
66
+ :rtype: bool
67
+ """
68
+ keys = set(nl) | set(nr)
69
+ keys.discard("atom_map")
70
+ return all(nl.get(k) == nr.get(k) for k in keys)
71
+
72
+ @staticmethod
73
+ def same_edge(el: Dict[str, Any], er: Dict[str, Any]) -> bool:
74
+ """Compare two edge attribute dictionaries for equality.
75
+
76
+ :param el: Edge attribute dict from left graph.
77
+ :type el: Dict[str, Any]
78
+ :param er: Edge attribute dict from right graph.
79
+ :type er: Dict[str, Any]
80
+ :return: True if all edge attributes match.
81
+ :rtype: bool
82
+ """
83
+ keys = set(el) | set(er)
84
+ return all(el.get(k) == er.get(k) for k in keys)
85
+
86
+ def compute(self) -> None:
87
+ """Compute conserved context and minimal changing nodes/edges,
88
+ then collect placeholder constraints from context graph.
89
+
90
+ :return: None
91
+ :rtype: None
92
+ """
93
+ # Identify conserved context nodes
94
+ self.context_nodes = {
95
+ n
96
+ for n in set(self.left.nodes) & set(self.right.nodes)
97
+ if self.same_node(self.left.nodes[n], self.right.nodes[n])
98
+ }
99
+ # Identify conserved context edges
100
+ self.context_edges = {
101
+ tuple(sorted((u, v)))
102
+ for u, v in set(self.left.edges) & set(self.right.edges)
103
+ if u in self.context_nodes
104
+ and v in self.context_nodes
105
+ and self.same_edge(self.left.edges[u, v], self.right.edges[u, v])
106
+ }
107
+ # Compute minimal changing edges and nodes
108
+ self.left_edges, left_extra = self.get_changing_edges_and_nodes(
109
+ self.left, self.context_edges, self.context_nodes
110
+ )
111
+ self.right_edges, right_extra = self.get_changing_edges_and_nodes(
112
+ self.right, self.context_edges, self.context_nodes
113
+ )
114
+ self.left_nodes = {
115
+ n for n in self.left.nodes if n not in self.context_nodes
116
+ } | left_extra
117
+ self.right_nodes = {
118
+ n for n in self.right.nodes if n not in self.context_nodes
119
+ } | right_extra
120
+ # Build context subgraph
121
+ self.context = nx.Graph()
122
+ for n in sorted(self.context_nodes):
123
+ self.context.add_node(n, **self.left.nodes[n])
124
+ for u, v in self.context_edges:
125
+ self.context.add_edge(u, v, **self.left.edges[u, v])
126
+ # Gather constraints from context
127
+ self.constraint_dict.clear()
128
+ for _, d in self.context.nodes(data=True):
129
+ if "constraint" in d:
130
+ self.constraint_dict[d["label"]] = d["constraint"]
131
+ for _, _, d in self.context.edges(data=True):
132
+ if "bond_constraint" in d:
133
+ self.constraint_dict[d["label"]] = d["bond_constraint"]
134
+
135
+ @staticmethod
136
+ def get_changing_edges_and_nodes(
137
+ G: nx.Graph, context_edges: Set[Tuple[int, int]], context_nodes: Set[int]
138
+ ) -> Tuple[List[Tuple[int, int, Dict[str, Any]]], Set[int]]:
139
+ """Identify edges and nodes in G that are not in the conserved context.
140
+
141
+ :param G: Input graph.
142
+ :type G: nx.Graph
143
+ :param context_edges: Edges part of context.
144
+ :type context_edges: Set[Tuple[int, int]]
145
+ :param context_nodes: Nodes part of context.
146
+ :type context_nodes: Set[int]
147
+ :return: A tuple of (changed_edges, changed_nodes).
148
+ :rtype: Tuple[List[Tuple[int, int, Dict[str, Any]]], Set[int]]
149
+ """
150
+ changed_edges: List[Tuple[int, int, Dict[str, Any]]] = []
151
+ changed_nodes: Set[int] = set()
152
+ for u, v in G.edges():
153
+ key = tuple(sorted((u, v)))
154
+ if key not in context_edges:
155
+ changed_edges.append((u, v, G.edges[u, v]))
156
+ if u not in context_nodes:
157
+ changed_nodes.add(u)
158
+ if v not in context_nodes:
159
+ changed_nodes.add(v)
160
+ return changed_edges, changed_nodes
161
+
162
+ @staticmethod
163
+ def graph_section(
164
+ name: str,
165
+ G: nx.Graph,
166
+ nodes: Set[int],
167
+ edges: List[Tuple[int, int, Dict[str, Any]]],
168
+ ) -> List[str]:
169
+ """Render a GML block for a subgraph section.
170
+
171
+ :param name: Section name ('left', 'context', or 'right').
172
+ :type name: str
173
+ :param G: Graph containing nodes/edges.
174
+ :type G: nx.Graph
175
+ :param nodes: Node IDs to include.
176
+ :type nodes: Set[int]
177
+ :param edges: Edges to include (u,v,attr).
178
+ :type edges: List[Tuple[int,int,Dict[str,Any]]]
179
+ :return: Lines of GML representing the section.
180
+ :rtype: List[str]
181
+ """
182
+ lines: List[str] = [f" {name} ["]
183
+ for n in sorted(nodes):
184
+ d = G.nodes[n]
185
+ lbl = d.get("label", d.get("element", str(n)))
186
+ lines.append(f' node [ id {n} label "{lbl}" ]')
187
+ order_map = {1: "-", 1.5: ":", 2: "=", 3: "#"}
188
+ for u, v, d in sorted(edges):
189
+ lbl = d.get("label", order_map.get(d.get("order", 1), "-"))
190
+ lines.append(f' edge [ source {u} target {v} label "{lbl}" ]')
191
+ lines.append(" ]")
192
+ return lines
193
+
194
+ @staticmethod
195
+ def context_section(G: nx.Graph) -> List[str]:
196
+ """Render the conserved context GML block.
197
+
198
+ :param G: Context graph.
199
+ :type G: nx.Graph
200
+ :return: Lines of GML for context.
201
+ :rtype: List[str]
202
+ """
203
+ lines: List[str] = [" context []"] # placeholder, updated in full block
204
+ lines = [" context ["]
205
+ for n, d in sorted(G.nodes(data=True)):
206
+ lbl = d.get("label", d.get("element", str(n)))
207
+ lines.append(f' node [ id {n} label "{lbl}" ]')
208
+ order_map = {1: "-", 1.5: ":", 2: "=", 3: "#"}
209
+ for u, v, d in sorted(G.edges(data=True)):
210
+ lbl = d.get("label", order_map.get(d.get("order", 1), "-"))
211
+ lines.append(f' edge [ source {u} target {v} label "{lbl}" ]')
212
+ lines.append(" ]")
213
+ return lines
214
+
215
+ def constraints_section(self) -> List[str]:
216
+ """Render placeholder constraints as one constrainLabelAny block.
217
+
218
+ :return: Lines of GML for constraints.
219
+ :rtype: List[str]
220
+ """
221
+ lines: List[str] = []
222
+ if not self.constraint_dict:
223
+ return lines
224
+ lines.append(" constrainLabelAny [")
225
+ for ph, children in self.constraint_dict.items():
226
+ lines.append(f' label "Rest({ph})"')
227
+ if children:
228
+ labels_inner = " ".join(f'label "Rest({c})"' for c in children)
229
+ lines.append(f" labels [{labels_inner}]")
230
+ else:
231
+ lines.append(" labels []")
232
+ lines.append(" ]")
233
+ return lines
234
+
235
+ def to_gml(self) -> str:
236
+ """Generate the full GML reaction rule string.
237
+
238
+ :return: Complete GML string for the reaction rule.
239
+ :rtype: str
240
+ """
241
+ self.compute()
242
+ out: List[str] = ["rule [", f' ruleID "{self.rule_id}"']
243
+ out += self.graph_section("left", self.left, self.left_nodes, self.left_edges)
244
+ out += self.context_section(self.context)
245
+ out += self.graph_section(
246
+ "right", self.right, self.right_nodes, self.right_edges
247
+ )
248
+ out += self.constraints_section()
249
+ out.append("]")
250
+ return "\n".join(out)
251
+
252
+ def __repr__(self) -> str:
253
+ """Return a summary of the rule converter.
254
+
255
+ :return: Brief description with node counts.
256
+ :rtype: str
257
+ """
258
+ return (
259
+ f"<GraphToGML rule_id='{self.rule_id}', "
260
+ f"left_nodes={len(self.left_nodes)}, "
261
+ f"right_nodes={len(self.right_nodes)}, "
262
+ f"context_nodes={len(self.context_nodes)}>"
263
+ )
264
+
265
+ def help(self) -> str:
266
+ """Show usage instructions for GraphToGML.
267
+
268
+ :return: Multi-line help text.
269
+ :rtype: str
270
+ """
271
+ return (
272
+ "GraphToGML(left, right, rule_id='374')\n"
273
+ " - left: nx.Graph for reactant state\n"
274
+ " - right: nx.Graph for product state\n"
275
+ " - rule_id: identifier for the GML rule\n"
276
+ "\n"
277
+ "Usage:\n"
278
+ " g2g = GraphToGML(G_left, G_right, rule_id='374')\n"
279
+ " print(g2g.to_gml())\n"
280
+ )