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.
- synkit/CRN/Benchmark/__init__.py +53 -0
- synkit/CRN/Benchmark/crosschecks.py +13 -0
- synkit/CRN/Benchmark/kegg.py +12 -0
- synkit/CRN/Benchmark/networks.py +13 -0
- synkit/CRN/Benchmark/scaling.py +13 -0
- synkit/CRN/Benchmark/validate.py +13 -0
- synkit/CRN/Construct/__init__.py +16 -0
- synkit/CRN/Construct/abstract.py +668 -0
- synkit/CRN/Construct/arity.py +36 -0
- synkit/CRN/Construct/builder.py +619 -0
- synkit/CRN/Construct/derivation.py +63 -0
- synkit/CRN/Construct/flattener.py +100 -0
- synkit/CRN/Construct/keys.py +14 -0
- synkit/CRN/Construct/mixtures.py +117 -0
- synkit/CRN/Construct/rdkit_worker.py +69 -0
- synkit/CRN/Construct/smiles.py +99 -0
- synkit/CRN/Construct/state.py +31 -0
- synkit/CRN/Construct/strategy.py +75 -0
- synkit/CRN/Construct/worker.py +42 -0
- synkit/CRN/IO/__init__.py +36 -0
- synkit/CRN/IO/sbml.py +925 -0
- synkit/CRN/Pathway/__init__.py +72 -0
- synkit/CRN/Pathway/_adapter.py +333 -0
- synkit/CRN/Pathway/pathfinder.py +500 -0
- synkit/CRN/Pathway/reachability.py +796 -0
- synkit/CRN/Pathway/realizability.py +1322 -0
- synkit/CRN/Petrinet/__init__.py +93 -0
- synkit/CRN/Petrinet/analyzer.py +486 -0
- synkit/CRN/Petrinet/minimal_semiflows.py +436 -0
- synkit/CRN/Petrinet/net.py +1041 -0
- synkit/CRN/Petrinet/persistence.py +97 -0
- synkit/CRN/Petrinet/semiflows.py +483 -0
- synkit/CRN/Petrinet/siphon_search.py +402 -0
- synkit/CRN/Petrinet/structure.py +286 -0
- synkit/CRN/Props/__init__.py +130 -0
- synkit/CRN/Props/_rank.py +29 -0
- synkit/CRN/Props/deficiency.py +953 -0
- synkit/CRN/Props/dynamics.py +832 -0
- synkit/CRN/Props/helper.py +151 -0
- synkit/CRN/Props/stoich.py +751 -0
- synkit/CRN/Props/thermo.py +584 -0
- synkit/CRN/Query/__init__.py +66 -0
- synkit/CRN/Query/cache.py +41 -0
- synkit/CRN/Query/kegg_api.py +99 -0
- synkit/CRN/Query/kegg_extract.py +714 -0
- synkit/CRN/Query/kegg_impute.py +707 -0
- synkit/CRN/Query/kegg_parse.py +480 -0
- synkit/CRN/Query/to_syncrn.py +290 -0
- synkit/CRN/README.md +234 -0
- synkit/CRN/Structure/__init__.py +12 -0
- synkit/CRN/Structure/_graph_io.py +713 -0
- synkit/CRN/Structure/_matrices.py +88 -0
- synkit/CRN/Structure/_parse.py +544 -0
- synkit/CRN/Structure/reaction.py +237 -0
- synkit/CRN/Structure/rule.py +55 -0
- synkit/CRN/Structure/species.py +46 -0
- synkit/CRN/Structure/syncrn.py +929 -0
- synkit/CRN/Symmetry/__init__.py +20 -0
- synkit/CRN/Symmetry/_common.py +1059 -0
- synkit/CRN/Symmetry/_ir.py +940 -0
- synkit/CRN/Symmetry/automorphism.py +472 -0
- synkit/CRN/Symmetry/canon.py +441 -0
- synkit/CRN/Symmetry/isomorphism.py +412 -0
- synkit/CRN/Symmetry/symmetry.py +61 -0
- synkit/CRN/Symmetry/wl_canon.py +967 -0
- synkit/CRN/Visualize/__init__.py +11 -0
- synkit/CRN/Visualize/labels.py +113 -0
- synkit/CRN/Visualize/layout.py +708 -0
- synkit/CRN/Visualize/palette.py +292 -0
- synkit/CRN/Visualize/validation.py +122 -0
- synkit/CRN/Visualize/vis.py +1152 -0
- synkit/CRN/__init__.py +233 -0
- synkit/CRN/_build.py +50 -0
- synkit/CRN/_native_build.py +175 -0
- synkit/CRN/analysis.py +629 -0
- synkit/CRN/backend.py +74 -0
- synkit/CRN/cpp/CMakeLists.txt +58 -0
- synkit/CRN/cpp/algebra.cpp +46 -0
- synkit/CRN/cpp/closure.cpp +29 -0
- synkit/CRN/cpp/exact.h +55 -0
- synkit/CRN/cpp/pathway.cpp +46 -0
- synkit/CRN/cpp/semiflows.cpp +209 -0
- synkit/CRN/cpp/structural.cpp +240 -0
- synkit/CRN/cpp/symmetry.cpp +45 -0
- synkit/CRN/cpp/write_manifest.cmake +28 -0
- synkit/CRN/kinds.py +137 -0
- synkit/CRN/lib/synkit_crn.dll +0 -0
- synkit/CRN/lib/synkit_crn.json +33 -0
- synkit/CRN/native.py +388 -0
- synkit/CRN/native_analysis.py +459 -0
- synkit/Chem/Cluster/__init__.py +0 -0
- synkit/Chem/Cluster/butina.py +140 -0
- synkit/Chem/Fingerprint/__init__.py +0 -0
- synkit/Chem/Fingerprint/fp_calculator.py +155 -0
- synkit/Chem/Fingerprint/smiles_featurizer.py +258 -0
- synkit/Chem/Fingerprint/transformation_fp.py +139 -0
- synkit/Chem/Mapper/README.rst +43 -0
- synkit/Chem/Mapper/__init__.py +255 -0
- synkit/Chem/Mapper/_compat.py +130 -0
- synkit/Chem/Mapper/adapters/__init__.py +1 -0
- synkit/Chem/Mapper/adapters/prediction.py +126 -0
- synkit/Chem/Mapper/adapters/template.py +412 -0
- synkit/Chem/Mapper/chem/__init__.py +52 -0
- synkit/Chem/Mapper/chem/aam.py +673 -0
- synkit/Chem/Mapper/chem/blind.py +160 -0
- synkit/Chem/Mapper/chem/its.py +309 -0
- synkit/Chem/Mapper/chem/smiles.py +564 -0
- synkit/Chem/Mapper/graph/__init__.py +66 -0
- synkit/Chem/Mapper/graph/automorphism.py +395 -0
- synkit/Chem/Mapper/graph/blockcut.py +98 -0
- synkit/Chem/Mapper/graph/labeled_graph.py +104 -0
- synkit/Chem/Mapper/graph/refine.py +176 -0
- synkit/Chem/Mapper/graph/synkit_adapter.py +110 -0
- synkit/Chem/Mapper/io/__init__.py +13 -0
- synkit/Chem/Mapper/io/idxmapstr.py +82 -0
- synkit/Chem/Mapper/mapper.py +685 -0
- synkit/Chem/Mapper/reaction_search.py +554 -0
- synkit/Chem/Mapper/reporting/__init__.py +1 -0
- synkit/Chem/Mapper/reporting/alternatives.py +451 -0
- synkit/Chem/Mapper/reporting/analysis.py +681 -0
- synkit/Chem/Mapper/reporting/native_analysis.py +485 -0
- synkit/Chem/Mapper/reporting/spectrum.py +642 -0
- synkit/Chem/Mapper/solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/__init__.py +141 -0
- synkit/Chem/Mapper/solvers/exact/assignment/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_certificate.py +113 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_domains.py +162 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_verification.py +58 -0
- synkit/Chem/Mapper/solvers/exact/assignment/incremental_assignment.py +247 -0
- synkit/Chem/Mapper/solvers/exact/certificate.py +128 -0
- synkit/Chem/Mapper/solvers/exact/core.py +183 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/bounds.py +319 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/exhaustive.py +179 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/inputs.py +283 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/records.py +242 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/search.py +1025 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/verify.py +378 -0
- synkit/Chem/Mapper/solvers/exact/edit_support.py +375 -0
- synkit/Chem/Mapper/solvers/exact/hybrid.py +224 -0
- synkit/Chem/Mapper/solvers/exact/hydrogen.py +264 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/branching.py +499 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumerate.py +1050 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumeration_result.py +30 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/kernel.py +256 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/milp.py +194 -0
- synkit/Chem/Mapper/solvers/exact/native/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/native/build.py +154 -0
- synkit/Chem/Mapper/solvers/exact/native/candidates.py +593 -0
- synkit/Chem/Mapper/solvers/exact/native/canonical.py +396 -0
- synkit/Chem/Mapper/solvers/exact/native/disk_frontier.py +415 -0
- synkit/Chem/Mapper/solvers/exact/native/frontier.py +390 -0
- synkit/Chem/Mapper/solvers/exact/native/hydrogen_quotient.py +213 -0
- synkit/Chem/Mapper/solvers/exact/native/its.py +528 -0
- synkit/Chem/Mapper/solvers/exact/native/native_distance.cpp +2803 -0
- synkit/Chem/Mapper/solvers/exact/native/orbit_aggregation.py +328 -0
- synkit/Chem/Mapper/solvers/exact/native/parallel.py +205 -0
- synkit/Chem/Mapper/solvers/exact/native/pmcd.py +203 -0
- synkit/Chem/Mapper/solvers/exact/native/runtime.py +40 -0
- synkit/Chem/Mapper/solvers/exact/native/search.py +294 -0
- synkit/Chem/Mapper/solvers/exact/native/separator.py +224 -0
- synkit/Chem/Mapper/solvers/exact/native_build.py +12 -0
- synkit/Chem/Mapper/solvers/exact/pabs/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/pabs/cost_lattice.py +43 -0
- synkit/Chem/Mapper/solvers/exact/pabs/factor_spectrum.py +110 -0
- synkit/Chem/Mapper/solvers/exact/pabs/multi_shell.py +368 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation.py +679 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_bounds.py +436 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_limits.py +13 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_search.py +856 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_symmetry.py +66 -0
- synkit/Chem/Mapper/solvers/exact/pabs/residual_typed_bonds.py +136 -0
- synkit/Chem/Mapper/solvers/exact/pabs/reward_frontier.py +201 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_bound.py +258 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_spectrum.py +308 -0
- synkit/Chem/Mapper/solvers/exact/pabs/sparse_reward_bound.py +207 -0
- synkit/Chem/Mapper/solvers/exact/pabs/suffix_spectrum.py +299 -0
- synkit/Chem/Mapper/solvers/exact/search.py +55 -0
- synkit/Chem/Mapper/solvers/exact/seeds/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed.py +104 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_fragments.py +148 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_relaxation.py +181 -0
- synkit/Chem/Mapper/solvers/exact/symmetry.py +223 -0
- synkit/Chem/Mapper/solvers/native/__init__.py +4 -0
- synkit/Chem/Mapper/solvers/native/assignment.py +99 -0
- synkit/Chem/Mapper/solvers/native/astar.py +22 -0
- synkit/Chem/Mapper/solvers/native/build.py +385 -0
- synkit/Chem/Mapper/solvers/native/classification.py +641 -0
- synkit/Chem/Mapper/solvers/native/core.py +378 -0
- synkit/Chem/Mapper/solvers/native/cpp/CMakeLists.txt +120 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/map_reaction.cpp +29 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/slap_graph.cpp +63 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/assignment/assignment.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/astar.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/bound.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/pmcd_witness.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/runtime.h +130 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/hydrogen/hydrogen.h +73 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mapper.h +175 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mces/mces.h +9 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/pabs/seed.h +34 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/reaction/reaction.h +30 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/sepdp/sepdp.h +21 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/slap.h +72 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/solvers/solvers.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/classification.h +140 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/cpabs.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/assignment/abb.cpp +302 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/CMakeLists.txt +12 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/README.md +47 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar.cpp +228 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar_graph.cpp +37 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/bound.cpp +212 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/dispatch.cpp +272 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/pmcd_witness.cpp +36 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/hydrogen/hydrogen.cpp +380 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/README.md +57 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/mces.cpp +287 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/bridge.cpp +334 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/chemical_floor.inc +181 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/endpoint_symmetry.inc +104 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/exact_helpers.h +20 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_assignment_certificate.h +165 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_certificate.h +125 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_model.h +365 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_provider.inc +319 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_rounding.inc +170 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_test_hooks.h +342 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/objective_reduction.inc +137 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/overlap_dual.inc +351 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/profile_seed.inc +214 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/seed_heuristics.inc +640 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_embedding.cpp +430 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_root_lp.h +176 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/test_hooks.inc +262 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/reaction/reaction.cpp +611 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/README.md +61 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/sepdp.cpp +253 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/slap.cpp +810 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/formulation.h +138 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/maxsat.cpp +526 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/ortools.cpp +475 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/seed.h +80 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/weighted_cnf.h +256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/README.md +43 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/dfs.cpp +123 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/edit_support.cpp +224 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification.cpp +553 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_pipeline.cpp +124 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_stream.h +13 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/cpabs.cpp +455 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/edge_deck.cpp +743 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naugraph.c +732 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.c +94 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.h +49 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.c +1771 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.h +133 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nautil.c +750 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naututil.h +355 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.c +1256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.h +1544 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.c +1131 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.h +70 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/sorttemplates.c +580 -0
- synkit/Chem/Mapper/solvers/native/hydrogen.py +711 -0
- synkit/Chem/Mapper/solvers/native/implicit.py +506 -0
- synkit/Chem/Mapper/solvers/native/implicit_certificate.py +187 -0
- synkit/Chem/Mapper/solvers/native/implicit_preparation.py +309 -0
- synkit/Chem/Mapper/solvers/native/lib/synkit_mapper.dll +0 -0
- synkit/Chem/Mapper/solvers/native/mces.py +16 -0
- synkit/Chem/Mapper/solvers/native/reaction.py +179 -0
- synkit/Chem/Mapper/solvers/native/reaction_build.py +277 -0
- synkit/Chem/Mapper/solvers/native/reaction_text.py +26 -0
- synkit/Chem/Mapper/solvers/native/runtime.py +242 -0
- synkit/Chem/Mapper/solvers/native/sepdp.py +47 -0
- synkit/Chem/Mapper/solvers/native/slap.py +266 -0
- synkit/Chem/Mapper/solvers/native/solvers.py +67 -0
- synkit/Chem/Mapper/solvers/native/stereo.py +86 -0
- synkit/Chem/Mapper/solvers/native/supporting.py +34 -0
- synkit/Chem/Mapper/solvers/native/symmetry.py +91 -0
- synkit/Chem/Mapper/solvers/slap/__init__.py +29 -0
- synkit/Chem/Mapper/solvers/slap/lap.py +174 -0
- synkit/Chem/Mapper/solvers/slap/sequential.py +696 -0
- synkit/Chem/Mapper/validation/__init__.py +1 -0
- synkit/Chem/Mapper/validation/aam_validator.py +442 -0
- synkit/Chem/Mapper/validation/annotations.py +274 -0
- synkit/Chem/Mapper/validation/bonds.py +124 -0
- synkit/Chem/Mapper/validation/cohorts.py +72 -0
- synkit/Chem/Mapper/validation/identifiability.py +150 -0
- synkit/Chem/Mapper/validation/numerical_scope.py +36 -0
- synkit/Chem/Mapper/validation/orbits.py +137 -0
- synkit/Chem/Molecule/__init__.py +0 -0
- synkit/Chem/Molecule/_chirality_loci.py +165 -0
- synkit/Chem/Molecule/_chirality_types.py +231 -0
- synkit/Chem/Molecule/_helical_loci.py +167 -0
- synkit/Chem/Molecule/_stereo_axis_evidence.py +202 -0
- synkit/Chem/Molecule/_stereo_element_detection.py +193 -0
- synkit/Chem/Molecule/_stereo_orientation_constraints.py +511 -0
- synkit/Chem/Molecule/_tetrahedral_carriers.py +63 -0
- synkit/Chem/Molecule/atom_features.py +379 -0
- synkit/Chem/Molecule/chirality.py +1041 -0
- synkit/Chem/Molecule/cip_assignment.py +569 -0
- synkit/Chem/Molecule/cip_ranking.py +843 -0
- synkit/Chem/Molecule/coordinate_stereo.py +503 -0
- synkit/Chem/Molecule/derived_stereo_naming.py +165 -0
- synkit/Chem/Molecule/descriptors.py +452 -0
- synkit/Chem/Molecule/formula.py +249 -0
- synkit/Chem/Molecule/global_stereo.py +175 -0
- synkit/Chem/Molecule/graph_annotator.py +300 -0
- synkit/Chem/Molecule/standardize.py +817 -0
- synkit/Chem/Molecule/stereo_evidence.py +179 -0
- synkit/Chem/Molecule/stereo_perception.py +1032 -0
- synkit/Chem/Molecule/valence.py +123 -0
- synkit/Chem/Reaction/Mapper/__init__.py +44 -0
- synkit/Chem/Reaction/__init__.py +20 -0
- synkit/Chem/Reaction/aam_validator.py +5 -0
- synkit/Chem/Reaction/balance_check.py +138 -0
- synkit/Chem/Reaction/canon_rsmi.py +249 -0
- synkit/Chem/Reaction/cleaning.py +58 -0
- synkit/Chem/Reaction/deionize.py +199 -0
- synkit/Chem/Reaction/explicit_h_audit.py +232 -0
- synkit/Chem/Reaction/fix_aam.py +64 -0
- synkit/Chem/Reaction/neutralize.py +207 -0
- synkit/Chem/Reaction/radical_wildcard.py +224 -0
- synkit/Chem/Reaction/standardize.py +203 -0
- synkit/Chem/Reaction/tautomerize.py +205 -0
- synkit/Chem/__init__.py +1 -0
- synkit/Chem/utils.py +315 -0
- synkit/Data/__init__.py +0 -0
- synkit/Data/aldol.json.gz +1 -0
- synkit/Data/gen_partial_aam.py +147 -0
- synkit/Data/paracetamol.json.gz +1 -0
- synkit/Graph/Canon/__init__.py +16 -0
- synkit/Graph/Canon/_native/__init__.py +13 -0
- synkit/Graph/Canon/_native/build.py +93 -0
- synkit/Graph/Canon/_native/lib/synkit_canon.dll +0 -0
- synkit/Graph/Canon/_native/prepare.py +49 -0
- synkit/Graph/Canon/_native/runtime.py +140 -0
- synkit/Graph/Canon/_native/search.py +137 -0
- synkit/Graph/Canon/canon_algs.py +228 -0
- synkit/Graph/Canon/canon_graph.py +531 -0
- synkit/Graph/Canon/cpp/CMakeLists.txt +42 -0
- synkit/Graph/Canon/cpp/README.md +123 -0
- synkit/Graph/Canon/cpp/examples/canonical_graph.cpp +16 -0
- synkit/Graph/Canon/cpp/include/synkit_canon/canon.h +85 -0
- synkit/Graph/Canon/cpp/src/canonical.cpp +391 -0
- synkit/Graph/Canon/cpp/src/symmetry.h +83 -0
- synkit/Graph/Canon/cpp/tests/symmetry.cpp +93 -0
- synkit/Graph/Canon/exact.py +1020 -0
- synkit/Graph/Canon/exact_refinement.py +368 -0
- synkit/Graph/Canon/nauty.py +143 -0
- synkit/Graph/Context/__init__.py +0 -0
- synkit/Graph/Context/hier_context.py +244 -0
- synkit/Graph/Context/radius_expand.py +252 -0
- synkit/Graph/FG/__init__.py +19 -0
- synkit/Graph/FG/api.py +39 -0
- synkit/Graph/FG/audit.py +155 -0
- synkit/Graph/FG/catalog.py +919 -0
- synkit/Graph/FG/detector.py +288 -0
- synkit/Graph/FG/model.py +97 -0
- synkit/Graph/FG/recognizers.py +274 -0
- synkit/Graph/FG/ring_system.py +154 -0
- synkit/Graph/Feature/Descriptors/topology.py +857 -0
- synkit/Graph/Feature/Fingerprint/__init__.py +0 -0
- synkit/Graph/Feature/Fingerprint/wl_rxn_fps.py +222 -0
- synkit/Graph/Feature/__init__.py +5 -0
- synkit/Graph/Feature/graph_descriptors.py +323 -0
- synkit/Graph/Feature/graph_fps.py +96 -0
- synkit/Graph/Feature/graph_signature.py +239 -0
- synkit/Graph/Feature/hash_fps.py +133 -0
- synkit/Graph/Feature/morgan_fps.py +88 -0
- synkit/Graph/Feature/path_fps.py +81 -0
- synkit/Graph/Feature/wl_hash.py +134 -0
- synkit/Graph/Fusion/__init__.py +85 -0
- synkit/Graph/Fusion/candidate.py +559 -0
- synkit/Graph/Fusion/constructor.py +877 -0
- synkit/Graph/Fusion/identity.py +184 -0
- synkit/Graph/Fusion/interface.py +700 -0
- synkit/Graph/Fusion/search.py +241 -0
- synkit/Graph/Hyrogen/__init__.py +6 -0
- synkit/Graph/Hyrogen/_misc.py +591 -0
- synkit/Graph/Hyrogen/hcomplete.py +995 -0
- synkit/Graph/Hyrogen/hcomplete_legacy.py +368 -0
- synkit/Graph/Hyrogen/hcompletion_algorithms.py +713 -0
- synkit/Graph/Hyrogen/hextend.py +570 -0
- synkit/Graph/Hyrogen/hextend_legacy.py +215 -0
- synkit/Graph/ITS/__init__.py +4 -0
- synkit/Graph/ITS/its_builder.py +120 -0
- synkit/Graph/ITS/its_construction.py +719 -0
- synkit/Graph/ITS/its_decompose.py +572 -0
- synkit/Graph/ITS/its_destruction.py +331 -0
- synkit/Graph/ITS/its_expand.py +1251 -0
- synkit/Graph/ITS/its_relabel.py +187 -0
- synkit/Graph/ITS/its_reverter.py +356 -0
- synkit/Graph/ITS/normalize_aam.py +145 -0
- synkit/Graph/ITS/partial_its.py +238 -0
- synkit/Graph/ITS/rc_extractor.py +656 -0
- synkit/Graph/ITS/stereo.py +74 -0
- synkit/Graph/MTG/__init__.py +107 -0
- synkit/Graph/MTG/gluing.py +451 -0
- synkit/Graph/MTG/history.py +928 -0
- synkit/Graph/MTG/inventory.py +118 -0
- synkit/Graph/MTG/local.py +447 -0
- synkit/Graph/MTG/mcs_matcher.py +246 -0
- synkit/Graph/MTG/mtg.py +611 -0
- synkit/Graph/MTG/mtg_explore.py +74 -0
- synkit/Graph/MTG/observation.py +209 -0
- synkit/Graph/MTG/process.py +577 -0
- synkit/Graph/MTG/queries.py +66 -0
- synkit/Graph/MTG/realization.py +95 -0
- synkit/Graph/MTG/series_parallel.py +107 -0
- synkit/Graph/MTG/utils.py +424 -0
- synkit/Graph/Matcher/__init__.py +10 -0
- synkit/Graph/Matcher/approx_mcs.py +1264 -0
- synkit/Graph/Matcher/auto_est.py +736 -0
- synkit/Graph/Matcher/automorphism.py +314 -0
- synkit/Graph/Matcher/batch_cluster.py +224 -0
- synkit/Graph/Matcher/dedup_matches.py +247 -0
- synkit/Graph/Matcher/graph_cluster.py +191 -0
- synkit/Graph/Matcher/graph_matcher.py +312 -0
- synkit/Graph/Matcher/graph_morphism.py +421 -0
- synkit/Graph/Matcher/mcs_matcher.py +804 -0
- synkit/Graph/Matcher/multi_turbo_iso.py +186 -0
- synkit/Graph/Matcher/orbit.py +284 -0
- synkit/Graph/Matcher/partial_matcher.py +694 -0
- synkit/Graph/Matcher/sing.py +544 -0
- synkit/Graph/Matcher/subgraph_matcher.py +812 -0
- synkit/Graph/Matcher/turbo_iso.py +272 -0
- synkit/Graph/Matcher/wl_sel.py +537 -0
- synkit/Graph/Mech/__init__.py +26 -0
- synkit/Graph/Mech/conversion.py +1466 -0
- synkit/Graph/Mech/conversion_debug.py +237 -0
- synkit/Graph/Mech/electron_accounting.py +200 -0
- synkit/Graph/Mech/lwg_editor.py +406 -0
- synkit/Graph/Mech/lwg_ops.py +313 -0
- synkit/Graph/Morphism/__init__.py +99 -0
- synkit/Graph/Morphism/constraints.py +460 -0
- synkit/Graph/Morphism/llg.py +999 -0
- synkit/Graph/Morphism/morphism.py +349 -0
- synkit/Graph/Morphism/stereo.py +258 -0
- synkit/Graph/Morphism/stereo_morphism.py +383 -0
- synkit/Graph/Morphism/stereo_morphism_helpers.py +957 -0
- synkit/Graph/Morphism/stereo_morphism_types.py +117 -0
- synkit/Graph/Stereo/__init__.py +376 -0
- synkit/Graph/Stereo/_descriptor_core.py +207 -0
- synkit/Graph/Stereo/_descriptor_serialization.py +138 -0
- synkit/Graph/Stereo/canonical.py +648 -0
- synkit/Graph/Stereo/changes.py +964 -0
- synkit/Graph/Stereo/composition.py +391 -0
- synkit/Graph/Stereo/configured.py +946 -0
- synkit/Graph/Stereo/couplings.py +245 -0
- synkit/Graph/Stereo/descriptors.py +1030 -0
- synkit/Graph/Stereo/enumeration.py +597 -0
- synkit/Graph/Stereo/extended_descriptors.py +406 -0
- synkit/Graph/Stereo/global_configured.py +152 -0
- synkit/Graph/Stereo/global_stereo.py +304 -0
- synkit/Graph/Stereo/identity.py +648 -0
- synkit/Graph/Stereo/interchange.py +496 -0
- synkit/Graph/Stereo/legacy.py +460 -0
- synkit/Graph/Stereo/matching.py +899 -0
- synkit/Graph/Stereo/native.py +154 -0
- synkit/Graph/Stereo/orbits.py +668 -0
- synkit/Graph/Stereo/outcomes.py +99 -0
- synkit/Graph/Stereo/pairwise.py +350 -0
- synkit/Graph/Stereo/rdkit_adapter.py +662 -0
- synkit/Graph/Stereo/rdkit_identity.py +118 -0
- synkit/Graph/Stereo/rdkit_resonance.py +140 -0
- synkit/Graph/Stereo/reaction_interchange.py +266 -0
- synkit/Graph/Stereo/semantics.py +296 -0
- synkit/Graph/Stereo/supports.py +257 -0
- synkit/Graph/Stereo/wire.py +339 -0
- synkit/Graph/Wildcard/__init__.py +0 -0
- synkit/Graph/Wildcard/fuse_graph.py +156 -0
- synkit/Graph/Wildcard/graph_wc.py +303 -0
- synkit/Graph/Wildcard/its_merge.py +857 -0
- synkit/Graph/Wildcard/radwc.py +114 -0
- synkit/Graph/Wildcard/wc_matcher.py +576 -0
- synkit/Graph/Wildcard/wildcard.py +225 -0
- synkit/Graph/__init__.py +17 -0
- synkit/Graph/canon_graph.py +14 -0
- synkit/Graph/syn_graph.py +199 -0
- synkit/Graph/utils.py +324 -0
- synkit/IO/__init__.py +4 -0
- synkit/IO/chem_converter.py +1059 -0
- synkit/IO/combinatorial/__init__.py +8 -0
- synkit/IO/combinatorial/gml_to_graph.py +223 -0
- synkit/IO/combinatorial/graph_to_gml.py +280 -0
- synkit/IO/combinatorial/graph_to_smarts.py +186 -0
- synkit/IO/combinatorial/smarts_expander.py +147 -0
- synkit/IO/combinatorial/smarts_generalizer.py +133 -0
- synkit/IO/combinatorial/smarts_to_graph.py +179 -0
- synkit/IO/conversion.py +42 -0
- synkit/IO/data_io.py +269 -0
- synkit/IO/data_process.py +143 -0
- synkit/IO/debug.py +73 -0
- synkit/IO/gml_to_nx.py +150 -0
- synkit/IO/graph_to_mol.py +199 -0
- synkit/IO/mol_to_graph.py +1105 -0
- synkit/IO/mol_to_graph_chemistry.py +545 -0
- synkit/IO/nx_to_gml.py +209 -0
- synkit/IO/smiles_to_id.py +123 -0
- synkit/Mechanism/__init__.py +151 -0
- synkit/Mechanism/adapters.py +136 -0
- synkit/Mechanism/audit.py +323 -0
- synkit/Mechanism/benchmark.py +638 -0
- synkit/Mechanism/compatibility.py +13 -0
- synkit/Mechanism/drawing.py +85 -0
- synkit/Mechanism/electron_models.py +725 -0
- synkit/Mechanism/equivalence.py +521 -0
- synkit/Mechanism/evidence.py +262 -0
- synkit/Mechanism/interchange.py +141 -0
- synkit/Mechanism/model.py +918 -0
- synkit/Mechanism/neighbor_stereo.py +312 -0
- synkit/Mechanism/radical_data.py +740 -0
- synkit/Mechanism/replay.py +986 -0
- synkit/Mechanism/schema.py +264 -0
- synkit/Mechanism/stereo_state.py +416 -0
- synkit/Mechanism/symbols.py +91 -0
- synkit/Rule/Apply/__init__.py +35 -0
- synkit/Rule/Apply/conditions.py +45 -0
- synkit/Rule/Apply/dpo.py +998 -0
- synkit/Rule/Apply/rule_matcher.py +218 -0
- synkit/Rule/Apply/validation.py +354 -0
- synkit/Rule/Compose/__init__.py +106 -0
- synkit/Rule/Compose/_identity.py +43 -0
- synkit/Rule/Compose/composition.py +976 -0
- synkit/Rule/Compose/laws.py +439 -0
- synkit/Rule/Compose/search.py +771 -0
- synkit/Rule/Compose/synrule.py +170 -0
- synkit/Rule/Modify/__init__.py +0 -0
- synkit/Rule/Modify/implict_rule.py +56 -0
- synkit/Rule/Modify/longest_path.py +92 -0
- synkit/Rule/Modify/molecule_rule.py +115 -0
- synkit/Rule/Modify/prune_templates.py +78 -0
- synkit/Rule/Modify/rule_utils.py +194 -0
- synkit/Rule/Modify/strip_rule.py +97 -0
- synkit/Rule/__init__.py +28 -0
- synkit/Rule/generic_stereo.py +884 -0
- synkit/Rule/stereo_identity.py +271 -0
- synkit/Rule/syn_rule.py +1090 -0
- synkit/Synthesis/MSR/__init__.py +0 -0
- synkit/Synthesis/MSR/path_finder.py +239 -0
- synkit/Synthesis/Metrics/__init__.py +0 -0
- synkit/Synthesis/Metrics/_base.py +52 -0
- synkit/Synthesis/Metrics/_plot.py +129 -0
- synkit/Synthesis/Metrics/_ranking.py +179 -0
- synkit/Synthesis/RBL/__init__.py +80 -0
- synkit/Synthesis/RBL/engine.py +1249 -0
- synkit/Synthesis/RBL/matching.py +652 -0
- synkit/Synthesis/RBL/overlap.py +336 -0
- synkit/Synthesis/RBL/pipeline.py +376 -0
- synkit/Synthesis/RBL/policy.py +139 -0
- synkit/Synthesis/RBL/proof.py +370 -0
- synkit/Synthesis/RBL/reaction.py +506 -0
- synkit/Synthesis/RBL/state.py +169 -0
- synkit/Synthesis/RBL/validation.py +1060 -0
- synkit/Synthesis/Reactor/__init__.py +60 -0
- synkit/Synthesis/Reactor/core/__init__.py +1 -0
- synkit/Synthesis/Reactor/core/engine.py +967 -0
- synkit/Synthesis/Reactor/core/product.py +621 -0
- synkit/Synthesis/Reactor/core/rewrite.py +561 -0
- synkit/Synthesis/Reactor/core/strategy.py +44 -0
- synkit/Synthesis/Reactor/matching/__init__.py +1 -0
- synkit/Synthesis/Reactor/matching/mixin.py +920 -0
- synkit/Synthesis/Reactor/matching/policy.py +345 -0
- synkit/Synthesis/Reactor/matching/symmetry.py +309 -0
- synkit/Synthesis/Reactor/output/__init__.py +1 -0
- synkit/Synthesis/Reactor/output/deduplication.py +703 -0
- synkit/Synthesis/Reactor/output/policy.py +16 -0
- synkit/Synthesis/Reactor/output/serialization.py +485 -0
- synkit/Synthesis/Reactor/output/structural.py +893 -0
- synkit/Synthesis/Reactor/stereo/__init__.py +1 -0
- synkit/Synthesis/Reactor/stereo/assignment.py +35 -0
- synkit/Synthesis/Reactor/stereo/mixin.py +780 -0
- synkit/Synthesis/Reactor/variants/__init__.py +1 -0
- synkit/Synthesis/Reactor/variants/imbalanced.py +180 -0
- synkit/Synthesis/Reactor/variants/partial.py +84 -0
- synkit/Synthesis/Reactor/workflow/__init__.py +1 -0
- synkit/Synthesis/Reactor/workflow/batch.py +550 -0
- synkit/Synthesis/Reactor/workflow/benchmark.py +143 -0
- synkit/Synthesis/Reactor/workflow/postprocess.py +267 -0
- synkit/Synthesis/Reactor/workflow/rule_filter.py +210 -0
- synkit/Synthesis/__init__.py +0 -0
- synkit/Synthesis/reactor_utils.py +316 -0
- synkit/Utils/__init__.py +0 -0
- synkit/Utils/utils.py +172 -0
- synkit/Vis/__init__.py +91 -0
- synkit/Vis/crn/__init__.py +40 -0
- synkit/Vis/epd/__init__.py +20 -0
- synkit/Vis/epd/arrows.py +425 -0
- synkit/Vis/epd/chem.py +197 -0
- synkit/Vis/epd/constants.py +83 -0
- synkit/Vis/epd/layout.py +283 -0
- synkit/Vis/epd/mapping.py +51 -0
- synkit/Vis/epd/models.py +136 -0
- synkit/Vis/epd/render.py +543 -0
- synkit/Vis/epd/utils.py +108 -0
- synkit/Vis/epd/visualizer.py +811 -0
- synkit/Vis/graph_visualizer.py +375 -0
- synkit/Vis/its/__init__.py +19 -0
- synkit/Vis/its/drawer.py +615 -0
- synkit/Vis/its_drawer.py +35 -0
- synkit/Vis/molecule/__init__.py +31 -0
- synkit/Vis/molecule/drawer.py +563 -0
- synkit/Vis/molecule/reaction.py +285 -0
- synkit/Vis/molecule_drawer.py +33 -0
- synkit/Vis/mtg/__init__.py +17 -0
- synkit/Vis/mtg/drawer.py +769 -0
- synkit/Vis/mtg_drawer.py +34 -0
- synkit/Vis/pdf_writer.py +146 -0
- synkit/Vis/reaction/__init__.py +19 -0
- synkit/Vis/reaction/rule.py +141 -0
- synkit/Vis/reaction/rxn.py +532 -0
- synkit/Vis/reaction_drawer.py +41 -0
- synkit/Vis/space/__init__.py +17 -0
- synkit/Vis/space/chemical.py +80 -0
- synkit/Vis/space/embedding.py +87 -0
- synkit/Vis/vis_synedu/Vis/__init__.py +7 -0
- synkit/Vis/vis_synedu/Vis/dpo.py +862 -0
- synkit/Vis/vis_synedu/rxn_vis.py +377 -0
- synkit/Vis/vis_synedu/vis.py +501 -0
- synkit/Vis/visual_drawer.py +215 -0
- synkit/Vis/visual_model.py +520 -0
- synkit/__init__.py +3 -0
- synkit/_native.py +91 -0
- synkit/examples.py +50 -0
- synkit/version.py +23 -0
- synkit-1.6.5.dist-info/METADATA +156 -0
- synkit-1.6.5.dist-info/RECORD +636 -0
- synkit-1.6.5.dist-info/WHEEL +4 -0
- synkit-1.6.5.dist-info/licenses/LICENSE +21 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- 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,123 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Protocol, runtime_checkable
|
|
4
|
+
|
|
5
|
+
from rdkit import Chem
|
|
6
|
+
from rdkit.Chem import rdchem as rdchem
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class _AtomLike(Protocol):
|
|
11
|
+
"""Minimal protocol RDKit atoms satisfy (duck-typed for typing tools)."""
|
|
12
|
+
|
|
13
|
+
def GetValence(self, which: rdchem.ValenceType | int = ...) -> int: ...
|
|
14
|
+
def GetExplicitValence(self) -> int: ...
|
|
15
|
+
def GetImplicitValence(self) -> int: ...
|
|
16
|
+
def GetNumImplicitHs(self) -> int: ...
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ValenceResolver:
|
|
20
|
+
"""Warning-free valence utilities for RDKit atoms.
|
|
21
|
+
|
|
22
|
+
These helpers retrieve **explicit**, **implicit**, and **total** valences
|
|
23
|
+
while silencing common deprecation or signature warnings across RDKit
|
|
24
|
+
versions. They first try the modern keyword-argument API and then
|
|
25
|
+
fall back to older call signatures or legacy methods.
|
|
26
|
+
|
|
27
|
+
Preferred (modern) RDKit API:
|
|
28
|
+
- ``atom.GetValence(which=rdchem.ValenceType.EXPLICIT)``
|
|
29
|
+
- ``atom.GetValence(which=rdchem.ValenceType.IMPLICIT)``
|
|
30
|
+
|
|
31
|
+
Fallbacks maintain compatibility with older wrappers:
|
|
32
|
+
- ``atom.GetValence(rdchem.ValenceType.EXPLICIT)`` (positional)
|
|
33
|
+
- ``atom.GetExplicitValence()``
|
|
34
|
+
- ``atom.GetImplicitValence()``
|
|
35
|
+
- ``atom.GetNumImplicitHs()`` (as a last resort for implicit)
|
|
36
|
+
|
|
37
|
+
.. rubric:: Notes
|
|
38
|
+
|
|
39
|
+
* Returned values are coerced to Python ``int`` and guaranteed non-negative,
|
|
40
|
+
with ``0`` returned if all strategies fail.
|
|
41
|
+
* Values reflect the current atom state and must be queried again after
|
|
42
|
+
changes to hydrogen counts, aromaticity, or bond orders.
|
|
43
|
+
* ``Chem.Atom`` is an alias of ``rdchem.Atom``, but a structural duck-type
|
|
44
|
+
``_AtomLike`` protocol is provided for static typing tools.
|
|
45
|
+
|
|
46
|
+
.. rubric:: Examples
|
|
47
|
+
|
|
48
|
+
>>> from rdkit import Chem
|
|
49
|
+
>>> m = Chem.MolFromSmiles("CCO")
|
|
50
|
+
>>> a = m.GetAtomWithIdx(1) # central carbon
|
|
51
|
+
>>> ValenceResolver.explicit(a) >= 0
|
|
52
|
+
True
|
|
53
|
+
>>> ValenceResolver.total(a) == ValenceResolver.explicit(a) + ValenceResolver.implicit(a)
|
|
54
|
+
True
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def explicit(atom: Chem.Atom | _AtomLike) -> int:
|
|
59
|
+
"""Return the **explicit valence** of an atom.
|
|
60
|
+
|
|
61
|
+
Tries modern ``GetValence(which=EXPLICIT)`` first, then older positional
|
|
62
|
+
form, then ``GetExplicitValence()``. Returns ``0`` on failure.
|
|
63
|
+
|
|
64
|
+
:param atom: RDKit atom instance.
|
|
65
|
+
:type atom: rdchem.Atom
|
|
66
|
+
:return: Explicit valence (non-negative integer).
|
|
67
|
+
:rtype: int
|
|
68
|
+
"""
|
|
69
|
+
# Modern keyword form (preferred; avoids RDKit warnings)
|
|
70
|
+
try:
|
|
71
|
+
return int(atom.GetValence(which=rdchem.ValenceType.EXPLICIT)) # type: ignore[call-arg]
|
|
72
|
+
except TypeError:
|
|
73
|
+
# Some RDKit builds don't accept the kwarg form
|
|
74
|
+
try:
|
|
75
|
+
return int(atom.GetValence(rdchem.ValenceType.EXPLICIT)) # type: ignore[arg-type]
|
|
76
|
+
except Exception:
|
|
77
|
+
# Legacy explicit valence API
|
|
78
|
+
try:
|
|
79
|
+
return int(atom.GetExplicitValence())
|
|
80
|
+
except Exception:
|
|
81
|
+
return 0
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def implicit(atom: Chem.Atom | _AtomLike) -> int:
|
|
85
|
+
"""Return the **implicit valence** of an atom.
|
|
86
|
+
|
|
87
|
+
Tries modern ``GetValence(which=IMPLICIT)`` first, then older positional
|
|
88
|
+
form, then ``GetImplicitValence()``, finally falls back to the number of
|
|
89
|
+
implicit hydrogens if needed. Returns ``0`` on failure.
|
|
90
|
+
|
|
91
|
+
:param atom: RDKit atom instance.
|
|
92
|
+
:type atom: rdchem.Atom
|
|
93
|
+
:return: Implicit valence (non-negative integer).
|
|
94
|
+
:rtype: int
|
|
95
|
+
"""
|
|
96
|
+
# Modern keyword form (preferred)
|
|
97
|
+
try:
|
|
98
|
+
return int(atom.GetValence(which=rdchem.ValenceType.IMPLICIT)) # type: ignore[call-arg]
|
|
99
|
+
except TypeError:
|
|
100
|
+
# Older builds without kwarg support
|
|
101
|
+
try:
|
|
102
|
+
return int(atom.GetValence(rdchem.ValenceType.IMPLICIT)) # type: ignore[arg-type]
|
|
103
|
+
except Exception:
|
|
104
|
+
# Legacy implicit valence API
|
|
105
|
+
try:
|
|
106
|
+
return int(atom.GetImplicitValence())
|
|
107
|
+
except Exception:
|
|
108
|
+
# As a last resort, approximate with implicit Hs
|
|
109
|
+
try:
|
|
110
|
+
return int(atom.GetNumImplicitHs())
|
|
111
|
+
except Exception:
|
|
112
|
+
return 0
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def total(atom: Chem.Atom | _AtomLike) -> int:
|
|
116
|
+
"""Return the **total valence** (explicit + implicit).
|
|
117
|
+
|
|
118
|
+
:param atom: RDKit atom instance.
|
|
119
|
+
:type atom: rdchem.Atom
|
|
120
|
+
:return: Total valence as ``explicit(atom) + implicit(atom)``.
|
|
121
|
+
:rtype: int
|
|
122
|
+
"""
|
|
123
|
+
return ValenceResolver.explicit(atom) + ValenceResolver.implicit(atom)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Compatibility alias for :mod:`synkit.Chem.Mapper`.
|
|
2
|
+
|
|
3
|
+
Atom-to-atom mapping is now a top-level chemistry concern. New code should
|
|
4
|
+
import from :mod:`synkit.Chem.Mapper`; this package preserves the former
|
|
5
|
+
``synkit.Chem.Reaction.Mapper`` imports, including imports of its submodules.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
import pkgutil
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
from synkit.Chem import Mapper as _mapper
|
|
15
|
+
from synkit.Chem.Mapper import * # noqa: F401,F403
|
|
16
|
+
|
|
17
|
+
__all__ = _mapper.__all__
|
|
18
|
+
__path__ = _mapper.__path__
|
|
19
|
+
|
|
20
|
+
for _solver_name in ("exact", "slap", "_native"):
|
|
21
|
+
globals()[_solver_name] = getattr(_mapper, _solver_name)
|
|
22
|
+
|
|
23
|
+
# Bind every canonical mapper module to its historical name. Besides keeping
|
|
24
|
+
# deep imports working, this ensures classes imported through old and new
|
|
25
|
+
# paths have the same identity.
|
|
26
|
+
for _module_info in pkgutil.walk_packages(
|
|
27
|
+
_mapper.__path__, prefix=f"{_mapper.__name__}."
|
|
28
|
+
):
|
|
29
|
+
_canonical_name = _module_info.name
|
|
30
|
+
_module = importlib.import_module(_canonical_name)
|
|
31
|
+
_suffix = _canonical_name.removeprefix(_mapper.__name__)
|
|
32
|
+
sys.modules[f"{__name__}{_suffix}"] = _module
|
|
33
|
+
if _suffix.count(".") == 1:
|
|
34
|
+
globals()[_suffix[1:]] = _module
|
|
35
|
+
|
|
36
|
+
# Include flat compatibility aliases that no longer have their own source file.
|
|
37
|
+
for _canonical_name, _module in list(sys.modules.items()):
|
|
38
|
+
if _canonical_name.startswith(f"{_mapper.__name__}."):
|
|
39
|
+
_suffix = _canonical_name.removeprefix(_mapper.__name__)
|
|
40
|
+
sys.modules[f"{__name__}{_suffix}"] = _module
|
|
41
|
+
if _suffix.count(".") == 1:
|
|
42
|
+
globals()[_suffix[1:]] = _module
|
|
43
|
+
|
|
44
|
+
del _canonical_name, _mapper, _module, _module_info, _suffix, _solver_name
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .aam_validator import AAMValidator
|
|
2
|
+
from .explicit_h_audit import (
|
|
3
|
+
ExplicitHydrogenReactionAudit,
|
|
4
|
+
MappedBondChange,
|
|
5
|
+
audit_explicit_h_reaction,
|
|
6
|
+
reaction_smiles_from_annotated_text,
|
|
7
|
+
)
|
|
8
|
+
from synkit.Chem.utils import remove_explicit_H_from_rsmi
|
|
9
|
+
|
|
10
|
+
# from .standardize import Standardize
|
|
11
|
+
# from .canon_rsmi import CanonRSMI
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AAMValidator",
|
|
15
|
+
"ExplicitHydrogenReactionAudit",
|
|
16
|
+
"MappedBondChange",
|
|
17
|
+
"audit_explicit_h_reaction",
|
|
18
|
+
"reaction_smiles_from_annotated_text",
|
|
19
|
+
"remove_explicit_H_from_rsmi",
|
|
20
|
+
]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from rdkit import Chem
|
|
2
|
+
from rdkit.Chem.rdMolDescriptors import CalcMolFormula
|
|
3
|
+
from joblib import Parallel, delayed
|
|
4
|
+
from typing import List, Dict, Union, Tuple, Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BalanceReactionCheck:
|
|
8
|
+
"""Check elemental balance of chemical reactions in SMILES format.
|
|
9
|
+
|
|
10
|
+
Supports checking single reactions, reaction dictionaries, or lists
|
|
11
|
+
in parallel.
|
|
12
|
+
|
|
13
|
+
:ivar n_jobs: Number of parallel jobs for batch checking.
|
|
14
|
+
:ivar verbose: Verbosity level for joblib.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, n_jobs: int = 4, verbose: int = 0) -> None:
|
|
18
|
+
"""
|
|
19
|
+
:param n_jobs: Number of parallel jobs for batch balance checks. Defaults to 4.
|
|
20
|
+
:type n_jobs: int
|
|
21
|
+
:param verbose: Verbosity level passed to joblib. Defaults to 0.
|
|
22
|
+
:type verbose: int
|
|
23
|
+
"""
|
|
24
|
+
self.n_jobs = n_jobs
|
|
25
|
+
self.verbose = verbose
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def get_combined_molecular_formula(smiles: str) -> str:
|
|
29
|
+
"""Compute the molecular formula of a SMILES.
|
|
30
|
+
|
|
31
|
+
:param smiles: SMILES string of the molecule.
|
|
32
|
+
:type smiles: str
|
|
33
|
+
:return: Elemental formula (e.g., "C6H6") or empty string if
|
|
34
|
+
invalid.
|
|
35
|
+
:rtype: str
|
|
36
|
+
"""
|
|
37
|
+
mol = Chem.MolFromSmiles(smiles)
|
|
38
|
+
if not mol:
|
|
39
|
+
return ""
|
|
40
|
+
return CalcMolFormula(mol)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def parse_input(
|
|
44
|
+
input_data: Union[str, List[Union[str, Dict[str, str]]]],
|
|
45
|
+
rsmi_column: str = "reactions",
|
|
46
|
+
) -> List[Dict[str, str]]:
|
|
47
|
+
"""Normalize input into a list of reaction‐dicts.
|
|
48
|
+
|
|
49
|
+
:param input_data: A single SMILES, list of SMILES, or list of dicts containing `rsmi_column`.
|
|
50
|
+
:type input_data: str or List[Union[str, Dict[str, str]]]
|
|
51
|
+
:param rsmi_column: Key in dicts for the reaction SMILES. Defaults to "reactions".
|
|
52
|
+
:type rsmi_column: str
|
|
53
|
+
:return: List of dicts with a single key `rsmi_column` mapping to each reaction.
|
|
54
|
+
:rtype: List[Dict[str, str]]
|
|
55
|
+
:raises ValueError: If `input_data` is neither str nor list.
|
|
56
|
+
"""
|
|
57
|
+
standardized: List[Dict[str, str]] = []
|
|
58
|
+
if isinstance(input_data, str):
|
|
59
|
+
standardized.append({rsmi_column: input_data})
|
|
60
|
+
elif isinstance(input_data, list):
|
|
61
|
+
for item in input_data:
|
|
62
|
+
if isinstance(item, str):
|
|
63
|
+
standardized.append({rsmi_column: item})
|
|
64
|
+
elif isinstance(item, dict) and rsmi_column in item:
|
|
65
|
+
standardized.append(item)
|
|
66
|
+
else:
|
|
67
|
+
raise ValueError("Unsupported input type for balance checking")
|
|
68
|
+
return standardized
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def parse_reaction(reaction_smiles: str) -> Tuple[str, str]:
|
|
72
|
+
"""Split a reaction SMILES into reactant and product SMILES strings.
|
|
73
|
+
|
|
74
|
+
:param reaction_smiles: Reaction SMILES in 'reactants>>products'
|
|
75
|
+
format.
|
|
76
|
+
:type reaction_smiles: str
|
|
77
|
+
:return: Tuple of (reactants, products) SMILES.
|
|
78
|
+
:rtype: Tuple[str, str]
|
|
79
|
+
"""
|
|
80
|
+
return tuple(reaction_smiles.split(">>"))
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def rsmi_balance_check(reaction_smiles: str) -> bool:
|
|
84
|
+
"""Determine if a reaction SMILES is elementally balanced.
|
|
85
|
+
|
|
86
|
+
:param reaction_smiles: Reaction SMILES in 'reactants>>products'
|
|
87
|
+
format.
|
|
88
|
+
:type reaction_smiles: str
|
|
89
|
+
:return: True if reactant and product formulas match, else
|
|
90
|
+
False.
|
|
91
|
+
:rtype: bool
|
|
92
|
+
"""
|
|
93
|
+
react, prod = BalanceReactionCheck.parse_reaction(reaction_smiles)
|
|
94
|
+
react_formula = BalanceReactionCheck.get_combined_molecular_formula(react)
|
|
95
|
+
prod_formula = BalanceReactionCheck.get_combined_molecular_formula(prod)
|
|
96
|
+
return react_formula == prod_formula
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def dict_balance_check(
|
|
100
|
+
reaction_dict: Dict[str, str], rsmi_column: str
|
|
101
|
+
) -> Dict[str, Any]:
|
|
102
|
+
"""Check balance for a single reaction dict, preserving original keys.
|
|
103
|
+
|
|
104
|
+
:param reaction_dict: Dict containing at least a `rsmi_column` key.
|
|
105
|
+
:type reaction_dict: Dict[str, str]
|
|
106
|
+
:param rsmi_column: Key for reaction SMILES in `reaction_dict`.
|
|
107
|
+
:type rsmi_column: str
|
|
108
|
+
:return: Original dict augmented with `"balanced": bool`.
|
|
109
|
+
:rtype: Dict[str, Any]
|
|
110
|
+
"""
|
|
111
|
+
rsmi = reaction_dict[rsmi_column]
|
|
112
|
+
balanced = BalanceReactionCheck.rsmi_balance_check(rsmi)
|
|
113
|
+
return {"balanced": balanced, **reaction_dict}
|
|
114
|
+
|
|
115
|
+
def dicts_balance_check(
|
|
116
|
+
self,
|
|
117
|
+
input_data: Union[str, List[Union[str, Dict[str, str]]]],
|
|
118
|
+
rsmi_column: str = "reactions",
|
|
119
|
+
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
|
|
120
|
+
"""Batch‐check balance for multiple reactions, in parallel.
|
|
121
|
+
|
|
122
|
+
:param input_data: Single reaction SMILES, list of SMILES, or
|
|
123
|
+
list of dicts.
|
|
124
|
+
:type input_data: Union[str, List[Union[str, Dict[str, str]]]]
|
|
125
|
+
:param rsmi_column: Key for reaction SMILES in each dict.
|
|
126
|
+
Defaults to "reactions".
|
|
127
|
+
:type rsmi_column: str
|
|
128
|
+
:return: Tuple (balanced_list, unbalanced_list) of dicts each
|
|
129
|
+
including `"balanced"`.
|
|
130
|
+
:rtype: Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]
|
|
131
|
+
"""
|
|
132
|
+
reactions = self.parse_input(input_data, rsmi_column)
|
|
133
|
+
results = Parallel(n_jobs=self.n_jobs, verbose=self.verbose)(
|
|
134
|
+
delayed(self.dict_balance_check)(rd, rsmi_column) for rd in reactions
|
|
135
|
+
)
|
|
136
|
+
balanced = [r for r in results if r["balanced"]]
|
|
137
|
+
unbalanced = [r for r in results if not r["balanced"]]
|
|
138
|
+
return balanced, unbalanced
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import networkx as nx
|
|
3
|
+
from rdkit import Chem
|
|
4
|
+
from rdkit.Chem import MolFromSmiles as _rdkit_MolFromSmiles
|
|
5
|
+
from typing import List, Tuple, Union, Optional
|
|
6
|
+
|
|
7
|
+
from synkit.Graph.canon_graph import GraphCanonicaliser
|
|
8
|
+
from synkit.IO import graph_to_smi, rsmi_to_graph
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CanonRSMI:
|
|
12
|
+
"""A **pure-Python / pure-NetworkX** utility for canonicalizing reaction
|
|
13
|
+
SMILES by expanding atom-maps and deterministically reindexing reaction
|
|
14
|
+
graphs.
|
|
15
|
+
|
|
16
|
+
Workflow
|
|
17
|
+
--------
|
|
18
|
+
1. **Expand atom-maps** on reactants to ensure each atom has a unique map ID.
|
|
19
|
+
2. **Convert** reaction SMILES to reactant/product NetworkX graphs.
|
|
20
|
+
3. **Canonicalize** the reactant graph using `GraphCanonicaliser` (generic or WL backend).
|
|
21
|
+
4. **Match** atom-map IDs to compute pairwise indices between reactants and products.
|
|
22
|
+
5. **Remap** the product graph to align with the canonical reactant ordering.
|
|
23
|
+
6. **Sync** each node’s `atom_map` attribute to its new graph index.
|
|
24
|
+
7. **Reassemble** the reaction SMILES from the canonical graphs.
|
|
25
|
+
|
|
26
|
+
Classes
|
|
27
|
+
-------
|
|
28
|
+
- `CanonRSMI` – Main interface for transforming any `reactants>>products` SMILES
|
|
29
|
+
into a canonicalized form, preserving all node and edge attributes.
|
|
30
|
+
|
|
31
|
+
.. rubric:: Example
|
|
32
|
+
|
|
33
|
+
>>> from canonical_rsm import CanonRSMI
|
|
34
|
+
>>> canon = CanonRSMI(backend='wl', wl_iterations=5)
|
|
35
|
+
>>> result = canon.canonicalise('[CH3:3][CH2:5][OH:10]>>[CH2:3]=[CH2:5].[OH2:10]')
|
|
36
|
+
>>> print(result.canonical_rsmi)
|
|
37
|
+
[OH:1][CH2:3][CH3:2]>>[CH2:2]=[CH2:3].[OH2:1]
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
backend: str = "wl",
|
|
43
|
+
wl_iterations: int = 3,
|
|
44
|
+
morgan_radius: int = 3,
|
|
45
|
+
node_attrs: List[str] = ("element", "aromatic", "charge", "hcount"),
|
|
46
|
+
):
|
|
47
|
+
self._canon = GraphCanonicaliser(
|
|
48
|
+
backend=backend,
|
|
49
|
+
wl_iterations=wl_iterations,
|
|
50
|
+
morgan_radius=morgan_radius,
|
|
51
|
+
node_attrs=node_attrs,
|
|
52
|
+
)
|
|
53
|
+
# internal storage
|
|
54
|
+
self._raw_rsmi: Optional[str] = None
|
|
55
|
+
self._canon_rsmi: Optional[str] = None
|
|
56
|
+
self._raw_reactant_graph: Optional[nx.Graph] = None
|
|
57
|
+
self._raw_product_graph: Optional[nx.Graph] = None
|
|
58
|
+
self._canon_reactant_graph: Optional[nx.Graph] = None
|
|
59
|
+
self._canon_product_graph: Optional[nx.Graph] = None
|
|
60
|
+
self._mapping_pairs: Optional[List[Tuple[int, int]]] = None
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def _mol_from_smiles(smi: str) -> Chem.Mol:
|
|
64
|
+
"""RDKit MolFromSmiles with explicit sanitize step."""
|
|
65
|
+
mol = _rdkit_MolFromSmiles(smi, sanitize=False)
|
|
66
|
+
Chem.SanitizeMol(mol)
|
|
67
|
+
return mol
|
|
68
|
+
|
|
69
|
+
def expand_aam(self, rsmi: str) -> str:
|
|
70
|
+
"""Assign new atom-map IDs to unmapped reactant atoms in
|
|
71
|
+
'reactants>>products' SMILES.
|
|
72
|
+
|
|
73
|
+
New IDs start at max(existing maps)+1.
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
reac_s, prod_s = rsmi.split(">>")
|
|
77
|
+
except ValueError:
|
|
78
|
+
raise ValueError("Input must be in 'reactants>>products' form")
|
|
79
|
+
|
|
80
|
+
reac_mols = [self._mol_from_smiles(s) for s in reac_s.split(".")]
|
|
81
|
+
prod_mols = [self._mol_from_smiles(s) for s in prod_s.split(".")]
|
|
82
|
+
|
|
83
|
+
existing = {
|
|
84
|
+
atom.GetAtomMapNum()
|
|
85
|
+
for mol in (*reac_mols, *prod_mols)
|
|
86
|
+
for atom in mol.GetAtoms()
|
|
87
|
+
if atom.GetAtomMapNum() > 0
|
|
88
|
+
}
|
|
89
|
+
next_id = max(existing, default=0) + 1
|
|
90
|
+
|
|
91
|
+
for mol in reac_mols:
|
|
92
|
+
for atom in mol.GetAtoms():
|
|
93
|
+
if atom.GetAtomMapNum() == 0:
|
|
94
|
+
atom.SetAtomMapNum(next_id)
|
|
95
|
+
next_id += 1
|
|
96
|
+
|
|
97
|
+
new_reac = ".".join(Chem.MolToSmiles(m, canonical=True) for m in reac_mols)
|
|
98
|
+
new_prod = ".".join(Chem.MolToSmiles(m, canonical=True) for m in prod_mols)
|
|
99
|
+
return f"{new_reac}>>{new_prod}"
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def sync_atom_map_with_index(G: nx.Graph) -> None:
|
|
103
|
+
"""
|
|
104
|
+
In-place: set each node's 'atom_map' attribute to its node ID.
|
|
105
|
+
"""
|
|
106
|
+
nx.set_node_attributes(G, {n: n for n in G.nodes()}, "atom_map")
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def get_aam_pairwise_indices(
|
|
110
|
+
G: nx.Graph, H: nx.Graph, aam_key: str = "atom_map"
|
|
111
|
+
) -> List[Tuple[int, int]]:
|
|
112
|
+
"""Return sorted list of (G_node, H_node) for shared atom-map IDs."""
|
|
113
|
+
gmap = {
|
|
114
|
+
data[aam_key]: n
|
|
115
|
+
for n, data in G.nodes(data=True)
|
|
116
|
+
if data.get(aam_key, 0) > 0
|
|
117
|
+
}
|
|
118
|
+
hmap = {
|
|
119
|
+
data[aam_key]: n
|
|
120
|
+
for n, data in H.nodes(data=True)
|
|
121
|
+
if data.get(aam_key, 0) > 0
|
|
122
|
+
}
|
|
123
|
+
common = sorted(gmap.keys() & hmap.keys())
|
|
124
|
+
return [(gmap[k], hmap[k]) for k in common]
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def remap_graph(
|
|
128
|
+
G: nx.Graph, node_map: Union[List[int], List[Tuple[int, int]]]
|
|
129
|
+
) -> nx.Graph:
|
|
130
|
+
"""Remap a product graph to match a canonical reactant ordering:
|
|
131
|
+
|
|
132
|
+
:param G: reactant graph
|
|
133
|
+
:type G: nx.Graph
|
|
134
|
+
:param node_map: Product node ordering or ``(new, old)`` node pairs.
|
|
135
|
+
:type node_map: list[int] | list[tuple[int, int]]
|
|
136
|
+
:return:
|
|
137
|
+
remapped product graph
|
|
138
|
+
:rtype: nx.Graph
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
if not node_map:
|
|
142
|
+
raise ValueError("node_map must be non-empty")
|
|
143
|
+
if isinstance(node_map[0], int):
|
|
144
|
+
mapping = {old: new for new, old in enumerate(node_map, start=1)}
|
|
145
|
+
else:
|
|
146
|
+
mapping = {old: new for new, old in node_map}
|
|
147
|
+
missing = set(mapping) - set(G.nodes())
|
|
148
|
+
if missing:
|
|
149
|
+
raise KeyError(f"Mappings refer to nodes not in G: {missing}")
|
|
150
|
+
return nx.relabel_nodes(G, mapping, copy=True)
|
|
151
|
+
|
|
152
|
+
def canonicalise(self, rsmi: str) -> "CanonRSMI":
|
|
153
|
+
"""
|
|
154
|
+
Full pipeline returning self with properties populated:
|
|
155
|
+
- raw_rsmi
|
|
156
|
+
- raw_reactant_graph, raw_product_graph
|
|
157
|
+
- mapping_pairs
|
|
158
|
+
- canonical_reactant_graph, canonical_product_graph
|
|
159
|
+
- canonical_rsmi
|
|
160
|
+
"""
|
|
161
|
+
# store raw
|
|
162
|
+
self._raw_rsmi = rsmi
|
|
163
|
+
# expand and build graphs
|
|
164
|
+
expanded = self.expand_aam(rsmi)
|
|
165
|
+
self._raw_reactant_graph, self._raw_product_graph = rsmi_to_graph(expanded)
|
|
166
|
+
# canonicalise reactants
|
|
167
|
+
self._canon_reactant_graph = self._canon.canonicalise_graph(
|
|
168
|
+
self._raw_reactant_graph
|
|
169
|
+
).canonical_graph
|
|
170
|
+
# map products
|
|
171
|
+
self._mapping_pairs = self.get_aam_pairwise_indices(
|
|
172
|
+
self._canon_reactant_graph, self._raw_product_graph
|
|
173
|
+
)
|
|
174
|
+
self._canon_product_graph = self.remap_graph(
|
|
175
|
+
self._raw_product_graph, self._mapping_pairs
|
|
176
|
+
)
|
|
177
|
+
# sync maps
|
|
178
|
+
self.sync_atom_map_with_index(self._canon_reactant_graph)
|
|
179
|
+
self.sync_atom_map_with_index(self._canon_product_graph)
|
|
180
|
+
# assemble output
|
|
181
|
+
self._canon_rsmi = (
|
|
182
|
+
f"{graph_to_smi(self._canon_reactant_graph)}>>"
|
|
183
|
+
f"{graph_to_smi(self._canon_product_graph)}"
|
|
184
|
+
)
|
|
185
|
+
return self
|
|
186
|
+
|
|
187
|
+
__call__ = canonicalise
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def raw_rsmi(self) -> Optional[str]:
|
|
191
|
+
"""Original SMILES before canonicalisation."""
|
|
192
|
+
return self._raw_rsmi
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def canonical_rsmi(self) -> Optional[str]:
|
|
196
|
+
"""Canonical SMILES after processing."""
|
|
197
|
+
return self._canon_rsmi
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def raw_reactant_graph(self) -> Optional[nx.Graph]:
|
|
201
|
+
"""NetworkX graph of raw reactants."""
|
|
202
|
+
return self._raw_reactant_graph
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def raw_product_graph(self) -> Optional[nx.Graph]:
|
|
206
|
+
"""NetworkX graph of raw products."""
|
|
207
|
+
return self._raw_product_graph
|
|
208
|
+
|
|
209
|
+
@property
|
|
210
|
+
def canonical_reactant_graph(self) -> Optional[nx.Graph]:
|
|
211
|
+
"""NetworkX graph of canonicalised reactants."""
|
|
212
|
+
return self._canon_reactant_graph
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def canonical_product_graph(self) -> Optional[nx.Graph]:
|
|
216
|
+
"""NetworkX graph of canonicalised products."""
|
|
217
|
+
return self._canon_product_graph
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def canonical_hash(self) -> Optional[str]:
|
|
221
|
+
"""Reaction-level hash combining reactant and product canonical
|
|
222
|
+
hashes."""
|
|
223
|
+
if not self._canon_reactant_graph or not self._canon_product_graph:
|
|
224
|
+
return None
|
|
225
|
+
h_reac = self._canon.canonical_signature(self._canon_reactant_graph)
|
|
226
|
+
h_prod = self._canon.canonical_signature(self._canon_product_graph)
|
|
227
|
+
return f"{h_reac}>>{h_prod}"
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def mapping_pairs(self) -> Optional[List[Tuple[int, int]]]:
|
|
231
|
+
"""List of atom-map index pairs between reactants and products."""
|
|
232
|
+
return self._mapping_pairs
|
|
233
|
+
|
|
234
|
+
def help(self) -> None: # pragma: no cover
|
|
235
|
+
"""Pretty-print the class doc and public methods with signatures."""
|
|
236
|
+
print(inspect.getdoc(self.__class__))
|
|
237
|
+
for meth in (
|
|
238
|
+
"expand_aam",
|
|
239
|
+
"canonicalise",
|
|
240
|
+
"get_aam_pairwise_indices",
|
|
241
|
+
"remap_graph",
|
|
242
|
+
):
|
|
243
|
+
print(f" • {meth}{inspect.signature(getattr(self, meth))}")
|
|
244
|
+
|
|
245
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
246
|
+
return (
|
|
247
|
+
f"<CanonRSMI backend={self._canon.backend!r} "
|
|
248
|
+
f"wl_iterations={self._canon._wl_k}>"
|
|
249
|
+
)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from synkit.Chem.Reaction.standardize import Standardize
|
|
3
|
+
from synkit.Chem.Reaction.balance_check import BalanceReactionCheck
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Cleaning:
|
|
7
|
+
"""Utilities for cleaning and filtering reaction SMILES lists."""
|
|
8
|
+
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
"""Initialize the Cleaning helper.
|
|
11
|
+
|
|
12
|
+
No instance attributes are used.
|
|
13
|
+
"""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def remove_duplicates(smiles_list: List[str]) -> List[str]:
|
|
18
|
+
"""Remove duplicate SMILES strings, preserving first occurrences.
|
|
19
|
+
|
|
20
|
+
:param smiles_list: List of reaction SMILES strings.
|
|
21
|
+
:type smiles_list: List[str]
|
|
22
|
+
:return: List of unique SMILES in original order.
|
|
23
|
+
:rtype: List[str]
|
|
24
|
+
"""
|
|
25
|
+
seen = set()
|
|
26
|
+
return [smi for smi in smiles_list if not (smi in seen or seen.add(smi))]
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def clean_smiles(smiles_list: List[str]) -> List[str]:
|
|
30
|
+
"""Standardize, balance‑check, and deduplicate reaction SMILES.
|
|
31
|
+
|
|
32
|
+
Steps:
|
|
33
|
+
1. Standardize each SMILES via `Standardize.standardize_rsmi`.
|
|
34
|
+
2. Keep only those that pass `BalanceReactionCheck.rsmi_balance_check`.
|
|
35
|
+
3. Remove duplicates preserving order.
|
|
36
|
+
|
|
37
|
+
:param smiles_list: List of reaction SMILES strings to clean.
|
|
38
|
+
:type smiles_list: List[str]
|
|
39
|
+
:return: Cleaned list of standardized, balanced, unique SMILES.
|
|
40
|
+
:rtype: List[str]
|
|
41
|
+
"""
|
|
42
|
+
standardizer = Standardize()
|
|
43
|
+
balance_checker = BalanceReactionCheck()
|
|
44
|
+
|
|
45
|
+
standardized: List[str] = []
|
|
46
|
+
for smi in smiles_list:
|
|
47
|
+
try:
|
|
48
|
+
std = standardizer.standardize_rsmi(smi, stereo=True)
|
|
49
|
+
if std:
|
|
50
|
+
standardized.append(std)
|
|
51
|
+
except Exception:
|
|
52
|
+
continue
|
|
53
|
+
|
|
54
|
+
balanced = [
|
|
55
|
+
smi for smi in standardized if balance_checker.rsmi_balance_check(smi)
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
return Cleaning.remove_duplicates(balanced)
|