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
File without changes
@@ -0,0 +1,222 @@
1
+ from __future__ import annotations
2
+ import networkx as nx
3
+ from collections import Counter
4
+ from hashlib import blake2b
5
+ from dataclasses import dataclass, field
6
+ from typing import Dict, List, Optional, Any, Union
7
+ import numpy as np
8
+ from synkit.IO import rsmi_to_graph
9
+
10
+
11
+ @dataclass
12
+ class WLRnxFps:
13
+ """
14
+ Weisfeiler-Lehman Reaction Fingerprint Sketch (NetworkX).
15
+
16
+ :param radius: number of WL refinement iterations
17
+ :type radius: int
18
+ :param size: bit budget for the parity sketch
19
+ :type size: int
20
+ :param to_array: whether to return fingerprint as NumPy array
21
+ :type to_array: bool
22
+
23
+ Usage example:
24
+ >>> rsmi = ('COc1cc(NC(N)=S)ccc1-n1cnc(C)c1.O=C1C(Br)CCCC1c1ccc(Cl)cc1Cl'
25
+ >>> +'>>Br.COc1cc(Nc2nc3c(s2)CCCC3c2ccc(Cl)cc2Cl)ccc1-n1cnc(C)c1.O')
26
+ >>> react, prod = rsmi_to_graph(rsmi, drop_non_aam=False, use_index_as_atom_map=False)
27
+ >>> fps = WLRnxFps(radius=2, size=1024, to_array=False).fit(react, prod)
28
+ >>> bits = fps.fingerprint
29
+ """
30
+
31
+ radius: int = 2
32
+ size: int = 1024
33
+ to_array: bool = False
34
+
35
+ _tokens_R: Optional[Counter] = field(init=False, default=None)
36
+ _tokens_P: Optional[Counter] = field(init=False, default=None)
37
+ _delta: Optional[Counter] = field(init=False, default=None)
38
+ _support: Optional[List[int]] = field(init=False, default=None)
39
+ _fingerprint: Optional[Union[List[int], np.ndarray]] = field(
40
+ init=False, default=None
41
+ )
42
+
43
+ def fit(self, react: nx.Graph, prod: nx.Graph) -> WLRnxFps:
44
+ """Compute WL tokens for reactant and product graphs, then build parity sketch on Δ-support.
45
+
46
+ :param react: reactant graph with node attrs 'element','aromatic','hcount','charge'
47
+ :type react: nx.Graph
48
+ :param prod: product graph with same node/edge attrs
49
+ :type prod: nx.Graph
50
+ :return: self
51
+ :rtype: WLRnxFps
52
+ :raises ValueError: if size is not positive
53
+ """
54
+ if self.size <= 0:
55
+ raise ValueError("size must be a positive integer")
56
+
57
+ def wl_tokens(G: nx.Graph) -> Counter:
58
+ labels: Dict[int, int] = {}
59
+ for n, attrs in G.nodes(data=True):
60
+ atom_tuple = (
61
+ attrs.get("element"),
62
+ bool(attrs.get("aromatic", False)),
63
+ int(attrs.get("charge", 0)),
64
+ int(attrs.get("hcount", 0)),
65
+ G.degree(n),
66
+ )
67
+ labels[n] = _h64(("init", atom_tuple))
68
+ cnt = Counter(labels.values())
69
+ for k in range(1, self.radius + 1):
70
+ new_labels: Dict[int, int] = {}
71
+ for n in G.nodes():
72
+ neigh = []
73
+ for m in G.neighbors(n):
74
+ bond_order = float(G.edges[n, m].get("order", 1.0))
75
+ neigh.append((_h64(("bond", bond_order)), labels[m]))
76
+ neigh.sort()
77
+ new_labels[n] = _h64(("wl", k, labels[n], tuple(neigh)))
78
+ labels = new_labels
79
+ cnt.update(labels.values())
80
+ return cnt
81
+
82
+ TR = wl_tokens(react)
83
+ TP = wl_tokens(prod)
84
+
85
+ Delta = Counter(TP)
86
+ for h, v in TR.items():
87
+ Delta[h] -= v
88
+ if Delta[h] == 0:
89
+ del Delta[h]
90
+
91
+ support = list(Delta.keys())
92
+ self._tokens_R = TR
93
+ self._tokens_P = TP
94
+ self._delta = Delta
95
+ self._support = support
96
+
97
+ bits = np.zeros(self.size, dtype=int) if self.to_array else [0] * self.size
98
+ for h in support:
99
+ idx = h % self.size
100
+ if self.to_array:
101
+ bits[idx] ^= 1
102
+ else:
103
+ bits[idx] = bits[idx] ^ 1
104
+ self._fingerprint = bits
105
+
106
+ return self
107
+
108
+ @classmethod
109
+ def from_rsmi(
110
+ cls,
111
+ rsmi: str,
112
+ radius: int = 2,
113
+ size: int = 1024,
114
+ to_array: bool = False,
115
+ drop_non_aam: bool = False,
116
+ use_index_as_atom_map: bool = False,
117
+ ) -> WLRnxFps:
118
+ """Build WLRnxFps directly from a reaction SMILES string.
119
+
120
+ :param rsmi: reaction SMILES string
121
+ :type rsmi: str
122
+ :param radius: number of WL refinement iterations
123
+ :type radius: int
124
+ :param size: bit budget for the parity sketch
125
+ :type size: int
126
+ :param to_array: return fingerprint as NumPy array if True
127
+ :type to_array: bool
128
+ :param drop_non_aam: drop atoms without atom-atom mapping
129
+ :type drop_non_aam: bool
130
+ :param use_index_as_atom_map: interpret node indices as atom map numbers
131
+ :type use_index_as_atom_map: bool
132
+ :return: fitted WLRnxFps instance
133
+ :rtype: WLRnxFps
134
+ :raises ValueError: on invalid SMILES parsing
135
+ """
136
+ try:
137
+ react, prod = rsmi_to_graph(
138
+ rsmi,
139
+ drop_non_aam=drop_non_aam,
140
+ use_index_as_atom_map=use_index_as_atom_map,
141
+ )
142
+ except Exception as e:
143
+ raise ValueError(f"Failed to parse rsmi: {e}")
144
+
145
+ return cls(radius=radius, size=size, to_array=to_array).fit(react, prod)
146
+
147
+ @property
148
+ def tokens_R(self) -> Counter:
149
+ """:return: WL token counts for reactant
150
+ :rtype: Counter
151
+ :raises AttributeError: if fit() has not been called
152
+ """
153
+ if self._tokens_R is None:
154
+ raise AttributeError("Call fit() before accessing tokens_R")
155
+ return self._tokens_R
156
+
157
+ @property
158
+ def tokens_P(self) -> Counter:
159
+ """:return: WL token counts for product
160
+ :rtype: Counter
161
+ :raises AttributeError: if fit() has not been called
162
+ """
163
+ if self._tokens_P is None:
164
+ raise AttributeError("Call fit() before accessing tokens_P")
165
+ return self._tokens_P
166
+
167
+ @property
168
+ def delta(self) -> Counter:
169
+ """:return: Signed token difference (product - reactant)
170
+ :rtype: Counter
171
+ :raises AttributeError: if fit() has not been called
172
+ """
173
+ if self._delta is None:
174
+ raise AttributeError("Call fit() before accessing delta")
175
+ return self._delta
176
+
177
+ @property
178
+ def support(self) -> List[int]:
179
+ """:return: Tokens with non-zero delta
180
+ :rtype: List[int]
181
+ :raises AttributeError: if fit() has not been called
182
+ """
183
+ if self._support is None:
184
+ raise AttributeError("Call fit() before accessing support")
185
+ return self._support
186
+
187
+ @property
188
+ def fingerprint(self) -> Union[List[int], np.ndarray]:
189
+ """:return: Parity sketch bit vector (0/1)
190
+ :rtype: Union[List[int], numpy.ndarray]
191
+ :raises AttributeError: if fit() has not been called
192
+ """
193
+ if self._fingerprint is None:
194
+ raise AttributeError("Call fit() before accessing fingerprint")
195
+ return self._fingerprint
196
+
197
+ def __repr__(self) -> str:
198
+ support_len = len(self._support) if self._support is not None else 0
199
+ return (
200
+ f"<WLRnxFps radius={self.radius} size={self.size} "
201
+ f"support={support_len} to_array={self.to_array}>"
202
+ )
203
+
204
+ def help(self) -> None:
205
+ """Print usage examples and class docstring.
206
+
207
+ :return: None
208
+ """
209
+ print(self.__doc__)
210
+
211
+
212
+ def _h64(obj: Any) -> int:
213
+ """Compute a stable 64-bit hash of an object.
214
+
215
+ :param obj: any hashable representation
216
+ :type obj: Any
217
+ :return: 64-bit integer hash
218
+ :rtype: int
219
+ """
220
+ h = blake2b(digest_size=8)
221
+ h.update(repr(obj).encode("utf-8"))
222
+ return int.from_bytes(h.digest(), "little")
@@ -0,0 +1,5 @@
1
+ from .wl_hash import WLHash
2
+ from .morgan_fps import MorganFPs
3
+ from .path_fps import PathFPs
4
+
5
+ __all__ = ["WLHash", "MorganFPs", "PathFPs"]
@@ -0,0 +1,323 @@
1
+ import networkx as nx
2
+ from joblib import Parallel, delayed
3
+ from typing import List, Dict, Any, Union
4
+ from collections import Counter, OrderedDict
5
+ from synkit.IO.debug import setup_logging
6
+ from synkit.Graph.Feature.graph_signature import GraphSignature
7
+
8
+ logger = setup_logging()
9
+
10
+
11
+ class GraphDescriptor:
12
+ def __init__(self) -> None:
13
+ pass
14
+
15
+ @staticmethod
16
+ def is_graph_empty(graph: Union[nx.Graph, dict, list, Any]) -> bool:
17
+ """Determine if a graph representation is empty.
18
+
19
+ :param graph: A graph representation which can be
20
+ a NetworkX graph, a dictionary, a list, or an object with an 'is_empty' method.
21
+ :type graph: Union[nx.Graph, dict, list, Any]
22
+
23
+ :return: True if the graph is empty, False otherwise.
24
+ :rtype: bool
25
+
26
+ :raises TypeError: If the graph representation is not supported.
27
+ """
28
+ if isinstance(graph, nx.Graph):
29
+ return graph.number_of_nodes() == 0
30
+ elif isinstance(graph, dict):
31
+ return len(graph) == 0
32
+ elif isinstance(graph, list):
33
+ return all(len(row) == 0 for row in graph)
34
+ elif hasattr(graph, "is_empty"):
35
+ return graph.is_empty()
36
+ else:
37
+ raise TypeError("Unsupported graph representation")
38
+
39
+ @staticmethod
40
+ def is_acyclic_graph(G: nx.Graph) -> bool:
41
+ """Determines if the given graph is acyclic.
42
+
43
+ :param G: The graph to be checked.
44
+ :type G: nx.Graph
45
+
46
+ :return: True if the graph is acyclic, False otherwise.
47
+ :rtype: bool
48
+ """
49
+ GraphDescriptor._validate_graph_input(G)
50
+ return nx.is_tree(G) if not GraphDescriptor.is_graph_empty(G) else False
51
+
52
+ @staticmethod
53
+ def is_single_cyclic_graph(G: nx.Graph) -> bool:
54
+ """Determines if the given graph has exactly one cycle.
55
+
56
+ :param G: The graph to be checked.
57
+ :type G: nx.Graph
58
+
59
+ :return: True if the graph is single cyclic, False otherwise.
60
+ :rtype: bool
61
+ """
62
+ GraphDescriptor._validate_graph_input(G)
63
+ if GraphDescriptor.is_graph_empty(G) or not nx.is_connected(G):
64
+ return False
65
+
66
+ cycles = nx.cycle_basis(G)
67
+ if cycles and set(G.nodes()) == {node for cycle in cycles for node in cycle}:
68
+ return G.number_of_edges() == G.number_of_nodes()
69
+ return False
70
+
71
+ @staticmethod
72
+ def is_complex_cyclic_graph(G: nx.Graph) -> bool:
73
+ """Determines if the graph is complex cyclic with multiple cycles.
74
+
75
+ :param G: The graph to be checked.
76
+ :type G: nx.Graph
77
+
78
+ :return: True if the graph is complex cyclic, False otherwise.
79
+ :rtype: bool
80
+ """
81
+ GraphDescriptor._validate_graph_input(G)
82
+ if GraphDescriptor.is_graph_empty(G) or not nx.is_connected(G):
83
+ return False
84
+
85
+ cycles = nx.minimum_cycle_basis(G)
86
+ nodes_in_cycles = {node for cycle in cycles for node in cycle}
87
+ return len(cycles) > 1 and nodes_in_cycles == set(G.nodes())
88
+
89
+ @staticmethod
90
+ def check_graph_type(G: nx.Graph) -> str:
91
+ """Classifies the graph as acyclic, single cyclic, or complex cyclic.
92
+
93
+ :param G: The graph to be checked.
94
+ :type G: nx.Graph
95
+
96
+ :return: The classification result.
97
+ :rtype: str
98
+ """
99
+ GraphDescriptor._validate_graph_input(G)
100
+ if GraphDescriptor.is_graph_empty(G):
101
+ return "Empty Graph"
102
+ elif GraphDescriptor.is_acyclic_graph(G):
103
+ return "Acyclic"
104
+ elif GraphDescriptor.is_single_cyclic_graph(G):
105
+ return "Single Cyclic"
106
+ elif GraphDescriptor.is_complex_cyclic_graph(G):
107
+ return "Combinatorial Cyclic"
108
+ else:
109
+ return "Complex Cyclic"
110
+
111
+ @staticmethod
112
+ def get_cycle_member_rings(G: nx.Graph, type="minimal") -> List[int]:
113
+ """Identifies all cycles in the given graph using cycle bases to ensure
114
+ no overlap and returns a list of the sizes of these cycles (member
115
+ rings), sorted in ascending order.
116
+
117
+ :param G: The NetworkX graph to be analyzed.
118
+ :type G: nx.Graph
119
+
120
+ :return: A sorted list of cycle sizes (member rings) found in the graph.
121
+ :rtype: List[int]
122
+ """
123
+ if not isinstance(G, nx.Graph):
124
+ raise TypeError("Input must be a networkx Graph object.")
125
+
126
+ if type == "minimal":
127
+ cycles = nx.minimum_cycle_basis(G)
128
+ else:
129
+ cycles = nx.cycle_basis(G)
130
+ member_rings = [len(cycle) for cycle in cycles]
131
+
132
+ member_rings.sort()
133
+
134
+ return member_rings
135
+
136
+ @staticmethod
137
+ def get_element_count(graph: nx.Graph) -> Dict[str, int]:
138
+ """Counts occurrences of each element in the graph nodes.
139
+
140
+ :param graph: A NetworkX graph with 'element' attribute in nodes.
141
+ :type graph: nx.Graph
142
+
143
+ :return: An ordered dictionary with element counts.
144
+ :rtype: Dict[str, int]
145
+ """
146
+ element_counts = Counter(data["element"] for _, data in graph.nodes(data=True))
147
+ return OrderedDict(sorted(element_counts.items()))
148
+
149
+ @staticmethod
150
+ def get_descriptors(
151
+ entry: Dict,
152
+ reaction_centers: str = "RC",
153
+ its: str = "ITS",
154
+ condensed: bool = True,
155
+ ) -> Dict:
156
+ """Enhance an entry dictionary with topology type and reaction type
157
+ descriptors.
158
+
159
+ :param entry: A dictionary with reaction data.
160
+ :type entry: Dict
161
+ :param reaction_centers: Key for accessing reaction center data.
162
+ :type reaction_centers: str
163
+ :param its: Key for accessing ITS (Intermediate Transition State) data.
164
+ :type its: str
165
+
166
+ :return: The enhanced entry with additional descriptors.
167
+ :rtype: Dict
168
+ """
169
+ graph = GraphDescriptor._extract_graph(entry, reaction_centers)
170
+ its_graph = GraphDescriptor._extract_graph(entry, its)
171
+
172
+ if not graph or not its_graph:
173
+ return entry # Early exit if graphs are missing
174
+
175
+ # Set initial topology descriptor for the reaction center graph
176
+ entry["topo"] = GraphDescriptor.check_graph_type(graph)
177
+ entry["cycle"] = GraphDescriptor.get_cycle_member_rings(graph)
178
+ entry["atom_count"] = GraphDescriptor.get_element_count(graph)
179
+ entry["its_count"] = GraphDescriptor.get_element_count(its_graph)
180
+
181
+ # Determine the reaction type based on the topology type
182
+ entry["rtype"] = (
183
+ "Elementary"
184
+ if entry["topo"] in ["Single Cyclic", "Acyclic"]
185
+ else "Complicated"
186
+ )
187
+
188
+ GraphDescriptor._adjust_cycle_and_step(entry, "cycle", entry["topo"])
189
+ entry["signature_rc"] = GraphSignature(graph).create_graph_signature()
190
+
191
+ # Initialize ITS descriptors and call adjust
192
+ topo_its = GraphDescriptor.check_graph_type(its_graph)
193
+ cycle_its = GraphDescriptor.get_cycle_member_rings(its_graph)
194
+ entry["cycle_its"] = cycle_its # Ensure key is initialized
195
+ GraphDescriptor._adjust_cycle_and_step(
196
+ entry, "cycle_its", topo_its, its_prefix="its"
197
+ )
198
+
199
+ entry["signature_its"] = GraphSignature(its_graph).create_graph_signature()
200
+
201
+ return entry
202
+
203
+ @staticmethod
204
+ def _extract_graph(entry: Dict, key: str) -> Union[nx.Graph, None]:
205
+ """Extracts a graph from an entry dictionary based on the specified
206
+ key.
207
+
208
+ :param entry: The dictionary containing graph data.
209
+ :type entry: Dict
210
+ :param key: The key for accessing graph data.
211
+ :type key: str
212
+
213
+ :return: The extracted graph or None if unavailable.
214
+ :rtype: Union[nx.Graph, None]
215
+ """
216
+ data = entry.get(key)
217
+ if isinstance(data, tuple):
218
+ try:
219
+ return data[2]
220
+ except IndexError:
221
+ logger.error(f"No graph data available at index 2 for entry {entry}")
222
+ elif isinstance(data, nx.Graph):
223
+ return data
224
+ else:
225
+ logger.error(f"Unsupported data type for {key} in entry {entry}")
226
+ return None
227
+
228
+ @staticmethod
229
+ def _adjust_cycle_and_step(
230
+ entry: Dict, cycle_key: str, topo_type: str, its_prefix: str = ""
231
+ ) -> None:
232
+ """Adjusts cycle and step descriptors based on the graph topology type.
233
+
234
+ :param entry: The entry dictionary to update.
235
+ :type entry: Dict
236
+ :param cycle_key: The key for the cycle descriptor.
237
+ :type cycle_key: str
238
+ :param topo_type: The topology type.
239
+ :type topo_type: str
240
+ :param its_prefix: Prefix for ITS-specific descriptors.
241
+ :type its_prefix: str
242
+ """
243
+ step_key = f"rstep_{its_prefix}" if its_prefix else "rstep"
244
+
245
+ # Initialize the step key in the dictionary to avoid KeyError
246
+ if cycle_key not in entry:
247
+ entry[cycle_key] = []
248
+
249
+ if topo_type == "Acyclic":
250
+ entry[cycle_key] = [0]
251
+ elif topo_type == "Complex Cyclic":
252
+ entry[cycle_key] = [0] + entry[cycle_key]
253
+
254
+ entry[step_key] = len(entry[cycle_key])
255
+
256
+ @staticmethod
257
+ def _validate_graph_input(G: nx.Graph) -> None:
258
+ """Validates that the input is a NetworkX graph.
259
+
260
+ :param G: The graph to validate.
261
+ :type G: nx.Graph
262
+
263
+ :raises TypeError: If G is not a NetworkX Graph.
264
+ """
265
+ if not isinstance(G, nx.Graph):
266
+ raise TypeError("Input must be a NetworkX Graph object.")
267
+
268
+ @staticmethod
269
+ def process_entries_in_parallel(
270
+ entries: List[Dict],
271
+ reaction_centers: str = "RC",
272
+ its: str = "ITS",
273
+ condensed: bool = True,
274
+ n_jobs: int = 4,
275
+ verbose: int = 0,
276
+ ) -> List[Dict]:
277
+ """Processes a list of entries in parallel to enhance each entry with
278
+ descriptors.
279
+
280
+ :param entries: List of dictionaries containing reaction data to enhance.
281
+ :type entries: List[Dict]
282
+ :param reaction_centers: Key to retrieve reaction center graph data from each
283
+ entry dictionary.
284
+ :type reaction_centers: str
285
+ :param its: Key to retrieve ITS (Intermediate Transition State) graph data from
286
+ each entry dictionary.
287
+ :type its: str
288
+ :param condensed: If True, condenses node signatures with counts.
289
+ :type condensed: bool
290
+ :param n_jobs: Number of jobs to run in parallel. -1 uses all processors.
291
+ :type n_jobs: int
292
+ :param verbose: The verbosity level for joblib's Parallel.
293
+ :type verbose: int
294
+
295
+ :return: A list of enhanced dictionaries with added descriptors.
296
+ :rtype: List[Dict]
297
+ """
298
+ return Parallel(n_jobs=n_jobs, verbose=verbose)(
299
+ delayed(GraphDescriptor.get_descriptors)(
300
+ entry, reaction_centers, its, condensed
301
+ )
302
+ for entry in entries
303
+ )
304
+
305
+
306
+ def check_graph_connectivity(graph: nx.Graph) -> str:
307
+ """Check the connectivity of a NetworkX graph.
308
+
309
+ This function assesses whether all nodes in the graph are connected by some path,
310
+ applicable to undirected graphs.
311
+
312
+ :param graph: A NetworkX graph object.
313
+ :type graph: nx.Graph
314
+
315
+ :return: Returns 'Connected' if the graph is connected, otherwise 'Disconnected'.
316
+ :rtype: str
317
+
318
+ :raises NetworkXNotImplemented: If graph is directed and does not support is_connected.
319
+ """
320
+ if nx.is_connected(graph):
321
+ return "Connected"
322
+ else:
323
+ return "Disconnected."
@@ -0,0 +1,96 @@
1
+ import networkx as nx
2
+ import hashlib
3
+ import numpy as np
4
+
5
+
6
+ class GraphFP:
7
+ def __init__(
8
+ self, graph: nx.Graph, nBits: int = 1024, hash_alg: str = "sha256"
9
+ ) -> None:
10
+ """Initialize the GraphFP class to create binary fingerprints based on
11
+ various graph characteristics.
12
+
13
+ :param graph: Graph on which to perform analysis.
14
+ :type graph: nx.Graph
15
+ :param nBits: Size of the binary fingerprint in bits.
16
+ :type nBits: int
17
+ :param hash_alg: Cryptographic hash function used for hashing.
18
+ :type hash_alg: str
19
+ """
20
+ self.graph = graph
21
+ self.nBits = nBits
22
+ self.hash_alg = hash_alg
23
+ self.hash_function = getattr(hashlib, self.hash_alg)
24
+
25
+ def fingerprint(self, method: str) -> str:
26
+ """Generate a binary string fingerprint of the graph using the
27
+ specified method.
28
+
29
+ :param method: The method to use for fingerprinting
30
+ ('spectrum', 'adjacency', 'degree', 'motif')
31
+ :type method: str
32
+
33
+ :return: A binary string of length `nBits` that represents the fingerprint of the graph.
34
+ :rtype: str
35
+ """
36
+ if method == "spectrum":
37
+ fp = self._spectrum_fp()
38
+ elif method == "adjacency":
39
+ fp = self._adjacency_fp()
40
+ elif method == "degree":
41
+ fp = self._degree_sequence_fp()
42
+ elif method == "motif":
43
+ fp = self._motif_count_fp()
44
+ else:
45
+ raise ValueError("Unsupported fingerprinting method.")
46
+
47
+ # If the fingerprint is shorter than nBits, use iterative deepening
48
+ if len(fp) < self.nBits:
49
+ fp += self.iterative_deepening(self.nBits - len(fp))
50
+
51
+ return fp[: self.nBits]
52
+
53
+ def _spectrum_fp(self) -> str:
54
+ # Graph spectrum (eigenvalues of the adjacency matrix)
55
+ eigenvalues = np.linalg.eigvals(nx.adjacency_matrix(self.graph).todense())
56
+ sorted_eigenvalues = np.sort(eigenvalues)[: self.nBits]
57
+ eigen_str = "".join(
58
+ bin(int(abs(eig)))[2:].zfill(8) for eig in sorted_eigenvalues
59
+ )
60
+ return eigen_str[: self.nBits]
61
+
62
+ def _adjacency_fp(self) -> str:
63
+ # Adjacency matrix flattened
64
+ adj_matrix = nx.adjacency_matrix(self.graph).todense().flatten()
65
+ adj_str = "".join(str(int(x)) for x in adj_matrix)
66
+ return adj_str[: self.nBits]
67
+
68
+ def _degree_sequence_fp(self) -> str:
69
+ # Degree sequence
70
+ degrees = sorted([d for n, d in self.graph.degree()], reverse=True)
71
+ degree_str = "".join(bin(d)[2:].zfill(8) for d in degrees)
72
+ return degree_str[: self.nBits]
73
+
74
+ def _motif_count_fp(self) -> str:
75
+ # Motif counts (e.g., number of triangles)
76
+ triangles = sum(nx.triangles(self.graph).values()) // 3
77
+ triangle_str = bin(triangles)[2:].zfill(self.nBits)
78
+ return triangle_str[: self.nBits]
79
+
80
+ def iterative_deepening(self, remaining_bits: int) -> str:
81
+ """Extend the hash length using iterative hashing until the desired bit
82
+ length is achieved.
83
+
84
+ :param remaining_bits: Number of bits needed to complete the fingerprint
85
+ to `nBits`.
86
+ :type remaining_bits: int
87
+
88
+ :return: Additional binary data to achieve the desired hash length.
89
+ :rtype: str
90
+ """
91
+ additional_data = ""
92
+ hash_obj = self.hash_function()
93
+ while len(additional_data) * 4 < remaining_bits:
94
+ hash_obj.update(additional_data.encode())
95
+ additional_data += hash_obj.hexdigest()
96
+ return bin(int(additional_data, 16))[2:][:remaining_bits]