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,247 @@
1
+ """Exact integer assignments with inherited, repaired primal--dual state."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ import numpy as np
8
+ from scipy.sparse import csr_matrix
9
+ from scipy.sparse.csgraph import connected_components
10
+
11
+ from .assignment_certificate import AssignmentCertificate
12
+ from .assignment_verification import verify_supported_assignment
13
+ from ..pabs.propagation_limits import check_deadline
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class AssignmentState:
18
+ """Certified residual matching; costs and potentials are scaled by four."""
19
+
20
+ rows: tuple[int, ...]
21
+ columns: tuple[int, ...]
22
+ certificate: AssignmentCertificate
23
+ augmentations: int
24
+ inherited_edges: int
25
+
26
+ @property
27
+ def lower_bound(self):
28
+ """Return the exact integer objective of this residual assignment."""
29
+ return self.certificate.scaled_objective
30
+
31
+
32
+ def _initial_state(costs, rows, columns, parent):
33
+ n = len(costs)
34
+ v = np.zeros(n, dtype=np.int64)
35
+ old_matches = {}
36
+ if parent is not None:
37
+ prior = parent.certificate
38
+ old_columns = dict(zip(parent.columns, prior.column_potentials))
39
+ v[:] = [old_columns.get(image, 0) for image in columns]
40
+ old_matches = {
41
+ row: parent.columns[prior.permutation[i]]
42
+ for i, row in enumerate(parent.rows)
43
+ }
44
+ # Repair feasibility after arbitrary residual cost changes. Old potentials
45
+ # are suggestions; each new row minimum restores u[i]+v[j] <= C[i,j].
46
+ u = np.min(costs - v[None, :], axis=1)
47
+ p = np.full(n, -1, dtype=int)
48
+ positions = {image: j for j, image in enumerate(columns)}
49
+ inherited = 0
50
+ for i, row in enumerate(rows):
51
+ j = positions.get(old_matches.get(row))
52
+ if j is not None and p[j] < 0 and costs[i, j] == u[i] + v[j]:
53
+ p[j] = i
54
+ inherited += 1
55
+ return u, v, p, inherited
56
+
57
+
58
+ def _augment(costs, u, v, p, root, deadline=None):
59
+ """Hungarian shortest augmenting path from one unmatched row."""
60
+ n = len(costs)
61
+ infinity = np.int64(2**60)
62
+ slack = np.full(n, infinity, dtype=np.int64)
63
+ predecessor = np.full(n, -1, dtype=int)
64
+ used = np.zeros(n, dtype=bool)
65
+ row, previous = root, -1
66
+ while True:
67
+ check_deadline(deadline)
68
+ reduced = costs[row] - u[row] - v
69
+ improve = ~used & (reduced < slack)
70
+ slack[improve] = reduced[improve]
71
+ predecessor[improve] = previous
72
+ image = int(np.argmin(np.where(used, infinity, slack)))
73
+ delta = int(slack[image])
74
+ u[root] += delta
75
+ if used.any():
76
+ u[p[used]] += delta
77
+ v[used] -= delta
78
+ slack[~used] -= delta
79
+ used[image] = True
80
+ if p[image] < 0:
81
+ break
82
+ row, previous = int(p[image]), image
83
+ while image >= 0:
84
+ previous = int(predecessor[image])
85
+ p[image] = root if previous < 0 else p[previous]
86
+ image = previous
87
+
88
+
89
+ def solve_assignment(costs, allowed, rows, columns, parent=None, *, deadline=None):
90
+ """Solve a nonnegative integer LAP and independently check its certificate.
91
+
92
+ Unsupported edges get a finite penalty above every all-supported matching.
93
+ A returned None means no supported perfect matching exists. The bounded
94
+ matrix and potential range keeps all working integer operations exact.
95
+ """
96
+ check_deadline(deadline)
97
+ original = np.asarray(costs)
98
+ if original.dtype.kind not in "iu":
99
+ raise ValueError("Assignment costs must be exact integers")
100
+ costs = original.astype(np.int64)
101
+ allowed = np.asarray(allowed, dtype=bool)
102
+ n = len(rows)
103
+ if costs.shape != (n, n) or allowed.shape != costs.shape or len(columns) != n:
104
+ raise ValueError("Residual assignment must be square")
105
+ if np.any(costs < 0) or np.max(costs, initial=0) > 2**30 or n > 512:
106
+ raise ValueError("Synister-CP assignment exceeds its exact integer domain")
107
+ if not n:
108
+ return AssignmentState((), (), AssignmentCertificate((), (), (), 0), 0, 0)
109
+ penalty = (n + 1) * int(costs.max(initial=0)) + 1
110
+ matrix = np.where(allowed, costs, penalty)
111
+ u, v, p, inherited = _initial_state(matrix, rows, columns, parent)
112
+ augmentations = 0
113
+ for row in range(n):
114
+ check_deadline(deadline)
115
+ if row not in p:
116
+ _augment(matrix, u, v, p, row, deadline)
117
+ augmentations += 1
118
+ permutation = np.empty(n, dtype=int)
119
+ permutation[p] = np.arange(n)
120
+ if not allowed[np.arange(n), permutation].all():
121
+ return None
122
+ certificate = AssignmentCertificate(
123
+ tuple(map(int, permutation)),
124
+ tuple(map(int, u)),
125
+ tuple(map(int, v)),
126
+ sum(int(matrix[i, j]) for i, j in enumerate(permutation)),
127
+ )
128
+ if not verify_supported_assignment(costs, allowed, certificate):
129
+ raise ArithmeticError(
130
+ "Synister-CP assignment failed independent integer verification"
131
+ )
132
+ return AssignmentState(
133
+ tuple(rows), tuple(columns), certificate, augmentations, inherited
134
+ )
135
+
136
+
137
+ def reduced_cost_filter(costs, allowed, state, budget):
138
+ """Keep every edge whose certified forced-cost lower bound fits the budget."""
139
+ certificate = state.certificate
140
+ reduced = (
141
+ costs
142
+ - np.asarray(certificate.row_potentials)[:, None]
143
+ - np.asarray(certificate.column_potentials)[None, :]
144
+ )
145
+ return allowed & (state.lower_bound + reduced <= budget)
146
+
147
+
148
+ def cycle_edge_lower_bounds(costs, allowed, state, *, deadline=None):
149
+ """Certify forced-edge LAP costs by minimum alternating completion cycles.
150
+
151
+ Relative to the certified matching, reduced-cost arcs are nonnegative.
152
+ Forcing i to the column owned by j needs a path from j back to i. A
153
+ completed all-pairs shortest-path calculation gives the exact forced LAP
154
+ optimum. Interrupted calculations are never used to prune.
155
+ """
156
+ certificate = state.certificate
157
+ permutation = np.asarray(certificate.permutation, dtype=int)
158
+ reduced = (
159
+ costs[:, permutation]
160
+ - np.asarray(certificate.row_potentials)[:, None]
161
+ - np.asarray(certificate.column_potentials)[permutation][None, :]
162
+ )
163
+ domain = allowed[:, permutation]
164
+ if np.any(reduced[domain] < 0):
165
+ raise ArithmeticError(
166
+ "Forced-edge calculation requires a feasible assignment dual"
167
+ )
168
+ # <=512 vertices, |potentials|<=2**50: every simple finite path <2**61.
169
+ infinity = np.int64(2**61)
170
+ arcs = np.where(domain, reduced, infinity)
171
+ _, component = connected_components(
172
+ csr_matrix(domain), directed=True, connection="strong"
173
+ )
174
+ distances = np.full_like(arcs, infinity)
175
+ for label in np.unique(component):
176
+ vertices = np.flatnonzero(component == label)
177
+ local = arcs[np.ix_(vertices, vertices)].copy()
178
+ for pivot in range(len(vertices)):
179
+ check_deadline(deadline)
180
+ local = np.minimum(
181
+ local, local[:, pivot, None] + local[pivot, None, :]
182
+ )
183
+ distances[np.ix_(vertices, vertices)] = local
184
+ result = np.empty_like(costs)
185
+ result[:, permutation] = state.lower_bound + arcs + distances.T
186
+ return result
187
+
188
+
189
+ def solve_partitioned_assignment(
190
+ costs,
191
+ allowed,
192
+ rows,
193
+ columns,
194
+ row_labels,
195
+ column_labels,
196
+ parent=None,
197
+ *,
198
+ deadline=None,
199
+ ):
200
+ """Solve independent atom-type blocks and verify their combined certificate."""
201
+ groups = {}
202
+ for i, label in enumerate(row_labels):
203
+ groups.setdefault(label, ([], []))[0].append(i)
204
+ for j, label in enumerate(column_labels):
205
+ groups.setdefault(label, ([], []))[1].append(j)
206
+ if len(groups) <= 1:
207
+ return solve_assignment(
208
+ costs, allowed, rows, columns, parent, deadline=deadline
209
+ )
210
+ n = len(rows)
211
+ permutation, u, v = [0] * n, [0] * n, [0] * n
212
+ augmentations = inherited = 0
213
+ for left, right in groups.values():
214
+ check_deadline(deadline)
215
+ if len(left) != len(right):
216
+ return None
217
+ state = solve_assignment(
218
+ costs[np.ix_(left, right)],
219
+ allowed[np.ix_(left, right)],
220
+ tuple(rows[i] for i in left),
221
+ tuple(columns[j] for j in right),
222
+ parent,
223
+ deadline=deadline,
224
+ )
225
+ if state is None:
226
+ return None
227
+ certificate = state.certificate
228
+ for i, position in enumerate(left):
229
+ permutation[position] = right[certificate.permutation[i]]
230
+ u[position] = certificate.row_potentials[i]
231
+ for j, position in enumerate(right):
232
+ v[position] = certificate.column_potentials[j]
233
+ augmentations += state.augmentations
234
+ inherited += state.inherited_edges
235
+ certificate = AssignmentCertificate(
236
+ tuple(permutation),
237
+ tuple(u),
238
+ tuple(v),
239
+ sum(int(costs[i, j]) for i, j in enumerate(permutation)),
240
+ )
241
+ if not verify_supported_assignment(costs, allowed, certificate):
242
+ raise ArithmeticError(
243
+ "Combined assignment blocks failed independent verification"
244
+ )
245
+ return AssignmentState(
246
+ tuple(rows), tuple(columns), certificate, augmentations, inherited
247
+ )
@@ -0,0 +1,128 @@
1
+ """
2
+ Optimality certificates and gap reporting.
3
+
4
+ A :class:`Certificate` pairs the cost of a concrete mapping (an *upper bound* on
5
+ the optimal chemical distance) with an admissible *lower bound*, and reports the
6
+ gap between them. When the gap is zero the mapping is *proven optimal*:
7
+
8
+ * ``method="dual-lap"`` -- the lower bound is the Gilmore-Lawler / dual-LAP
9
+ relaxation (:func:`mapper.slap.lap.dual_lap_lower_bound`). A zero gap means the
10
+ cheap relaxation already certifies optimality; a positive gap is honest about
11
+ the relaxation not being tight, *not* about the mapping being suboptimal.
12
+ * ``method="milp-exact"`` -- the lower bound equals the optimum returned by the
13
+ exact MILP/QAP solver (:mod:`mapper.exact.milp`), which CBC proves optimal, so
14
+ the gap is zero by construction.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from dataclasses import dataclass
20
+
21
+ from ..slap.lap import dual_lap_lower_bound, chemical_distance, recover_mapping
22
+
23
+ # Costs are integer/half-integer in cd units; this tolerance absorbs float noise.
24
+ _TOL = 1e-6
25
+
26
+
27
+ @dataclass
28
+ class Certificate:
29
+ """Optimality certificate for a single mapping.
30
+
31
+ :ivar upper_bound: Cost of the concrete mapping (chemical distance, cd units).
32
+ :vartype upper_bound: float
33
+ :ivar lower_bound: Admissible lower bound on the optimal chemical distance.
34
+ :vartype lower_bound: float
35
+ :ivar method: How ``lower_bound`` was obtained (``"dual-lap"`` or ``"milp-exact"``).
36
+ :vartype method: str
37
+ """
38
+
39
+ upper_bound: float
40
+ lower_bound: float
41
+ method: str = "dual-lap"
42
+
43
+ @property
44
+ def gap(self) -> float:
45
+ """Optimality gap ``upper_bound - lower_bound`` (>= 0)."""
46
+ return self.upper_bound - self.lower_bound
47
+
48
+ @property
49
+ def proven_optimal(self) -> bool:
50
+ """True iff the lower bound certifies the mapping is optimal."""
51
+ import math
52
+
53
+ return math.isfinite(self.lower_bound) and self.gap <= _TOL
54
+
55
+ def __str__(self) -> str:
56
+ status = "PROVEN OPTIMAL" if self.proven_optimal else "not certified"
57
+ return (
58
+ f"Certificate(cost={self.upper_bound:g}, "
59
+ f"lower_bound={self.lower_bound:g}, gap={self.gap:g}, "
60
+ f"method={self.method!r}) -> {status}"
61
+ )
62
+
63
+
64
+ def certify_result(result, binary, method="dual-lap"):
65
+ """Build and attach a :class:`Certificate` to a single result dict.
66
+
67
+ Uses the result's ``"cd"`` as the incumbent upper bound (falling back to a
68
+ recomputed chemical distance) and the dual-LAP lower bound. The certificate
69
+ is stored under ``result["certificate"]`` and returned.
70
+
71
+ :param result: A result entry with ``"lgp"`` and (optionally) ``"cd"``.
72
+ :type result: dict
73
+ :param binary: Whether bond orders are binarised (matches the matcher's ``binary``).
74
+ :type binary: bool
75
+ :param method: Lower-bound provenance label.
76
+ :type method: str, optional
77
+
78
+ :rtype: Certificate
79
+ """
80
+ lgp = result["lgp"]
81
+ if "cd" in result:
82
+ ub = float(result["cd"])
83
+ else:
84
+ ub = chemical_distance(lgp, recover_mapping(lgp), binary)
85
+ lb = dual_lap_lower_bound(lgp, binary)
86
+ cert = Certificate(upper_bound=ub, lower_bound=lb, method=method)
87
+ result["certificate"] = cert
88
+ return cert
89
+
90
+
91
+ def certify_results_exact(results, binary):
92
+ """Attach exact (MILP/QAP) certificates to a set of optimal results.
93
+
94
+ The uncertainty-region kernel is extracted from the results and solved to
95
+ proven optimality with the MILP/QAP solver. The proven kernel optimum becomes
96
+ the lower bound for every result, so results whose cost equals it are
97
+ certified optimal over the uncertainty region (``method="milp-exact"``).
98
+
99
+ Falls back to the dual-LAP certificate when PuLP is unavailable or the kernel
100
+ is degenerate.
101
+
102
+ :param results: Optimal results sharing a common reaction (each with ``"lgp"``/``"cd"``).
103
+ :type results: list[dict]
104
+ :param binary: Whether bond orders are binarised.
105
+ :type binary: bool
106
+ """
107
+ if not results:
108
+ return
109
+
110
+ from .kernel_solvers.kernel import extract_kernel
111
+ from .kernel_solvers.milp import solve_kernel_milp, HAS_PULP
112
+
113
+ if not HAS_PULP:
114
+ for r in results:
115
+ certify_result(r, binary)
116
+ return
117
+
118
+ lgp = results[0]["lgp"]
119
+ kernel = extract_kernel(results, lgp, binary=binary)
120
+ sol = solve_kernel_milp(kernel)
121
+ lb = sol.cost
122
+ method = "milp-exact" if sol.proven_optimal else "milp"
123
+ for r in results:
124
+ if "cd" in r:
125
+ ub = float(r["cd"])
126
+ else:
127
+ ub = chemical_distance(r["lgp"], recover_mapping(r["lgp"]), binary)
128
+ r["certificate"] = Certificate(upper_bound=ub, lower_bound=lb, method=method)
@@ -0,0 +1,183 @@
1
+ """Reference-ITS component reduction for staged exact AAM enumeration.
2
+
3
+ The reduction is intentionally explicit about scope. Given a *known* mapped
4
+ reaction (or any trusted seed mapping), it keeps every connected component of
5
+ the union ITS that contains a changed heavy-atom bond, H-count change, or charge
6
+ change. Completely unchanged disconnected components are fixed to the seed
7
+ mapping and can subsequently be represented by endpoint automorphism orbits.
8
+
9
+ This is exact for the seed-conditioned active-component space and is useful for
10
+ reference-AAM reproduction. It is not an unrestricted proof over mappings that
11
+ exchange atoms between active and inactive components; callers must not label it
12
+ as the complete atom-compatible CD shell.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from dataclasses import dataclass
18
+ import math
19
+
20
+ import numpy as np
21
+
22
+ from ...graph.labeled_graph import LabeledGraph
23
+ from ..slap.lap import _adjacency_and_elements
24
+
25
+
26
+ def _node_property(lg, name, default=0):
27
+ values = lg.props.get(name)
28
+ if values is None:
29
+ return [default] * len(lg.labels)
30
+ if len(values) != len(lg.labels):
31
+ raise ValueError(f"{name} must contain one value per graph atom")
32
+ return list(values)
33
+
34
+
35
+ def _induced_labeled_graph(lg, nodes):
36
+ nodes = tuple(nodes)
37
+ position = {node: index for index, node in enumerate(nodes)}
38
+ graph = {index: {} for index in range(len(nodes))}
39
+ for source in nodes:
40
+ for target, weight in lg.graph.get(source, {}).items():
41
+ if target in position:
42
+ graph[position[source]][position[target]] = weight
43
+ reduced = LabeledGraph(graph, [lg.labels[node] for node in nodes])
44
+ for name in ("atomic numbers", "hcounts", "charges"):
45
+ values = lg.props.get(name)
46
+ if values is not None:
47
+ reduced.set_prop(name, [values[node] for node in nodes])
48
+ return reduced
49
+
50
+
51
+ def _union_components(reactant, mapped_product):
52
+ size = reactant.shape[0]
53
+ neighbours = [set() for _ in range(size)]
54
+ for left in range(size):
55
+ for right in range(left + 1, size):
56
+ if reactant[left, right] != 0 or mapped_product[left, right] != 0:
57
+ neighbours[left].add(right)
58
+ neighbours[right].add(left)
59
+ components = []
60
+ unseen = set(range(size))
61
+ while unseen:
62
+ root = min(unseen)
63
+ component = set()
64
+ pending = [root]
65
+ while pending:
66
+ node = pending.pop()
67
+ if node in component:
68
+ continue
69
+ component.add(node)
70
+ pending.extend(neighbours[node] - component)
71
+ unseen.difference_update(component)
72
+ components.append(frozenset(component))
73
+ return tuple(components)
74
+
75
+
76
+ @dataclass(frozen=True)
77
+ class ITSComponentReduction:
78
+ """A seed-conditioned active ITS problem and its exact lifting map."""
79
+
80
+ lgp: tuple[LabeledGraph, LabeledGraph]
81
+ reference_mapping: tuple[int, ...]
82
+ reactant_atoms: tuple[int, ...]
83
+ product_atoms: tuple[int, ...]
84
+ inactive_atoms: tuple[int, ...]
85
+ fixed_mapping: tuple[int, ...]
86
+ changed_atoms: tuple[int, ...]
87
+ heavy_distance: float
88
+ hydrogen_distance: int
89
+ scope: str = "reference_active_its_component_space"
90
+
91
+ def lift(self, core_mapping) -> list[int]:
92
+ """Lift one reduced mapping while retaining the seed outside the ITS core."""
93
+ core_mapping = tuple(int(image) for image in core_mapping)
94
+ size = len(self.reactant_atoms)
95
+ if sorted(core_mapping) != list(range(size)):
96
+ raise ValueError("core_mapping must be a complete reduced permutation")
97
+ lifted = list(self.fixed_mapping)
98
+ for position, reactant_atom in enumerate(self.reactant_atoms):
99
+ lifted[reactant_atom] = self.product_atoms[core_mapping[position]]
100
+ return lifted
101
+
102
+
103
+ def reduce_to_reference_its_components(
104
+ lgp,
105
+ reference_mapping,
106
+ *,
107
+ binary=False,
108
+ tolerance=1e-9,
109
+ ) -> ITSComponentReduction:
110
+ """Keep union-ITS components changed by a trusted reference mapping.
111
+
112
+ Hydrogens remain implicit. Per-heavy-atom H counts are carried in the
113
+ reduced graph metadata and H-count changes participate in reaction-center
114
+ selection. ``hydrogen_distance`` is the L1 H-count discrepancy induced by
115
+ the seed heavy-atom mapping; it is the minimum explicit H--parent bond-edit
116
+ contribution when the two hydrogen inventories are balanced.
117
+ """
118
+ reactant, reactant_elements = _adjacency_and_elements(lgp[0], binary)
119
+ product, product_elements = _adjacency_and_elements(lgp[1], binary)
120
+ if reactant.shape != product.shape:
121
+ raise ValueError("reactant and product must contain the same atom count")
122
+ size = reactant.shape[0]
123
+ mapping = tuple(int(image) for image in reference_mapping)
124
+ if sorted(mapping) != list(range(size)):
125
+ raise ValueError("reference_mapping must be a complete permutation")
126
+ if any(
127
+ reactant_elements[atom] != product_elements[image]
128
+ for atom, image in enumerate(mapping)
129
+ ):
130
+ raise ValueError("reference_mapping must preserve atom types")
131
+
132
+ images = np.asarray(mapping, dtype=int)
133
+ mapped_product = product[images[:, None], images[None, :]]
134
+ changed = set()
135
+ for left in range(size):
136
+ for right in range(left + 1, size):
137
+ if not math.isclose(
138
+ float(reactant[left, right]),
139
+ float(mapped_product[left, right]),
140
+ abs_tol=tolerance,
141
+ rel_tol=0.0,
142
+ ):
143
+ changed.update((left, right))
144
+
145
+ h_r = _node_property(lgp[0], "hcounts")
146
+ h_p = _node_property(lgp[1], "hcounts")
147
+ charge_r = _node_property(lgp[0], "charges")
148
+ charge_p = _node_property(lgp[1], "charges")
149
+ hydrogen_distance = 0
150
+ for atom, image in enumerate(mapping):
151
+ h_delta = abs(int(h_r[atom]) - int(h_p[image]))
152
+ hydrogen_distance += h_delta
153
+ if h_delta or charge_r[atom] != charge_p[image]:
154
+ changed.add(atom)
155
+
156
+ components = _union_components(reactant, mapped_product)
157
+ active = (
158
+ set().union(*(component for component in components if component & changed))
159
+ if changed
160
+ else set()
161
+ )
162
+ reactant_atoms = tuple(sorted(active))
163
+ product_atoms = tuple(mapping[atom] for atom in reactant_atoms)
164
+ inactive_atoms = tuple(atom for atom in range(size) if atom not in active)
165
+ reduced_pair = (
166
+ _induced_labeled_graph(lgp[0], reactant_atoms),
167
+ _induced_labeled_graph(lgp[1], product_atoms),
168
+ )
169
+ heavy_distance = 0.5 * float(np.abs(reactant - mapped_product).sum())
170
+ return ITSComponentReduction(
171
+ lgp=reduced_pair,
172
+ reference_mapping=tuple(range(len(reactant_atoms))),
173
+ reactant_atoms=reactant_atoms,
174
+ product_atoms=product_atoms,
175
+ inactive_atoms=inactive_atoms,
176
+ fixed_mapping=mapping,
177
+ changed_atoms=tuple(sorted(changed)),
178
+ heavy_distance=heavy_distance,
179
+ hydrogen_distance=hydrogen_distance,
180
+ )
181
+
182
+
183
+ __all__ = ["ITSComponentReduction", "reduce_to_reference_its_components"]
@@ -0,0 +1 @@
1
+ """Full-space distance enumeration, replay certificates, and small-graph exhaustive search."""