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,553 @@
1
+ #include "synkit_mapper/symmetry/classification.h"
2
+ #include "synkit_mapper/core/runtime.h"
3
+
4
+ #include <algorithm>
5
+ #include <array>
6
+ #include <chrono>
7
+ #include <cmath>
8
+ #include <cstring>
9
+ #include <iomanip>
10
+ #include <limits>
11
+ #include <map>
12
+ #include <numeric>
13
+ #include <set>
14
+ #include <sstream>
15
+ #include <stdexcept>
16
+ #include <string>
17
+ #include <vector>
18
+
19
+ namespace {
20
+ using Clock = std::chrono::steady_clock;
21
+ using Perm = std::vector<int32_t>;
22
+ using Partition = std::vector<Perm>;
23
+ thread_local std::string error;
24
+
25
+ // FIPS 180-4 SHA256; only a compact index, never used for class equality.
26
+ std::string sha256(const std::string &message) {
27
+ static constexpr uint32_t k[64] = {
28
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
29
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
30
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
31
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
32
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
33
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
34
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
35
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};
36
+ auto rotate = [](uint32_t x, int n) { return (x >> n) | (x << (32 - n)); };
37
+ std::vector<unsigned char> data(message.begin(), message.end());
38
+ uint64_t bits = static_cast<uint64_t>(data.size()) * 8;
39
+ data.push_back(0x80);
40
+ while (data.size() % 64 != 56) data.push_back(0);
41
+ for (int i=7;i>=0;--i) data.push_back(static_cast<unsigned char>(bits >> (8*i)));
42
+ std::array<uint32_t,8> h = {0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
43
+ 0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19};
44
+ for (size_t offset=0;offset<data.size();offset+=64) {
45
+ uint32_t w[64];
46
+ for (int i=0;i<16;++i) {
47
+ w[i]=0;
48
+ for (int j=0;j<4;++j) w[i]=(w[i]<<8)|data[offset+4*i+j];
49
+ }
50
+ for (int i=16;i<64;++i) {
51
+ uint32_t x=w[i-15],y=w[i-2];
52
+ w[i]=w[i-16]+(rotate(x,7)^rotate(x,18)^(x>>3))+w[i-7]+(rotate(y,17)^rotate(y,19)^(y>>10));
53
+ }
54
+ auto v=h;
55
+ for (int i=0;i<64;++i) {
56
+ uint32_t t1=v[7]+(rotate(v[4],6)^rotate(v[4],11)^rotate(v[4],25))+
57
+ ((v[4]&v[5])^(~v[4]&v[6]))+k[i]+w[i];
58
+ uint32_t t2=(rotate(v[0],2)^rotate(v[0],13)^rotate(v[0],22))+
59
+ ((v[0]&v[1])^(v[0]&v[2])^(v[1]&v[2]));
60
+ for (int j=7;j>0;--j) v[j]=v[j-1];
61
+ v[4]+=t1;v[0]=t1+t2;
62
+ }
63
+ for (int i=0;i<8;++i) h[i]+=v[i];
64
+ }
65
+ std::ostringstream out;
66
+ out<<std::hex<<std::setfill('0');
67
+ for (uint32_t x:h) out<<std::setw(8)<<x;
68
+ return out.str();
69
+ }
70
+
71
+ struct Budget {
72
+ Clock::time_point start=Clock::now();
73
+ double seconds;
74
+ int64_t max_nodes,nodes=0;
75
+ int reason=0;
76
+ void *cancel_token=nullptr;
77
+ bool check(bool visit=false) {
78
+ if(reason) return false;
79
+ if(cancel_token && static_cast<synkit_mapper::Cancellation*>(cancel_token)->requested.load(std::memory_order_relaxed)) reason=5;
80
+ else if(seconds>=0 && std::chrono::duration<double>(Clock::now()-start).count()>=seconds) reason=1;
81
+ else if(visit && max_nodes>=0 && nodes>=max_nodes) reason=2;
82
+ if(reason) return false;
83
+ if(visit) ++nodes;
84
+ return true;
85
+ }
86
+ };
87
+
88
+ // Exact individualization/refinement. Signature, target-cell and leaf order
89
+ // match exact/native's existing canonicalizer. No WL equality shortcuts.
90
+ struct Canonical {
91
+ int n;
92
+ const Perm &colors,&edges;
93
+ Budget &budget;
94
+ Perm best,best_key,twins;
95
+ std::vector<Perm> automorphisms;
96
+ Canonical(int size,const Perm &c,const Perm &e,Budget &b)
97
+ :n(size),colors(c),edges(e),budget(b),twins(size) {
98
+ std::map<Perm,int> rows;
99
+ for(int i=0;i<n;++i) {
100
+ Perm row{colors[i]};
101
+ row.insert(row.end(),edges.begin()+i*n,edges.begin()+(i+1)*n);
102
+ auto inserted=rows.emplace(std::move(row),i);
103
+ twins[i]=inserted.first->second;
104
+ }
105
+ }
106
+ Partition refine(Partition p) {
107
+ while(true) {
108
+ Perm ci(n);
109
+ for(size_t k=0;k<p.size();++k) for(int i:p[k]) ci[i]=static_cast<int>(k);
110
+ Partition next;
111
+ bool split=false;
112
+ for(const auto &cell:p) {
113
+ std::map<Perm,Perm> buckets;
114
+ for(int x:cell) {
115
+ std::map<std::pair<int,int>,int> counts;
116
+ for(int y=0;y<n;++y) if(edges[x*n+y]) ++counts[{ci[y],edges[x*n+y]}];
117
+ Perm signature;
118
+ int last=-1;
119
+ for(const auto &entry:counts) {
120
+ int id=entry.first.first;
121
+ if(id!=last) {
122
+ if(last>=0) signature.push_back(0);
123
+ signature.push_back(-id);last=id;
124
+ }
125
+ signature.push_back(entry.first.second);signature.push_back(entry.second);
126
+ }
127
+ if(last>=0) signature.push_back(0);
128
+ buckets[signature].push_back(x);
129
+ }
130
+ split|=buckets.size()>1;
131
+ for(auto &entry:buckets) next.push_back(std::move(entry.second));
132
+ }
133
+ p=std::move(next);
134
+ if(!split) return p;
135
+ }
136
+ }
137
+ void visit(Partition p) {
138
+ if(!budget.check(true)) return;
139
+ p=refine(std::move(p));
140
+ int target=-1;
141
+ while(true) {
142
+ target=-1;
143
+ for(size_t k=0;k<p.size();++k)
144
+ if(p[k].size()>1 && (target<0 || p[k].size()<p[target].size())) target=static_cast<int>(k);
145
+ if(target<0) break;
146
+ bool equal=true;
147
+ for(int i:p[target]) equal&=twins[i]==twins[p[target][0]];
148
+ if(!equal) break;
149
+ Partition next;
150
+ for(size_t k=0;k<p.size();++k) {
151
+ if(static_cast<int>(k)==target) for(int i:p[k]) next.push_back(Perm{i});
152
+ else next.push_back(p[k]);
153
+ }
154
+ p=std::move(next);
155
+ }
156
+ if(target<0) {
157
+ Perm order,key;
158
+ for(const auto &cell:p) order.push_back(cell[0]);
159
+ for(int x:order) key.push_back(colors[x]);
160
+ for(int i=0;i<n;++i) for(int j=i;j<n;++j) if(edges[order[i]*n+order[j]]) {
161
+ key.push_back(-(i*n+j));key.push_back(edges[order[i]*n+order[j]]);
162
+ }
163
+ if(best.empty() || key<best_key) {best=order;best_key=key;}
164
+ else if(key==best_key) {
165
+ Perm g(n);
166
+ for(int i=0;i<n;++i) g[best[i]]=order[i];
167
+ automorphisms.push_back(std::move(g));
168
+ }
169
+ return;
170
+ }
171
+ Perm ci(n),explored;
172
+ for(size_t k=0;k<p.size();++k) for(int x:p[k]) ci[x]=static_cast<int>(k);
173
+ for(int chosen:p[target]) {
174
+ // Every witness comes from identical exact leaves. Orbit closure uses
175
+ // only witnesses stabilizing this ordered partition, so is safe even
176
+ // when group discovery is incomplete.
177
+ std::set<int> orbit{chosen};
178
+ bool changed=true;
179
+ while(changed) {
180
+ changed=false;
181
+ for(const auto &g:automorphisms) {
182
+ bool stabilizes=true;
183
+ for(int i=0;i<n;++i) if(ci[i]!=ci[g[i]]) {stabilizes=false;break;}
184
+ if(stabilizes) {
185
+ Perm old(orbit.begin(),orbit.end());
186
+ for(int x:old) changed|=orbit.insert(g[x]).second;
187
+ }
188
+ }
189
+ }
190
+ bool seen=false;
191
+ for(int x:explored) if(orbit.count(x)) {seen=true;break;}
192
+ if(seen) continue;
193
+ Partition child=p;
194
+ Perm rest;
195
+ for(int x:p[target]) if(x!=chosen) rest.push_back(x);
196
+ child[target]=Perm{chosen};child.insert(child.begin()+target+1,std::move(rest));
197
+ visit(std::move(child));
198
+ if(budget.reason) return;
199
+ explored.push_back(chosen);
200
+ }
201
+ }
202
+ Perm run() {
203
+ std::map<int,Perm> buckets;
204
+ for(int i=0;i<n;++i) buckets[colors[i]].push_back(i);
205
+ Partition p;
206
+ for(auto &entry:buckets) p.push_back(std::move(entry.second));
207
+ visit(std::move(p));
208
+ return best;
209
+ }
210
+ };
211
+
212
+ void append16(std::string &out,int value) {
213
+ out.push_back(static_cast<char>(value&255));out.push_back(static_cast<char>((value>>8)&255));
214
+ }
215
+ void append32(std::string &out,uint32_t value) {
216
+ for(int i=0;i<4;++i) out.push_back(static_cast<char>((value>>(8*i))&255));
217
+ }
218
+ std::string escape_repr(const std::string &token) {
219
+ std::string out;
220
+ for(char c:token) {if(c=='\\'||c=='\'') out.push_back('\\');out.push_back(c);}
221
+ return out;
222
+ }
223
+ struct Certificate {std::string packed,identifier;};
224
+ // Packed SKC1 bytes remain the exact equality key. Build the legacy dense
225
+ // identifier only after that key has been found to be a new accepted class.
226
+ std::string packed_certificate(const SynkitClassProblem &p,const Perm &colors,const Perm &edges,const Perm &order) {
227
+ std::set<int> used;
228
+ for(int x:order) used.insert(colors[x]);
229
+ for(int i=0;i<p.n;++i) for(int j=i+1;j<p.n;++j) if(edges[i*p.n+j]) used.insert(edges[i*p.n+j]-1);
230
+ Perm local(p.palette_size,-1);
231
+ std::string palette="[";
232
+ int index=0;
233
+ for(int rank:used) {
234
+ if(index) palette+=',';
235
+ palette+=p.palette_json[rank];local[rank]=index++;
236
+ }
237
+ palette+=']';
238
+ std::string packed="SKC1";
239
+ append32(packed,static_cast<uint32_t>(palette.size()));append16(packed,p.n);packed+=palette;
240
+ for(int i=0;i<p.n;++i) append16(packed,local[colors[order[i]]]);
241
+ for(int i=0;i<p.n;++i) for(int j=i;j<p.n;++j) {
242
+ const int edge=edges[order[i]*p.n+order[j]];
243
+ if(edge) {append16(packed,i);append16(packed,j);append16(packed,local[edge-1]);}
244
+ }
245
+ return packed;
246
+ }
247
+ std::string legacy_identifier(const SynkitClassProblem &p,const Perm &colors,const Perm &edges,const Perm &order) {
248
+ std::string dense="'[[\"directed\",0],[\"nodes\",[";
249
+ for(int i=0;i<p.n;++i) {
250
+ const int rank=colors[order[i]];
251
+ if(i) dense+=',';
252
+ dense+=escape_repr(p.palette_json[rank]);
253
+ }
254
+ dense+="]],[\"adjacency\",[";
255
+ bool first=true;
256
+ for(int i=0;i<p.n;++i) for(int j=i;j<p.n;++j) {
257
+ if(!first) dense+=',';
258
+ first=false;
259
+ const int edge=edges[order[i]*p.n+order[j]];
260
+ if(edge) dense+="[\"edge\","+escape_repr(p.palette_json[edge-1])+"]";
261
+ else dense+="[\"absent\"]";
262
+ }
263
+ dense+="]]]'";
264
+ return sha256(p.n ? dense : "('empty_colored_graph',)");
265
+ }
266
+ void validate(const SynkitClassProblem &p) {
267
+ if(p.n<0||p.n>512||p.palette_size<0||p.palette_size>=65536||p.edge_states_r<1||p.edge_states_p<1)
268
+ throw std::invalid_argument("invalid class problem dimensions");
269
+ if(p.n && (!p.node_pair_colors||!p.edges_r||!p.edges_p||!p.edge_pair_colors||!p.palette_json))
270
+ throw std::invalid_argument("null class problem buffer");
271
+ for(int i=0;i<p.palette_size;++i) if(!p.palette_json[i]) throw std::invalid_argument("null palette token");
272
+ for(int i=0;i<p.n;++i) for(int j=0;j<p.n;++j) {
273
+ int at=i*p.n+j;
274
+ if(p.node_pair_colors[at]<0||p.node_pair_colors[at]>=p.palette_size||
275
+ p.edges_r[at]<0||p.edges_r[at]>=p.edge_states_r||p.edges_p[at]<0||p.edges_p[at]>=p.edge_states_p||
276
+ p.edges_r[at]!=p.edges_r[j*p.n+i]||p.edges_p[at]!=p.edges_p[j*p.n+i])
277
+ throw std::invalid_argument("invalid class palette or asymmetric endpoint state");
278
+ }
279
+ int64_t pairs=static_cast<int64_t>(p.edge_states_r)*p.edge_states_p;
280
+ for(int64_t i=0;i<pairs;++i) if(p.edge_pair_colors[i]<0||p.edge_pair_colors[i]>p.palette_size)
281
+ throw std::invalid_argument("invalid edge pair color");
282
+ }
283
+ struct Record {Perm mapping;int64_t cost,count;Certificate key;int64_t published=0;};
284
+ } // namespace
285
+
286
+ extern "C" int synkit_mapper_classification_abi() {return 1;}
287
+ extern "C" int synkit_mapper_classification_max_vertices() {return 512;}
288
+ extern "C" const char *synkit_mapper_classification_error() {return error.c_str();}
289
+ static int classify_batch_impl(
290
+ const SynkitClassProblem *problem,int64_t count,const int32_t *mappings,
291
+ const int64_t *costs2,double seconds,int64_t max_nodes,int64_t max_classes,void *cancel_token,
292
+ SynkitClassCallback callback,void *userdata,SynkitClassStatistics *statistics,
293
+ bool updates,bool packed_identifier) {
294
+ const auto invocation_start=Clock::now();
295
+ try {
296
+ error.clear();
297
+ if(!problem||!statistics||!callback||count<0||(!mappings&&count&&problem->n)||(!costs2&&count)||
298
+ !std::isfinite(seconds)||(seconds<0&&seconds!=-1)||(max_nodes<1&&max_nodes!=-1)||(max_classes<1&&max_classes!=-1))
299
+ throw std::invalid_argument("invalid classification request");
300
+ *statistics={};validate(*problem);
301
+ const auto &p=*problem;
302
+ Budget budget{invocation_start,seconds,max_nodes,0,0,cancel_token};
303
+ budget.check();
304
+ std::map<std::string,size_t> seen;
305
+ // Exact fixed-label states share the same canonical certificate. Bound this
306
+ // invocation-local accelerator; no approximate/WL/hash-only equality is used.
307
+ constexpr size_t labelled_cache_bytes_limit=8*1024*1024;
308
+ constexpr size_t labelled_cache_entries_limit=4096;
309
+ size_t labelled_cache_bytes=0;
310
+ std::map<std::string,size_t> labelled_seen;
311
+ std::vector<Record> records;
312
+ auto publish=[&](Record &record) {
313
+ // Publication shares the original deadline. Node/class caps interrupt
314
+ // construction, but may still leave time to deliver completed evidence.
315
+ auto interrupted=[&]() {
316
+ if(budget.seconds>=0 && std::chrono::duration<double>(Clock::now()-budget.start).count()>=budget.seconds) {
317
+ if(!budget.reason) budget.reason=1;
318
+ return true;
319
+ }
320
+ if(cancel_token && static_cast<synkit_mapper::Cancellation*>(cancel_token)->requested.load(std::memory_order_relaxed)) {
321
+ if(!budget.reason) budget.reason=5;
322
+ return true;
323
+ }
324
+ return false;
325
+ };
326
+ if(interrupted()) return false;
327
+ if(callback(record.mapping.data(),record.cost,record.count,
328
+ reinterpret_cast<const unsigned char*>(record.key.packed.data()),
329
+ static_cast<int64_t>(record.key.packed.size()),record.key.identifier.c_str(),userdata)) {
330
+ if(!budget.reason) budget.reason=4;
331
+ return false;
332
+ }
333
+ record.published=record.count;
334
+ return !interrupted();
335
+ };
336
+ for(int64_t k=0;k<count && budget.check();++k) {
337
+ Perm mapping(p.n),taken(p.n,0),colors(p.n),edges(p.n*p.n,0);
338
+ for(int i=0;i<p.n;++i) {
339
+ int image=mappings[k*p.n+i];
340
+ if(image<0||image>=p.n||taken[image]++) throw std::invalid_argument("mapping is not a bijection");
341
+ mapping[i]=image;colors[i]=p.node_pair_colors[i*p.n+image];
342
+ }
343
+ if(costs2[k]<0) throw std::invalid_argument("negative objective cost");
344
+ for(int i=0;i<p.n;++i) for(int j=i+1;j<p.n;++j)
345
+ edges[i*p.n+j]=edges[j*p.n+i]=p.edge_pair_colors[
346
+ p.edges_r[i*p.n+j]*p.edge_states_p+p.edges_p[mapping[i]*p.n+mapping[j]]];
347
+ std::string labelled;
348
+ labelled.reserve(static_cast<size_t>(p.n)*(p.n+1)*2);
349
+ for(int color:colors) append32(labelled,static_cast<uint32_t>(color));
350
+ for(int i=0;i<p.n;++i) for(int j=i+1;j<p.n;++j)
351
+ append32(labelled,static_cast<uint32_t>(edges[i*p.n+j]));
352
+ auto duplicate=labelled_seen.find(labelled);
353
+ if(duplicate!=labelled_seen.end()) {
354
+ ++records[duplicate->second].count;
355
+ ++statistics->candidates;
356
+ continue;
357
+ }
358
+ Canonical canonical(p.n,colors,edges,budget);
359
+ Perm order=p.n?canonical.run():Perm{};
360
+ if(budget.reason) break;
361
+ auto packed=packed_certificate(p,colors,edges,order);
362
+ auto old=seen.find(packed);
363
+ bool discovered=old==seen.end();
364
+ size_t record_index=discovered?records.size():old->second;
365
+ if(old!=seen.end()) ++records[old->second].count;
366
+ else {
367
+ if(max_classes>=0 && static_cast<int64_t>(records.size())>=max_classes) {budget.reason=3;break;}
368
+ auto identifier=packed_identifier?sha256(packed):legacy_identifier(p,colors,edges,order);
369
+ Certificate key{std::move(packed),std::move(identifier)};
370
+ seen.emplace(key.packed,records.size());records.push_back({std::move(mapping),costs2[k],1,std::move(key)});
371
+ }
372
+ if(labelled_seen.size()<labelled_cache_entries_limit &&
373
+ labelled.size()<=labelled_cache_bytes_limit-labelled_cache_bytes) {
374
+ labelled_cache_bytes+=labelled.size();
375
+ labelled_seen.emplace(std::move(labelled),record_index);
376
+ }
377
+ ++statistics->candidates;
378
+ // The additive update interface publishes first discovery immediately.
379
+ // Legacy batch callbacks still receive exactly one final prefix count.
380
+ if(updates && discovered && !publish(records.back())) break;
381
+ }
382
+ if(budget.reason!=4) for(auto &record:records)
383
+ if((!updates || record.published!=record.count) && !publish(record)) break;
384
+ statistics->classes=static_cast<int64_t>(records.size());statistics->canonical_nodes=budget.nodes;
385
+ statistics->complete=budget.reason==0;statistics->reason=budget.reason;
386
+ statistics->elapsed_seconds=std::chrono::duration<double>(Clock::now()-budget.start).count();
387
+ return 0;
388
+ } catch(const std::exception &exception) {error=exception.what();return -1;}
389
+ catch(...) {error="unknown native classification error";return -1;}
390
+ }
391
+
392
+ extern "C" int synkit_mapper_classify_batch_with_cancel(
393
+ const SynkitClassProblem *problem,int64_t count,const int32_t *mappings,
394
+ const int64_t *costs2,double seconds,int64_t max_nodes,int64_t max_classes,void *cancel_token,
395
+ SynkitClassCallback callback,void *userdata,SynkitClassStatistics *statistics) {
396
+ return classify_batch_impl(problem,count,mappings,costs2,seconds,max_nodes,max_classes,
397
+ cancel_token,callback,userdata,statistics,false,false);
398
+ }
399
+
400
+ extern "C" int synkit_mapper_classify_batch_updates_with_cancel(
401
+ const SynkitClassProblem *problem,int64_t count,const int32_t *mappings,
402
+ const int64_t *costs2,double seconds,int64_t max_nodes,int64_t max_classes,void *cancel_token,
403
+ SynkitClassCallback callback,void *userdata,SynkitClassStatistics *statistics) {
404
+ return classify_batch_impl(problem,count,mappings,costs2,seconds,max_nodes,max_classes,
405
+ cancel_token,callback,userdata,statistics,true,false);
406
+ }
407
+
408
+ extern "C" int synkit_mapper_classify_batch_ex(
409
+ const SynkitClassProblem *problem,int64_t count,const int32_t *mappings,
410
+ const int64_t *costs2,double seconds,int64_t max_nodes,int64_t max_classes,void *cancel_token,
411
+ SynkitClassCallback callback,void *userdata,SynkitClassStatistics *statistics,
412
+ int32_t updates,int32_t packed_identifier) {
413
+ if((updates!=0&&updates!=1)||(packed_identifier!=0&&packed_identifier!=1)) {
414
+ error="classification option flags must be zero or one";return -1;
415
+ }
416
+ return classify_batch_impl(problem,count,mappings,costs2,seconds,max_nodes,max_classes,
417
+ cancel_token,callback,userdata,statistics,updates!=0,packed_identifier!=0);
418
+ }
419
+
420
+ extern "C" int synkit_mapper_classify_batch(
421
+ const SynkitClassProblem *problem,int64_t count,const int32_t *mappings,
422
+ const int64_t *costs2,double seconds,int64_t max_nodes,int64_t max_classes,
423
+ SynkitClassCallback callback,void *userdata,SynkitClassStatistics *statistics) {
424
+ return synkit_mapper_classify_batch_with_cancel(problem,count,mappings,costs2,seconds,
425
+ max_nodes,max_classes,nullptr,callback,userdata,statistics);
426
+ }
427
+
428
+
429
+ // The streaming context shares the same exact canonicalizer, certificate
430
+ // routines, cache units and cumulative-record contract as batch classification.
431
+ // It retains state while raw search is suspended inside its native callback.
432
+ namespace synkit_mapper::detail {
433
+ struct ClassStream {
434
+ const SynkitClassProblem &p;
435
+ ::Budget budget;
436
+ int64_t max_classes,candidates=0;
437
+ SynkitClassCallback callback;
438
+ void *userdata;
439
+ bool packed_identifier;
440
+ double processing_seconds=0;
441
+ std::map<std::string,size_t> seen,labelled_seen;
442
+ size_t labelled_bytes=0;
443
+ std::vector<::Record> records;
444
+ ClassStream(const SynkitClassProblem &problem,double seconds,int64_t nodes,
445
+ int64_t classes,void *cancel,SynkitClassCallback cb,void *data,bool packed):
446
+ p(problem),budget{::Clock::now(),seconds,nodes,0,0,cancel},
447
+ max_classes(classes),callback(cb),userdata(data),packed_identifier(packed) {
448
+ if(!std::isfinite(seconds)||(seconds<0&&seconds!=-1)||
449
+ (nodes<1&&nodes!=-1)||(classes<1&&classes!=-1)||!callback)
450
+ throw std::invalid_argument("invalid streaming classification request");
451
+ ::validate(p);
452
+ processing_seconds=std::chrono::duration<double>(::Clock::now()-budget.start).count();
453
+ }
454
+ bool publish(::Record &record) {
455
+ auto interrupted=[&]() {
456
+ if(budget.seconds>=0&&std::chrono::duration<double>(::Clock::now()-budget.start).count()>=budget.seconds) {
457
+ if(!budget.reason)budget.reason=1;
458
+ return true;
459
+ }
460
+ if(budget.cancel_token&&static_cast<Cancellation*>(budget.cancel_token)->requested.load(std::memory_order_relaxed)) {
461
+ if(!budget.reason)budget.reason=5;
462
+ return true;
463
+ }
464
+ return false;
465
+ };
466
+ if(interrupted())return false;
467
+ if(callback(record.mapping.data(),record.cost,record.count,
468
+ reinterpret_cast<const unsigned char*>(record.key.packed.data()),
469
+ record.key.packed.size(),record.key.identifier.c_str(),userdata)) {
470
+ if(!budget.reason)budget.reason=4;
471
+ return false;
472
+ }
473
+ record.published=record.count;
474
+ return !interrupted();
475
+ }
476
+ int push(const int32_t *input,int64_t cost) {
477
+ auto start=::Clock::now();
478
+ struct Charge {
479
+ ClassStream &self;::Clock::time_point start;
480
+ ~Charge(){self.processing_seconds+=std::chrono::duration<double>(::Clock::now()-start).count();}
481
+ } charge{*this,start};
482
+ if(!budget.check())return budget.reason;
483
+ ::Perm mapping(p.n),taken(p.n,0),colors(p.n),edges(p.n*p.n,0);
484
+ for(int i=0;i<p.n;++i) {
485
+ int image=input[i];
486
+ if(image<0||image>=p.n||taken[image]++)throw std::invalid_argument("mapping is not a bijection");
487
+ mapping[i]=image;colors[i]=p.node_pair_colors[i*p.n+image];
488
+ }
489
+ if(cost<0)throw std::invalid_argument("negative objective cost");
490
+ for(int i=0;i<p.n;++i)for(int j=i+1;j<p.n;++j)
491
+ edges[i*p.n+j]=edges[j*p.n+i]=p.edge_pair_colors[
492
+ p.edges_r[i*p.n+j]*p.edge_states_p+p.edges_p[mapping[i]*p.n+mapping[j]]];
493
+ std::string labelled;labelled.reserve(static_cast<size_t>(p.n)*(p.n+1)*2);
494
+ for(int color:colors)append32(labelled,static_cast<uint32_t>(color));
495
+ for(int i=0;i<p.n;++i)for(int j=i+1;j<p.n;++j)
496
+ append32(labelled,static_cast<uint32_t>(edges[i*p.n+j]));
497
+ auto duplicate=labelled_seen.find(labelled);
498
+ if(duplicate!=labelled_seen.end()) {
499
+ ++records[duplicate->second].count;++candidates;
500
+ return 0;
501
+ }
502
+ ::Canonical canonical(p.n,colors,edges,budget);
503
+ ::Perm order=p.n?canonical.run(): ::Perm{};
504
+ if(budget.reason)return budget.reason;
505
+ auto packed=packed_certificate(p,colors,edges,order);
506
+ auto old=seen.find(packed);
507
+ bool discovered=old==seen.end();
508
+ size_t index=discovered?records.size():old->second;
509
+ if(!discovered)++records[index].count;
510
+ else {
511
+ if(max_classes>=0&&static_cast<int64_t>(records.size())>=max_classes) {
512
+ budget.reason=3;return 3;
513
+ }
514
+ auto identifier=packed_identifier?sha256(packed):legacy_identifier(p,colors,edges,order);
515
+ ::Certificate key{std::move(packed),std::move(identifier)};
516
+ seen.emplace(key.packed,records.size());
517
+ records.push_back({std::move(mapping),cost,1,std::move(key)});
518
+ }
519
+ if(labelled_seen.size()<4096&&labelled.size()<=8*1024*1024-labelled_bytes) {
520
+ labelled_bytes+=labelled.size();labelled_seen.emplace(std::move(labelled),index);
521
+ }
522
+ ++candidates;
523
+ if(discovered&&!publish(records.back()))return budget.reason;
524
+ return 0;
525
+ }
526
+ void finish(SynkitClassStatistics &statistics) {
527
+ auto start=::Clock::now();
528
+ if(budget.reason!=4)for(auto &record:records)
529
+ if(record.published!=record.count&&!publish(record))break;
530
+ budget.check();
531
+ processing_seconds+=std::chrono::duration<double>(::Clock::now()-start).count();
532
+ statistics={};statistics.candidates=candidates;statistics.classes=records.size();
533
+ statistics.canonical_nodes=budget.nodes;statistics.complete=budget.reason==0;
534
+ statistics.reason=budget.reason;statistics.elapsed_seconds=processing_seconds;
535
+ }
536
+ };
537
+ ClassStream *class_stream_create(const SynkitClassProblem &p,double seconds,
538
+ int64_t nodes,int64_t classes,void *cancel,SynkitClassCallback cb,
539
+ void *data,bool packed) {
540
+ ::error.clear();
541
+ try{return new ClassStream(p,seconds,nodes,classes,cancel,cb,data,packed);}
542
+ catch(const std::exception &exception){::error=exception.what();throw;}
543
+ }
544
+ int class_stream_push(ClassStream *context,const int32_t *mapping,int64_t cost) {
545
+ try{return context->push(mapping,cost);}
546
+ catch(const std::exception &exception){::error=exception.what();throw;}
547
+ }
548
+ void class_stream_finish(ClassStream *context,SynkitClassStatistics &statistics) {
549
+ try{context->finish(statistics);}
550
+ catch(const std::exception &exception){::error=exception.what();throw;}
551
+ }
552
+ void class_stream_delete(ClassStream *context) {delete context;}
553
+ }
@@ -0,0 +1,124 @@
1
+ #include "synkit_mapper/symmetry/classification.h"
2
+ #include "synkit_mapper/core/runtime.h"
3
+ #include "classification_stream.h"
4
+ #include <memory>
5
+ #include <exception>
6
+
7
+ namespace {
8
+ struct Candidates {
9
+ int n;
10
+ std::vector<int32_t> mappings;
11
+ std::vector<int64_t> costs;
12
+ std::exception_ptr failure;
13
+ synkit_mapper::detail::ClassStream *stream=nullptr;
14
+ };
15
+ int remember(const int32_t *mapping,int64_t cost,void *data) {
16
+ auto &c=*static_cast<Candidates*>(data);
17
+ try {
18
+ if(c.stream) {
19
+ int reason=synkit_mapper::detail::class_stream_push(c.stream,mapping,cost);
20
+ // A classification node/class cap preserves the independent raw
21
+ // search status and prefix counts. Other stops end both stages.
22
+ return reason==2||reason==3?0:reason!=0;
23
+ }
24
+ c.mappings.insert(c.mappings.end(),mapping,mapping+c.n);c.costs.push_back(cost);return 0;
25
+ } catch(...) {c.failure=std::current_exception();return 1;}
26
+ }
27
+ int solve_classified_impl(
28
+ const SynkitMapperProblem *p,const SynkitMapperRequest *request,
29
+ const uint8_t *allowed,
30
+ const SynkitClassProblem *classes,int64_t max_canonical_nodes,
31
+ SynkitClassCallback callback,void *userdata,SynkitMapperStatistics *statistics,
32
+ SynkitClassStatistics *class_statistics,bool updates,bool packed_identifier) {
33
+ using namespace synkit_mapper;
34
+ if(!p||!request||!classes||!callback||!statistics||!class_statistics||
35
+ p->n!=classes->n||request->classify!=1||request->query==SYNKIT_MINIMUM_PROOF||
36
+ (max_canonical_nodes<1&&max_canonical_nodes!=-1)||
37
+ !std::isfinite(request->seconds)||(request->seconds<0&&request->seconds!=-1)) return -1;
38
+ try {
39
+ initialize(*statistics,*request);*class_statistics={};
40
+ // The cap concerns the selected backend's accounted frontier/table.
41
+ // Intermediate class buffers and process RSS are outside those units.
42
+ Budget budget(*request);
43
+ Request raw=*request;raw.classify=0;raw.max_classes=-1;
44
+ using Stream=detail::ClassStream;
45
+ std::unique_ptr<Stream,void(*)(Stream*)> stream(nullptr,detail::class_stream_delete);
46
+ if(updates)stream.reset(detail::class_stream_create(*classes,
47
+ request->seconds<0?-1:budget.remaining(),max_canonical_nodes,
48
+ request->max_classes,request->cancel_token,callback,userdata,packed_identifier));
49
+ Candidates candidates{p->n,{}, {},nullptr,stream.get()};
50
+ raw.seconds=request->seconds<0?-1:budget.remaining();
51
+ int result=allowed?synkit_mapper_solve_domains(p,&raw,allowed,remember,&candidates,statistics):
52
+ synkit_mapper_solve(p,&raw,remember,&candidates,statistics);
53
+ *class_statistics={};statistics->classification_complete=0;
54
+ if(result||candidates.failure) return -1;
55
+ if(statistics->status==SYNKIT_UNSUPPORTED||statistics->status==SYNKIT_ERROR) return 0;
56
+ double remaining=request->seconds<0?-1:budget.remaining();
57
+ if(stream)detail::class_stream_finish(stream.get(),*class_statistics);
58
+ else result=synkit_mapper_classify_batch_ex(classes,static_cast<int64_t>(candidates.costs.size()),
59
+ candidates.mappings.data(),candidates.costs.data(),remaining,max_canonical_nodes,
60
+ request->max_classes,request->cancel_token,callback,userdata,class_statistics,
61
+ updates?1:0,packed_identifier?1:0);
62
+ statistics->classification_complete=class_statistics->complete;
63
+ statistics->class_count=class_statistics->classes;
64
+ statistics->classification_seconds=class_statistics->elapsed_seconds;
65
+ statistics->elapsed_seconds=budget.seconds();
66
+ if(result) {statistics->status=SYNKIT_ERROR;return -1;}
67
+ if(!class_statistics->complete && (statistics->status==SYNKIT_FINISHED||
68
+ (stream&&statistics->reason==SYNKIT_STOP_CALLBACK))) {
69
+ const int reasons[]={0,SYNKIT_STOP_TIME,SYNKIT_STOP_STATES,SYNKIT_STOP_CLASSES,
70
+ SYNKIT_STOP_CALLBACK,SYNKIT_STOP_CANCELLED};
71
+ statistics->status=SYNKIT_LIMIT;statistics->reason=reasons[class_statistics->reason];
72
+ }
73
+ return 0;
74
+ } catch(...) {return -1;}
75
+ }
76
+ } // namespace
77
+
78
+ extern "C" int synkit_mapper_solve_classified(
79
+ const SynkitMapperProblem *p,const SynkitMapperRequest *request,
80
+ const SynkitClassProblem *classes,int64_t max_canonical_nodes,
81
+ SynkitClassCallback callback,void *userdata,SynkitMapperStatistics *statistics,
82
+ SynkitClassStatistics *class_statistics) {
83
+ return solve_classified_impl(p,request,nullptr,classes,max_canonical_nodes,
84
+ callback,userdata,statistics,class_statistics,false,false);
85
+ }
86
+
87
+ extern "C" int synkit_mapper_solve_domains_classified(
88
+ const SynkitMapperProblem *p,const SynkitMapperRequest *request,const uint8_t *allowed,
89
+ const SynkitClassProblem *classes,int64_t max_canonical_nodes,
90
+ SynkitClassCallback callback,void *userdata,SynkitMapperStatistics *statistics,
91
+ SynkitClassStatistics *class_statistics) {
92
+ if(!allowed) return -1;
93
+ return solve_classified_impl(p,request,allowed,classes,max_canonical_nodes,
94
+ callback,userdata,statistics,class_statistics,false,false);
95
+ }
96
+
97
+ extern "C" int synkit_mapper_solve_classified_updates(
98
+ const SynkitMapperProblem *p,const SynkitMapperRequest *request,
99
+ const SynkitClassProblem *classes,int64_t max_canonical_nodes,
100
+ SynkitClassCallback callback,void *userdata,SynkitMapperStatistics *statistics,
101
+ SynkitClassStatistics *class_statistics) {
102
+ return solve_classified_impl(p,request,nullptr,classes,max_canonical_nodes,
103
+ callback,userdata,statistics,class_statistics,true,false);
104
+ }
105
+
106
+ extern "C" int synkit_mapper_solve_domains_classified_updates(
107
+ const SynkitMapperProblem *p,const SynkitMapperRequest *request,const uint8_t *allowed,
108
+ const SynkitClassProblem *classes,int64_t max_canonical_nodes,
109
+ SynkitClassCallback callback,void *userdata,SynkitMapperStatistics *statistics,
110
+ SynkitClassStatistics *class_statistics) {
111
+ if(!allowed) return -1;
112
+ return solve_classified_impl(p,request,allowed,classes,max_canonical_nodes,
113
+ callback,userdata,statistics,class_statistics,true,false);
114
+ }
115
+
116
+ extern "C" int synkit_mapper_solve_classified_ex(
117
+ const SynkitMapperProblem *p,const SynkitMapperRequest *request,const uint8_t *allowed,
118
+ const SynkitClassProblem *classes,int64_t max_canonical_nodes,
119
+ SynkitClassCallback callback,void *userdata,SynkitMapperStatistics *statistics,
120
+ SynkitClassStatistics *class_statistics,int32_t updates,int32_t packed_identifier) {
121
+ if((updates!=0&&updates!=1)||(packed_identifier!=0&&packed_identifier!=1)) return -1;
122
+ return solve_classified_impl(p,request,allowed,classes,max_canonical_nodes,
123
+ callback,userdata,statistics,class_statistics,updates!=0,packed_identifier!=0);
124
+ }