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,531 @@
1
+ """
2
+ canonicalize_graph.py
3
+ =====================
4
+
5
+ A **pure‑Python / pure‑NetworkX** library that assigns *canonical*,
6
+ deterministic identifiers to graphs **without any external toolchain**.
7
+ It can be dropped into cheminformatics, bio‑networks, knowledge graphs,
8
+ or any workflow that needs stable de‑duplication of isomorphic graphs.
9
+
10
+ Why canonicalise?
11
+ -----------------
12
+ * **De‑duplication** – hash the canonical form, then compare hashes
13
+ instead of running an expensive isomorphism test for every pair.
14
+ * **Index keys** – store the 32‑hex digest in a database and use it as a
15
+ primary key for sub‑structure search or provenance tracking.
16
+ * **Version control‑friendly** – serialise nodes/edges in a predictable,
17
+ line‑ordered way so diffs stay minimal.
18
+
19
+ Two back‑ends
20
+ ~~~~~~~~~~~~~
21
+ ``backend="generic"`` (default)
22
+ *Sort‑and‑hash* strategy identical to earlier releases. Fastest on
23
+ graphs where node/edge attributes already break most automorphisms.
24
+ ``backend="wl"``
25
+ Weisfeiler–Lehman colour‑refinement adds **structure awareness**
26
+ without leaving pure Python. Slightly slower but collapses many more
27
+ isomorphic graphs to the same label.
28
+
29
+ Quick start
30
+ -----------
31
+ >>> import networkx as nx
32
+ >>> from canonicalize_graph import GraphCanonicaliser
33
+ >>>
34
+ >>> G = nx.Graph()
35
+ >>> G.add_node(1, element="C"); G.add_node(2, element="O")
36
+ >>> G.add_edge(1, 2, order=1)
37
+ >>>
38
+ >>> cg = GraphCanonicaliser(backend="wl").canonicalise_graph(G)
39
+ >>> cg.canonical_hash
40
+ '0df9e34a7c3cd9b35c0ba5f5cbe7598e'
41
+ >>> cg.canonical_graph.nodes(data=True)
42
+ [(1, {'element': 'C'}), (2, {'element': 'O'})]
43
+ """
44
+
45
+ from __future__ import annotations
46
+
47
+ import hashlib
48
+ import inspect
49
+ from typing import (
50
+ Any,
51
+ Callable,
52
+ Dict,
53
+ Hashable,
54
+ Iterable,
55
+ List,
56
+ Literal,
57
+ Tuple,
58
+ )
59
+
60
+ from synkit.IO.chem_converter import gml_to_its, its_to_gml
61
+ import networkx as nx
62
+ from networkx.algorithms.graph_hashing import (
63
+ weisfeiler_lehman_subgraph_hashes as _wl_hashes,
64
+ )
65
+ from .canon_algs import canon_morgan
66
+ from .nauty import NautyCanonicalizer
67
+
68
+ __all__: list[str] = ["CanonicalGraph", "GraphCanonicaliser", "CanonicalRule"]
69
+
70
+ ###############################################################################
71
+ # Type aliases & helpers ######################################################
72
+ ###############################################################################
73
+
74
+ NodeId = Hashable # a node label accepted by NetworkX
75
+ NodeData = Dict[str, Any]
76
+ EdgeData = Dict[str, Any]
77
+ Digest = str
78
+
79
+ T_NodeSortKey = Callable[[NodeId, NodeData], Tuple[Any, ...]]
80
+ T_EdgeSortKey = Callable[[NodeId, NodeId, EdgeData], Tuple[Any, ...]]
81
+
82
+
83
+ def _default_node_key(node_id: NodeId, data: NodeData) -> Tuple[Any, ...]:
84
+ """Fallback sort‑key if the user supplies none."""
85
+ return (
86
+ data.get("element", ""),
87
+ data.get("charge", 0),
88
+ data.get("lone_pairs", 0),
89
+ data.get("radical", 0),
90
+ data.get("aromatic", False),
91
+ # data.get("atom_map", 0),
92
+ data.get("hcount", 0),
93
+ # data.get("neighbors", []),
94
+ # tuple(data.get("typesGH", ())),
95
+ # node_id, # final tie‑breaker
96
+ )
97
+
98
+
99
+ def _default_edge_key(u: NodeId, v: NodeId, data: EdgeData) -> Tuple[Any, ...]:
100
+ """Fallback edge sort‑key (makes undirected edges order‑invariant)."""
101
+ return (tuple(sorted((u, v))), data.get("order", 0), data.get("standard_order", 0))
102
+
103
+
104
+ def _digest(text: str) -> Digest:
105
+ """First 32 hex chars of SHA‑256 – short *but* collision‑safe for up to
106
+ 2¹²⁸ graphs."""
107
+ return hashlib.sha256(text.encode()).hexdigest()[:32]
108
+
109
+
110
+ ###############################################################################
111
+ # Public API ##################################################################
112
+ ###############################################################################
113
+
114
+
115
+ class GraphCanonicaliser:
116
+ """Factory that turns arbitrary ``networkx.Graph`` objects into their
117
+ *canonical* twin plus a **stable 32‑hex digest**.
118
+
119
+ :param backend: ``"generic"`` or ``"wl"`` (structure‑aware Weisfeiler–Lehman).
120
+ :param wl_iterations: Depth of WL refinement (ignored for ``generic``). Three iterations
121
+ distinguish nearly all real‑world chemical graphs; increase for
122
+ very large or highly regular topologies.
123
+ :param node_sort_key: Custom deterministic orderings. They *must* treat their arguments
124
+ as *read‑only* and return plain tuples for total ordering.
125
+ :param edge_sort_key: Custom deterministic orderings. They *must* treat their arguments
126
+ as *read‑only* and return plain tuples for total ordering.
127
+
128
+ .. rubric:: Notes
129
+
130
+ *All* returned graphs are of the *same class* as the input
131
+ (``nx.Graph``, ``nx.DiGraph`` …), so multigraphs and digraphs are
132
+ preserved.
133
+
134
+ .. rubric:: Examples
135
+
136
+ >>> canon = GraphCanonicaliser(backend="generic")
137
+ >>> sig = canon.canonical_signature(G)
138
+ >>> cg = canon.canonicalise_graph(G)
139
+ >>> cg.canonical_graph # a relabelled copy, nodes 1…N
140
+ """
141
+
142
+ # ------------------------------------------------------------------ #
143
+ # Construction #
144
+ # ------------------------------------------------------------------ #
145
+ def __init__(
146
+ self,
147
+ *,
148
+ backend: Literal["generic", "wl", "morgan", "nauty"] = "generic",
149
+ wl_iterations: int = 3,
150
+ morgan_radius: int = 3,
151
+ node_attrs: List[str] = [
152
+ "element",
153
+ "aromatic",
154
+ "charge",
155
+ "lone_pairs",
156
+ "radical",
157
+ "hcount",
158
+ ],
159
+ node_sort_key: T_NodeSortKey = _default_node_key,
160
+ edge_sort_key: T_EdgeSortKey = _default_edge_key,
161
+ ) -> None:
162
+ if backend not in {"generic", "wl", "morgan", "nauty"}:
163
+ raise ValueError("backend must be 'generic' or 'wl' or 'morgan' ")
164
+ self.backend: Literal["generic", "wl", "morgan"] = backend
165
+ self._wl_k: int = wl_iterations
166
+ self._mg_k: int = morgan_radius
167
+ self._node_key: T_NodeSortKey = node_sort_key
168
+ self._edge_key: T_EdgeSortKey = edge_sort_key
169
+ self._wl_node_attrs: Tuple[str, ...] = tuple(node_attrs)
170
+ self._mg_node_attrs: List[str] = node_attrs
171
+ if self.backend == "nauty":
172
+ self.nauty = NautyCanonicalizer(node_attrs=node_attrs, edge_attrs=["order"])
173
+
174
+ # ------------------------------------------------------------------ #
175
+ # High‑level helpers #
176
+ # ------------------------------------------------------------------ #
177
+ def canonicalise_graph(self, graph: nx.Graph) -> "CanonicalGraph":
178
+ """Return a :class:`CanonicalGraph` wrapper around *graph*.
179
+
180
+ The wrapper exposes:
181
+
182
+ * :attr:`~CanonicalGraph.canonical_graph` – relabelled 1…N
183
+ * :attr:`~CanonicalGraph.canonical_hash` – 32‑char digest
184
+ """
185
+ return CanonicalGraph(graph, self)
186
+
187
+ def canonicalise_graphs(
188
+ self,
189
+ graphs: Iterable[nx.Graph],
190
+ ) -> Tuple["CanonicalGraph", ...]:
191
+ """Bulk helper that returns *all* wrappers **sorted by hash**.
192
+
193
+ Useful when you want fast set comparison but need the canonical
194
+ graphs as well:
195
+
196
+ >>> wrappers = canon.canonicalise_graphs([G1, G2, G3])
197
+ >>> unique = {w.canonical_hash for w in wrappers}
198
+ """
199
+ return tuple(
200
+ sorted(
201
+ (self.canonicalise_graph(g) for g in graphs),
202
+ key=lambda x: x.canonical_hash,
203
+ )
204
+ )
205
+
206
+ # ------------------------------------------------------------------ #
207
+ # Digest / core methods #
208
+ # ------------------------------------------------------------------ #
209
+ def canonical_signature(self, graph: nx.Graph) -> Digest:
210
+ """Return the *hash of the canonical form* of *graph*.
211
+
212
+ Equal digests ⇒ graphs are guaranteed isomorphic **under the
213
+ chosen back‑end and keys**.
214
+ """
215
+ return _digest(self._serialise(self._make_canonical_graph(graph)))
216
+
217
+ # Alias kept for backward‑compatibility
218
+ graph_canonical_hash: Callable[[nx.Graph], Digest] = canonical_signature
219
+
220
+ # ------------------------------------------------------------------ #
221
+ # Internal – make canonical graph #
222
+ # ------------------------------------------------------------------ #
223
+ def _make_canonical_graph(self, g: nx.Graph) -> nx.Graph:
224
+ """Dispatcher that calls the appropriate back‑end."""
225
+ if self.backend == "generic":
226
+ return self._canon_generic(g)
227
+ elif self.backend == "wl":
228
+ return self._canon_wl(g)
229
+ elif self.backend == "nauty":
230
+ return self._canon_nauty(g)
231
+ else:
232
+ return canon_morgan(
233
+ g, morgan_radius=self._mg_k, node_attributes=self._mg_node_attrs
234
+ )
235
+ # return (
236
+ # self._canon_generic(g) if self.backend == "generic" else self._canon_wl(g)
237
+ # )
238
+
239
+ def _canon_nauty(self, g: nx.Graph) -> nx.Graph:
240
+ return self.nauty.canonical_form(g)
241
+
242
+ def _canon_generic(self, g: nx.Graph) -> nx.Graph:
243
+ """Pure attribute-sort strategy with ``O(V log V + E log E)`` cost."""
244
+ nodes_sorted = sorted(g.nodes(data=True), key=lambda x: self._node_key(*x))
245
+ mapping: Dict[NodeId, int] = {
246
+ old: i + 1 for i, (old, _) in enumerate(nodes_sorted)
247
+ }
248
+
249
+ G2 = type(g)()
250
+ for old, data in nodes_sorted:
251
+ G2.add_node(mapping[old], **data)
252
+
253
+ edges_sorted = sorted(g.edges(data=True), key=lambda x: self._edge_key(*x))
254
+ for u, v, data in edges_sorted:
255
+ G2.add_edge(mapping[u], mapping[v], **data)
256
+
257
+ return G2
258
+
259
+ def _canon_wl(self, g: nx.Graph) -> nx.Graph:
260
+ """Weisfeiler–Lehman colour-refinement back-end (pure Python).
261
+
262
+ Seeds each node’s initial colour by the tuple of attributes
263
+ in `self._wl_node_attrs` (e.g. ["element","charge","hcount"]),
264
+ then runs k iterations of WL and orders nodes by
265
+ (final_colour, degree, original_id).
266
+
267
+ Returns a new graph of the same type as `g`, with nodes relabelled
268
+ 1…N in that order and all original node & edge attributes preserved.
269
+ """
270
+ # 1) Prepare a working copy if we need composite node labels
271
+ if self._wl_node_attrs:
272
+ g2 = g.copy()
273
+ for n, data in g2.nodes(data=True):
274
+ # build the initial label tuple
275
+ data["_wl_init"] = tuple(
276
+ data.get(attr, "") for attr in self._wl_node_attrs
277
+ )
278
+ node_attr = "_wl_init"
279
+ else:
280
+ g2 = g
281
+ node_attr = "element"
282
+
283
+ # 2) Run WL hashing
284
+ wl_hash = _wl_hashes(
285
+ g2,
286
+ node_attr=node_attr,
287
+ edge_attr="order",
288
+ iterations=self._wl_k,
289
+ )
290
+
291
+ # 3) Extract final hash (last iteration) as the node colour
292
+ colour: Dict[NodeId, str] = {n: hashes[-1] for n, hashes in wl_hash.items()}
293
+
294
+ # 4) Determine node ordering
295
+ order: List[NodeId] = sorted(g, key=lambda n: (colour[n], g.degree[n], n))
296
+ mapping: Dict[NodeId, int] = {old: i + 1 for i, old in enumerate(order)}
297
+
298
+ # 5) Build the new graph
299
+ G2 = type(g)()
300
+ # copy any graph‐level attributes
301
+ if hasattr(g, "graph"):
302
+ G2.graph.update(g.graph)
303
+
304
+ # add nodes in canonical order
305
+ for old in order:
306
+ G2.add_node(mapping[old], **g.nodes[old])
307
+
308
+ # add edges, sorted for consistency
309
+ for u, v, e_attrs in sorted(
310
+ g.edges(data=True),
311
+ key=lambda e: tuple(sorted((mapping[e[0]], mapping[e[1]]))),
312
+ ):
313
+ G2.add_edge(mapping[u], mapping[v], **e_attrs)
314
+
315
+ return G2
316
+
317
+ # ------------------------------------------------------------------ #
318
+ # Internal – serialisation #
319
+ # ------------------------------------------------------------------ #
320
+ def _serialise(self, g: nx.Graph) -> str:
321
+ """Stable plain‑text representation → fed into SHA‑256."""
322
+ nodes = sorted(g.nodes(data=True), key=lambda x: self._node_key(*x))
323
+ edges = sorted(g.edges(data=True), key=lambda x: self._edge_key(*x))
324
+
325
+ node_str = ";".join(f"{n}:{self._node_key(n, d)}" for n, d in nodes)
326
+ edge_str = ";".join(f"{(u, v)}:{self._edge_key(u, v, d)}" for u, v, d in edges)
327
+ return f"N[{node_str}]|E[{edge_str}]"
328
+
329
+ # ------------------------------------------------------------------ #
330
+ # Misc utilities #
331
+ # ------------------------------------------------------------------ #
332
+ def help(self) -> None: # pragma: no cover
333
+ """Pretty‑print the public methods with their signatures."""
334
+ print(inspect.getdoc(self))
335
+ for meth in (
336
+ "canonical_signature",
337
+ "make_canonical_graph",
338
+ "canonicalise_graph",
339
+ ):
340
+ print(f" • {meth}{inspect.signature(getattr(self, meth))}")
341
+
342
+ def __repr__(self) -> str: # pragma: no cover
343
+ return (
344
+ f"<GraphCanonicaliser backend={self.backend!r} "
345
+ f"node_key={self._node_key.__name__} "
346
+ f"edge_key={self._edge_key.__name__}>"
347
+ )
348
+
349
+ # keep public attribute for backwards compatibility
350
+ make_canonical_graph = _make_canonical_graph
351
+
352
+
353
+ # =============================================================================
354
+ # Value wrapper (unchanged surface – richer docs)
355
+ # =============================================================================
356
+ class CanonicalGraph:
357
+ """*Value object* tying together:
358
+
359
+ * the **original** NetworkX graph (mutable, user‑supplied);
360
+ * its **canonical twin** (immutable copy, nodes relabelled 1…N);
361
+ * a 32‑char **SHA‑256 digest**.
362
+
363
+ Instances compare & hash **by digest only** – perfect for set/dict
364
+ membership while still carrying the underlying graphs.
365
+
366
+ Mutating :attr:`original_graph` invalidates :attr:`canonical_hash`;
367
+ repeat canonicalisation after structural changes.
368
+ """
369
+
370
+ def __init__(self, g: nx.Graph, canon: GraphCanonicaliser) -> None:
371
+ self._original: nx.Graph = g
372
+ self._canonical_graph: nx.Graph = canon._make_canonical_graph(g)
373
+ self._canonical_hash: Digest = canon.canonical_signature(self._canonical_graph)
374
+
375
+ # ------------------------------------------------------------------ #
376
+ # Dunder sugar #
377
+ # ------------------------------------------------------------------ #
378
+ def __eq__(self, other: object) -> bool:
379
+ return (
380
+ isinstance(other, CanonicalGraph)
381
+ and self.canonical_hash == other.canonical_hash
382
+ )
383
+
384
+ def __hash__(self) -> int:
385
+ return hash(self.canonical_hash)
386
+
387
+ def __str__(self) -> str: # pragma: no cover
388
+ return (
389
+ f"<CanonicalGraph |V|={self._canonical_graph.number_of_nodes()} "
390
+ f"|E|={self._canonical_graph.number_of_edges()} "
391
+ f"hash={self.canonical_hash[:8]}>"
392
+ )
393
+
394
+ __repr__ = __str__
395
+
396
+ # ------------------------------------------------------------------ #
397
+ # Public read‑only views #
398
+ # ------------------------------------------------------------------ #
399
+ @property
400
+ def original_graph(self) -> nx.Graph:
401
+ """Direct mutable reference to the caller-provided graph."""
402
+ return self._original
403
+
404
+ @property
405
+ def canonical_graph(self) -> nx.Graph:
406
+ """Immutable relabelled copy with nodes numbered from 1 through V."""
407
+ return self._canonical_graph
408
+
409
+ @property
410
+ def canonical_hash(self) -> Digest:
411
+ """32‑hex‑char SHA‑256 digest (*lower‑case*, deterministic)."""
412
+ return self._canonical_hash
413
+
414
+ # ------------------------------------------------------------------ #
415
+ # Convenience debug helper #
416
+ # ------------------------------------------------------------------ #
417
+ def help(self) -> None: # pragma: no cover
418
+ """Print both graphs’ node/edge tables – handy for debugging."""
419
+ print("Original graph:")
420
+ for n, d in self._original.nodes(data=True):
421
+ print(f" {n}: {d}")
422
+ print("\nCanonical graph:")
423
+ for n, d in self._canonical_graph.nodes(data=True):
424
+ print(f" {n}: {d}")
425
+ print("\nEdges:")
426
+ for u, v, d in self._canonical_graph.edges(data=True):
427
+ print(f" ({u},{v}): {d}")
428
+
429
+
430
+ class CanonicalRule:
431
+ """Value object that wraps a graph transformation rule in GML string form,
432
+ providing a canonicalised GML output and a stable 32-character SHA-256
433
+ hash.
434
+
435
+ Internally, the GML rule is parsed into a NetworkX graph via `gml_to_its`,
436
+ canonicalised using a `GraphCanonicaliser`, and re-serialized back to GML
437
+ with `its_to_gml`.
438
+
439
+ Equality and hashing are based solely on the canonical hash, so
440
+ isomorphic rules (under the chosen backend) compare equal.
441
+
442
+ :ivar original_rule: The raw GML string supplied by the user.
443
+ :vartype original_rule: str
444
+ :ivar original_graph: The NetworkX graph parsed from `original_rule`.
445
+ :vartype original_graph: nx.Graph
446
+ :ivar canonical_graph: The relabelled canonical graph (nodes renumbered 1…N).
447
+ :vartype canonical_graph: nx.Graph
448
+ :ivar canonical_rule: The canonical graph re-serialized to a GML string.
449
+ :vartype canonical_rule: str
450
+ :ivar canonical_hash: 32-hex-character SHA-256 digest of the canonical graph.
451
+ :vartype canonical_hash: Digest
452
+ """
453
+
454
+ def __init__(
455
+ self,
456
+ rule: str,
457
+ canon: GraphCanonicaliser = GraphCanonicaliser(),
458
+ ) -> None:
459
+ """Instantiate a CanonicalRule.
460
+
461
+ :param rule: GML string of the transformation rule.
462
+ :type rule: str
463
+ :param canon: Initialized canonicaliser (generic or WL backend).
464
+ :type canon: GraphCanonicaliser
465
+ """
466
+ # Store raw inputs
467
+ self._original_rule: str = rule
468
+ # Parse into NetworkX
469
+ self._original_graph: nx.Graph = gml_to_its(rule)
470
+ # Canonicalise graph
471
+ self._canonical_graph: nx.Graph = canon._make_canonical_graph(
472
+ self._original_graph
473
+ )
474
+ # Serialize back to GML
475
+ self._canonical_rule: str = its_to_gml(self._canonical_graph)
476
+ # Compute hash
477
+ self._canonical_hash: Digest = canon.canonical_signature(self._canonical_graph)
478
+
479
+ def __eq__(self, other: object) -> bool:
480
+ return (
481
+ isinstance(other, CanonicalRule)
482
+ and self.canonical_hash == other.canonical_hash
483
+ )
484
+
485
+ def __hash__(self) -> int:
486
+ return hash(self._canonical_hash)
487
+
488
+ def __str__(self) -> str:
489
+ n = self._canonical_graph.number_of_nodes()
490
+ m = self._canonical_graph.number_of_edges()
491
+ return f"<CanonicalRule |V|={n} |E|={m} hash={self._canonical_hash[:8]}>"
492
+
493
+ __repr__ = __str__
494
+
495
+ @property
496
+ def original_rule(self) -> str:
497
+ """Original GML rule string."""
498
+ return self._original_rule
499
+
500
+ @property
501
+ def original_graph(self) -> nx.Graph:
502
+ """Parsed NetworkX graph from `original_rule`."""
503
+ return self._original_graph
504
+
505
+ @property
506
+ def canonical_graph(self) -> nx.Graph:
507
+ """Relabelled canonical NetworkX graph (nodes 1…N)."""
508
+ return self._canonical_graph
509
+
510
+ @property
511
+ def canonical_rule(self) -> str:
512
+ """GML string of the canonical graph."""
513
+ return self._canonical_rule
514
+
515
+ @property
516
+ def canonical_hash(self) -> Digest:
517
+ """32-hex-character SHA-256 digest of the canonical graph."""
518
+ return self._canonical_hash
519
+
520
+ def help(self) -> None:
521
+ """Print original and canonical rule texts and underlying graphs."""
522
+ print("Original GML rule:")
523
+ print(self._original_rule)
524
+ print("\nCanonical GML rule:")
525
+ print(self._canonical_rule)
526
+ print("\nCanonical graph nodes and data:")
527
+ for n, d in self._canonical_graph.nodes(data=True):
528
+ print(f" {n}: {d}")
529
+ print("\nCanonical graph edges and data:")
530
+ for u, v, d in self._canonical_graph.edges(data=True):
531
+ print(f" ({u},{v}): {d}")
@@ -0,0 +1,42 @@
1
+ cmake_minimum_required(VERSION 3.16)
2
+ project(synkit_canon VERSION 1.6.5 LANGUAGES CXX)
3
+ add_library(synkit_canon SHARED src/canonical.cpp)
4
+ target_compile_definitions(synkit_canon PRIVATE SYNKIT_CANON_BUILD)
5
+ target_compile_features(synkit_canon PUBLIC cxx_std_17)
6
+ target_include_directories(synkit_canon PUBLIC
7
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
8
+ $<INSTALL_INTERFACE:include>)
9
+ set_target_properties(synkit_canon PROPERTIES CXX_EXTENSIONS OFF)
10
+ if(MSVC)
11
+ target_compile_options(synkit_canon PRIVATE /W4)
12
+ else()
13
+ target_compile_options(synkit_canon PRIVATE -Wall -Wextra -Wpedantic)
14
+ endif()
15
+ option(SYNKIT_CANON_BUILD_EXAMPLES "Build standalone graph example" OFF)
16
+ if(SYNKIT_CANON_BUILD_EXAMPLES)
17
+ add_executable(canonical_graph examples/canonical_graph.cpp)
18
+ target_link_libraries(canonical_graph PRIVATE synkit_canon)
19
+ endif()
20
+ option(SYNKIT_CANON_BUILD_TESTS "Build independent native symmetry checks" OFF)
21
+ if(SYNKIT_CANON_BUILD_TESTS)
22
+ enable_testing()
23
+ add_executable(canonical_symmetry_tests tests/symmetry.cpp)
24
+ target_compile_features(canonical_symmetry_tests PRIVATE cxx_std_17)
25
+ target_include_directories(canonical_symmetry_tests PRIVATE src)
26
+ add_test(NAME canonical_symmetry COMMAND canonical_symmetry_tests)
27
+ endif()
28
+ include(GNUInstallDirs)
29
+ option(SYNKIT_CANON_WHEEL "Install the runtime library inside the Python wheel" OFF)
30
+ if(SYNKIT_CANON_WHEEL)
31
+ if(MSVC)
32
+ set_property(TARGET synkit_canon PROPERTY MSVC_RUNTIME_LIBRARY
33
+ "MultiThreaded$<$<CONFIG:Debug>:Debug>")
34
+ endif()
35
+ install(TARGETS synkit_canon
36
+ LIBRARY DESTINATION synkit/Graph/Canon/_native/lib
37
+ RUNTIME DESTINATION synkit/Graph/Canon/_native/lib)
38
+ else()
39
+ install(TARGETS synkit_canon LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
40
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
41
+ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
42
+ endif()