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,662 @@
|
|
|
1
|
+
"""RDKit conversion for SynKit relative stereo descriptors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Iterable
|
|
6
|
+
|
|
7
|
+
from rdkit import Chem
|
|
8
|
+
|
|
9
|
+
from .descriptors import (
|
|
10
|
+
AtropBondStereo,
|
|
11
|
+
OctahedralStereo,
|
|
12
|
+
PlanarBondStereo,
|
|
13
|
+
SquarePlanarStereo,
|
|
14
|
+
StereoValue,
|
|
15
|
+
TetrahedralStereo,
|
|
16
|
+
TrigonalBipyramidalStereo,
|
|
17
|
+
descriptor_id,
|
|
18
|
+
virtual_reference,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# RDKit's square-planar permutation numbers describe arrangements relative to
|
|
22
|
+
# the atom's current local neighbor order; they are not global stereo labels.
|
|
23
|
+
# These position maps are the SP1/SP2/SP3 ligand-numbering table from RDKit's
|
|
24
|
+
# non-tetrahedral SMILES documentation. SynKit stores the resulting cyclic
|
|
25
|
+
# ligand order, whose identity is invariant under D4 rotations/reflections.
|
|
26
|
+
_SQUARE_PLANAR_POSITION_MAPS = {
|
|
27
|
+
1: (0, 1, 2, 3),
|
|
28
|
+
2: (0, 2, 1, 3),
|
|
29
|
+
3: (0, 1, 3, 2),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# A/B are the two axial positions and C/D/E are the cyclic equatorial
|
|
33
|
+
# positions in RDKit's documented TB table. Each value maps RDKit's current
|
|
34
|
+
# local neighbor order into that positional SynKit representation.
|
|
35
|
+
_TRIGONAL_BIPYRAMIDAL_POSITION_MAPS = {
|
|
36
|
+
1: (0, 4, 1, 2, 3),
|
|
37
|
+
2: (0, 4, 1, 3, 2),
|
|
38
|
+
3: (0, 3, 1, 2, 4),
|
|
39
|
+
4: (0, 3, 1, 4, 2),
|
|
40
|
+
5: (0, 2, 1, 3, 4),
|
|
41
|
+
6: (0, 2, 1, 4, 3),
|
|
42
|
+
7: (0, 1, 2, 3, 4),
|
|
43
|
+
8: (0, 1, 2, 4, 3),
|
|
44
|
+
9: (1, 4, 0, 2, 3),
|
|
45
|
+
10: (1, 3, 0, 2, 4),
|
|
46
|
+
11: (1, 4, 0, 3, 2),
|
|
47
|
+
12: (1, 3, 0, 4, 2),
|
|
48
|
+
13: (1, 2, 0, 3, 4),
|
|
49
|
+
14: (1, 2, 0, 4, 3),
|
|
50
|
+
15: (2, 4, 0, 1, 3),
|
|
51
|
+
16: (2, 3, 0, 1, 4),
|
|
52
|
+
17: (3, 4, 0, 1, 2),
|
|
53
|
+
18: (3, 4, 0, 2, 1),
|
|
54
|
+
19: (2, 3, 0, 4, 1),
|
|
55
|
+
20: (2, 4, 0, 3, 1),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# A/B are an opposite pair and C/D/E/F are the cyclic square in RDKit's
|
|
59
|
+
# documented OH table. As for SP/TBP, these are local-order transforms, not
|
|
60
|
+
# global labels and not SynKit descriptor identity.
|
|
61
|
+
_OCTAHEDRAL_POSITION_MAPS = {
|
|
62
|
+
1: (0, 5, 1, 2, 3, 4),
|
|
63
|
+
2: (0, 5, 1, 4, 3, 2),
|
|
64
|
+
3: (0, 4, 1, 2, 3, 5),
|
|
65
|
+
4: (0, 5, 1, 2, 4, 3),
|
|
66
|
+
5: (0, 4, 1, 2, 5, 3),
|
|
67
|
+
6: (0, 3, 1, 2, 4, 5),
|
|
68
|
+
7: (0, 3, 1, 2, 5, 4),
|
|
69
|
+
8: (0, 5, 1, 3, 2, 4),
|
|
70
|
+
9: (0, 4, 1, 3, 2, 5),
|
|
71
|
+
10: (0, 5, 1, 4, 2, 3),
|
|
72
|
+
11: (0, 4, 1, 5, 2, 3),
|
|
73
|
+
12: (0, 3, 1, 4, 2, 5),
|
|
74
|
+
13: (0, 3, 1, 5, 2, 4),
|
|
75
|
+
14: (0, 5, 1, 3, 4, 2),
|
|
76
|
+
15: (0, 4, 1, 3, 5, 2),
|
|
77
|
+
16: (0, 4, 1, 5, 3, 2),
|
|
78
|
+
17: (0, 3, 1, 4, 5, 2),
|
|
79
|
+
18: (0, 3, 1, 5, 4, 2),
|
|
80
|
+
19: (0, 2, 1, 3, 4, 5),
|
|
81
|
+
20: (0, 2, 1, 3, 5, 4),
|
|
82
|
+
21: (0, 2, 1, 4, 3, 5),
|
|
83
|
+
22: (0, 2, 1, 5, 3, 4),
|
|
84
|
+
23: (0, 2, 1, 4, 5, 3),
|
|
85
|
+
24: (0, 2, 1, 5, 4, 3),
|
|
86
|
+
25: (0, 1, 2, 3, 4, 5),
|
|
87
|
+
26: (0, 1, 2, 3, 5, 4),
|
|
88
|
+
27: (0, 1, 2, 4, 3, 5),
|
|
89
|
+
28: (0, 1, 2, 5, 3, 4),
|
|
90
|
+
29: (0, 1, 2, 4, 5, 3),
|
|
91
|
+
30: (0, 1, 2, 5, 4, 3),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _square_planar_permutations(mol: Chem.Mol) -> dict[int, int]:
|
|
96
|
+
"""Return RDKit square-planar permutations keyed by center atom index."""
|
|
97
|
+
return {
|
|
98
|
+
int(info.centeredOn): int(info.permutation)
|
|
99
|
+
for info in Chem.FindPotentialStereo(mol)
|
|
100
|
+
if info.type == Chem.StereoType.Atom_SquarePlanar
|
|
101
|
+
and mol.GetAtomWithIdx(int(info.centeredOn)).GetChiralTag()
|
|
102
|
+
== Chem.ChiralType.CHI_SQUAREPLANAR
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _trigonal_bipyramidal_permutations(mol: Chem.Mol) -> dict[int, int]:
|
|
107
|
+
"""Return RDKit TBP permutations keyed by center atom index."""
|
|
108
|
+
return {
|
|
109
|
+
int(info.centeredOn): int(info.permutation)
|
|
110
|
+
for info in Chem.FindPotentialStereo(mol)
|
|
111
|
+
if info.type == Chem.StereoType.Atom_TrigonalBipyramidal
|
|
112
|
+
and mol.GetAtomWithIdx(int(info.centeredOn)).GetChiralTag()
|
|
113
|
+
== Chem.ChiralType.CHI_TRIGONALBIPYRAMIDAL
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _octahedral_permutations(mol: Chem.Mol) -> dict[int, int]:
|
|
118
|
+
"""Return RDKit octahedral permutations keyed by center atom index."""
|
|
119
|
+
return {
|
|
120
|
+
int(info.centeredOn): int(info.permutation)
|
|
121
|
+
for info in Chem.FindPotentialStereo(mol)
|
|
122
|
+
if info.type == Chem.StereoType.Atom_Octahedral
|
|
123
|
+
and mol.GetAtomWithIdx(int(info.centeredOn)).GetChiralTag()
|
|
124
|
+
== Chem.ChiralType.CHI_OCTAHEDRAL
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _non_tetrahedral_local_references(
|
|
129
|
+
atom: Chem.Atom,
|
|
130
|
+
ids: dict[int, int],
|
|
131
|
+
center: int,
|
|
132
|
+
coordination: int,
|
|
133
|
+
descriptor_name: str,
|
|
134
|
+
) -> tuple[int | str, ...]:
|
|
135
|
+
"""Resolve a local ligand order without inventing vacant sites."""
|
|
136
|
+
refs: list[int | str] = [ids[neighbor.GetIdx()] for neighbor in atom.GetNeighbors()]
|
|
137
|
+
if len(refs) == coordination:
|
|
138
|
+
return tuple(refs)
|
|
139
|
+
hidden_hydrogens = int(atom.GetNumExplicitHs()) + int(atom.GetNumImplicitHs())
|
|
140
|
+
if len(refs) + hidden_hydrogens != coordination:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
f"{descriptor_name} center {center} requires exactly "
|
|
143
|
+
f"{coordination} represented "
|
|
144
|
+
"or hydrogen ligands; vacant or otherwise missing coordination "
|
|
145
|
+
"sites cannot be inferred safely."
|
|
146
|
+
)
|
|
147
|
+
refs.extend(virtual_reference("H", center) for _ in range(hidden_hydrogens))
|
|
148
|
+
return tuple(refs)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _atrop_end_references(
|
|
152
|
+
atom: Chem.Atom,
|
|
153
|
+
other_index: int,
|
|
154
|
+
ids: dict[int, int],
|
|
155
|
+
center: int,
|
|
156
|
+
) -> tuple[int | str, int | str]:
|
|
157
|
+
"""Resolve two local atrop substituents without guessing vacant sites."""
|
|
158
|
+
refs: list[int | str] = [
|
|
159
|
+
ids[neighbor.GetIdx()]
|
|
160
|
+
for neighbor in atom.GetNeighbors()
|
|
161
|
+
if neighbor.GetIdx() != other_index
|
|
162
|
+
]
|
|
163
|
+
if len(refs) == 2:
|
|
164
|
+
return tuple(refs) # type: ignore[return-value]
|
|
165
|
+
hidden_hydrogens = int(atom.GetNumExplicitHs()) + int(atom.GetNumImplicitHs())
|
|
166
|
+
if len(refs) + hidden_hydrogens != 2:
|
|
167
|
+
raise ValueError(
|
|
168
|
+
f"Atrop-bond end {center} requires exactly two represented or "
|
|
169
|
+
"hydrogen substituents."
|
|
170
|
+
)
|
|
171
|
+
refs.extend(virtual_reference("H", center) for _ in range(hidden_hydrogens))
|
|
172
|
+
return tuple(refs) # type: ignore[return-value]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _atom_ids(mol: Chem.Mol, *, require_maps: bool) -> dict[int, int]:
|
|
176
|
+
values = {}
|
|
177
|
+
for atom in mol.GetAtoms():
|
|
178
|
+
value = int(atom.GetAtomMapNum()) if require_maps else atom.GetIdx() + 1
|
|
179
|
+
if value <= 0:
|
|
180
|
+
raise ValueError("Stereo conversion requires non-zero atom maps.")
|
|
181
|
+
if value in values.values():
|
|
182
|
+
raise ValueError("Stereo conversion requires unique atom maps.")
|
|
183
|
+
values[atom.GetIdx()] = value
|
|
184
|
+
return values
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _virtual_ligand(atom: Chem.Atom, center: int) -> str:
|
|
188
|
+
"""Resolve RDKit's unrepresented ligand without guessing its identity."""
|
|
189
|
+
hidden_hydrogens = int(atom.GetNumExplicitHs()) + int(atom.GetNumImplicitHs())
|
|
190
|
+
if hidden_hydrogens > 0:
|
|
191
|
+
return virtual_reference("H", center)
|
|
192
|
+
|
|
193
|
+
# Keep this import local: MolToGraph calls this adapter while constructing
|
|
194
|
+
# its registry. Its Lewis estimate supplies the electronic distinction
|
|
195
|
+
# that RDKit's absent-neighbor representation itself does not encode.
|
|
196
|
+
from synkit.IO.mol_to_graph import MolToGraph
|
|
197
|
+
|
|
198
|
+
if MolToGraph.estimate_lone_pairs(atom) > 0:
|
|
199
|
+
return virtual_reference("LP", center)
|
|
200
|
+
raise ValueError(
|
|
201
|
+
f"Missing stereo ligand at atom {center} is neither an unrepresented "
|
|
202
|
+
"hydrogen nor a Lewis lone pair."
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def descriptors_from_rdkit(
|
|
207
|
+
mol: Chem.Mol, *, require_atom_maps: bool = True
|
|
208
|
+
) -> dict[str, StereoValue]:
|
|
209
|
+
"""Extract SynKit's RDKit-interoperable stereo descriptor subset."""
|
|
210
|
+
Chem.AssignStereochemistry(mol, cleanIt=False, force=True)
|
|
211
|
+
ids = _atom_ids(mol, require_maps=require_atom_maps)
|
|
212
|
+
descriptors: dict[str, StereoValue] = {}
|
|
213
|
+
square_planar_permutations = _square_planar_permutations(mol)
|
|
214
|
+
trigonal_bipyramidal_permutations = _trigonal_bipyramidal_permutations(mol)
|
|
215
|
+
octahedral_permutations = _octahedral_permutations(mol)
|
|
216
|
+
tetra_tags = {
|
|
217
|
+
Chem.ChiralType.CHI_TETRAHEDRAL_CW: 1,
|
|
218
|
+
Chem.ChiralType.CHI_TETRAHEDRAL_CCW: -1,
|
|
219
|
+
}
|
|
220
|
+
for atom in mol.GetAtoms():
|
|
221
|
+
tag = atom.GetChiralTag()
|
|
222
|
+
if tag == Chem.ChiralType.CHI_SQUAREPLANAR:
|
|
223
|
+
center = ids[atom.GetIdx()]
|
|
224
|
+
permutation = square_planar_permutations.get(atom.GetIdx())
|
|
225
|
+
local_refs = _non_tetrahedral_local_references(
|
|
226
|
+
atom,
|
|
227
|
+
ids,
|
|
228
|
+
center,
|
|
229
|
+
4,
|
|
230
|
+
"Square-planar",
|
|
231
|
+
)
|
|
232
|
+
if permutation == 0:
|
|
233
|
+
descriptor = SquarePlanarStereo(
|
|
234
|
+
(center, *local_refs),
|
|
235
|
+
None,
|
|
236
|
+
"rdkit",
|
|
237
|
+
)
|
|
238
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
239
|
+
continue
|
|
240
|
+
positions = _SQUARE_PLANAR_POSITION_MAPS.get(permutation)
|
|
241
|
+
if positions is None:
|
|
242
|
+
raise ValueError(
|
|
243
|
+
f"Square-planar center {center} has unsupported RDKit "
|
|
244
|
+
f"permutation {permutation!r}."
|
|
245
|
+
)
|
|
246
|
+
cyclic_refs = tuple(local_refs[index] for index in positions)
|
|
247
|
+
descriptor = SquarePlanarStereo(
|
|
248
|
+
(center, *cyclic_refs),
|
|
249
|
+
0,
|
|
250
|
+
"rdkit",
|
|
251
|
+
)
|
|
252
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
253
|
+
continue
|
|
254
|
+
if tag == Chem.ChiralType.CHI_TRIGONALBIPYRAMIDAL:
|
|
255
|
+
center = ids[atom.GetIdx()]
|
|
256
|
+
permutation = trigonal_bipyramidal_permutations.get(atom.GetIdx())
|
|
257
|
+
local_refs = _non_tetrahedral_local_references(
|
|
258
|
+
atom,
|
|
259
|
+
ids,
|
|
260
|
+
center,
|
|
261
|
+
5,
|
|
262
|
+
"Trigonal-bipyramidal",
|
|
263
|
+
)
|
|
264
|
+
if permutation == 0:
|
|
265
|
+
descriptor = TrigonalBipyramidalStereo(
|
|
266
|
+
(center, *local_refs),
|
|
267
|
+
None,
|
|
268
|
+
"rdkit",
|
|
269
|
+
)
|
|
270
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
271
|
+
continue
|
|
272
|
+
positions = _TRIGONAL_BIPYRAMIDAL_POSITION_MAPS.get(permutation)
|
|
273
|
+
if positions is None:
|
|
274
|
+
raise ValueError(
|
|
275
|
+
f"Trigonal-bipyramidal center {center} has unsupported "
|
|
276
|
+
f"RDKit permutation {permutation!r}."
|
|
277
|
+
)
|
|
278
|
+
positional_refs = tuple(local_refs[index] for index in positions)
|
|
279
|
+
descriptor = TrigonalBipyramidalStereo(
|
|
280
|
+
(center, *positional_refs),
|
|
281
|
+
1,
|
|
282
|
+
"rdkit",
|
|
283
|
+
)
|
|
284
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
285
|
+
continue
|
|
286
|
+
if tag == Chem.ChiralType.CHI_OCTAHEDRAL:
|
|
287
|
+
center = ids[atom.GetIdx()]
|
|
288
|
+
permutation = octahedral_permutations.get(atom.GetIdx())
|
|
289
|
+
local_refs = _non_tetrahedral_local_references(
|
|
290
|
+
atom,
|
|
291
|
+
ids,
|
|
292
|
+
center,
|
|
293
|
+
6,
|
|
294
|
+
"Octahedral",
|
|
295
|
+
)
|
|
296
|
+
if permutation == 0:
|
|
297
|
+
descriptor = OctahedralStereo(
|
|
298
|
+
(center, *local_refs),
|
|
299
|
+
None,
|
|
300
|
+
"rdkit",
|
|
301
|
+
)
|
|
302
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
303
|
+
continue
|
|
304
|
+
positions = _OCTAHEDRAL_POSITION_MAPS.get(permutation)
|
|
305
|
+
if positions is None:
|
|
306
|
+
raise ValueError(
|
|
307
|
+
f"Octahedral center {center} has unsupported RDKit "
|
|
308
|
+
f"permutation {permutation!r}."
|
|
309
|
+
)
|
|
310
|
+
positional_refs = tuple(local_refs[index] for index in positions)
|
|
311
|
+
descriptor = OctahedralStereo(
|
|
312
|
+
(center, *positional_refs),
|
|
313
|
+
1,
|
|
314
|
+
"rdkit",
|
|
315
|
+
)
|
|
316
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
317
|
+
continue
|
|
318
|
+
if tag not in tetra_tags:
|
|
319
|
+
continue
|
|
320
|
+
center = ids[atom.GetIdx()]
|
|
321
|
+
refs: list[int | str] = [
|
|
322
|
+
ids[neighbor.GetIdx()] for neighbor in atom.GetNeighbors()
|
|
323
|
+
]
|
|
324
|
+
if len(refs) == 3:
|
|
325
|
+
refs.append(_virtual_ligand(atom, center))
|
|
326
|
+
if len(refs) != 4:
|
|
327
|
+
continue
|
|
328
|
+
descriptor = TetrahedralStereo((center, *refs), tetra_tags[tag], "rdkit")
|
|
329
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
330
|
+
|
|
331
|
+
for bond in mol.GetBonds():
|
|
332
|
+
stereo = bond.GetStereo()
|
|
333
|
+
if stereo in {
|
|
334
|
+
Chem.BondStereo.STEREOATROPCW,
|
|
335
|
+
Chem.BondStereo.STEREOATROPCCW,
|
|
336
|
+
}:
|
|
337
|
+
left_index = bond.GetBeginAtomIdx()
|
|
338
|
+
right_index = bond.GetEndAtomIdx()
|
|
339
|
+
left = ids[left_index]
|
|
340
|
+
right = ids[right_index]
|
|
341
|
+
left_refs = _atrop_end_references(
|
|
342
|
+
mol.GetAtomWithIdx(left_index),
|
|
343
|
+
right_index,
|
|
344
|
+
ids,
|
|
345
|
+
left,
|
|
346
|
+
)
|
|
347
|
+
right_refs = _atrop_end_references(
|
|
348
|
+
mol.GetAtomWithIdx(right_index),
|
|
349
|
+
left_index,
|
|
350
|
+
ids,
|
|
351
|
+
right,
|
|
352
|
+
)
|
|
353
|
+
parity = {
|
|
354
|
+
Chem.BondStereo.STEREOATROPCW: 1,
|
|
355
|
+
Chem.BondStereo.STEREOATROPCCW: -1,
|
|
356
|
+
}[stereo]
|
|
357
|
+
descriptor = AtropBondStereo(
|
|
358
|
+
(*left_refs, left, right, *right_refs),
|
|
359
|
+
parity,
|
|
360
|
+
"rdkit",
|
|
361
|
+
)
|
|
362
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
363
|
+
continue
|
|
364
|
+
if bond.GetBondType() != Chem.BondType.DOUBLE:
|
|
365
|
+
continue
|
|
366
|
+
if stereo not in {Chem.BondStereo.STEREOE, Chem.BondStereo.STEREOZ}:
|
|
367
|
+
continue
|
|
368
|
+
left_idx, right_idx = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()
|
|
369
|
+
left, right = ids[left_idx], ids[right_idx]
|
|
370
|
+
stereo_atoms = tuple(bond.GetStereoAtoms())
|
|
371
|
+
if len(stereo_atoms) != 2:
|
|
372
|
+
continue
|
|
373
|
+
selected_left, selected_right = stereo_atoms
|
|
374
|
+
left_refs: list[int | str] = [ids[selected_left]]
|
|
375
|
+
left_refs.extend(
|
|
376
|
+
ids[neighbor.GetIdx()]
|
|
377
|
+
for neighbor in mol.GetAtomWithIdx(left_idx).GetNeighbors()
|
|
378
|
+
if neighbor.GetIdx() not in {right_idx, selected_left}
|
|
379
|
+
)
|
|
380
|
+
right_refs: list[int | str] = [ids[selected_right]]
|
|
381
|
+
right_refs.extend(
|
|
382
|
+
ids[neighbor.GetIdx()]
|
|
383
|
+
for neighbor in mol.GetAtomWithIdx(right_idx).GetNeighbors()
|
|
384
|
+
if neighbor.GetIdx() not in {left_idx, selected_right}
|
|
385
|
+
)
|
|
386
|
+
if len(left_refs) == 1:
|
|
387
|
+
left_refs.append(_virtual_ligand(mol.GetAtomWithIdx(left_idx), left))
|
|
388
|
+
if len(right_refs) == 1:
|
|
389
|
+
right_refs.append(_virtual_ligand(mol.GetAtomWithIdx(right_idx), right))
|
|
390
|
+
if len(left_refs) != 2 or len(right_refs) != 2:
|
|
391
|
+
continue
|
|
392
|
+
if stereo == Chem.BondStereo.STEREOE:
|
|
393
|
+
right_refs.reverse()
|
|
394
|
+
descriptor = PlanarBondStereo(
|
|
395
|
+
(*left_refs, left, right, *right_refs), 0, "rdkit"
|
|
396
|
+
)
|
|
397
|
+
descriptors[descriptor_id(descriptor)] = descriptor
|
|
398
|
+
return descriptors
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def apply_stereo_to_rdkit(
|
|
402
|
+
mol: Chem.Mol, descriptors: Iterable[StereoValue]
|
|
403
|
+
) -> Chem.Mol:
|
|
404
|
+
"""Apply the RDKit-interoperable descriptor subset in place.
|
|
405
|
+
|
|
406
|
+
Unsupported descriptors remain valid SynKit graph/rule values, but their
|
|
407
|
+
RDKit projection is not silently discarded: conversion raises until a
|
|
408
|
+
class-specific, round-trip-tested adapter is available.
|
|
409
|
+
"""
|
|
410
|
+
ids = _atom_ids(mol, require_maps=True)
|
|
411
|
+
by_map = {atom_map: index for index, atom_map in ids.items()}
|
|
412
|
+
for descriptor in descriptors:
|
|
413
|
+
if isinstance(descriptor, TetrahedralStereo):
|
|
414
|
+
if (
|
|
415
|
+
not isinstance(descriptor.center, int)
|
|
416
|
+
or descriptor.center not in by_map
|
|
417
|
+
):
|
|
418
|
+
raise ValueError("Tetrahedral center is absent from RDKit molecule.")
|
|
419
|
+
atom = mol.GetAtomWithIdx(by_map[descriptor.center])
|
|
420
|
+
refs = tuple(ids[neighbor.GetIdx()] for neighbor in atom.GetNeighbors())
|
|
421
|
+
if len(refs) == 3:
|
|
422
|
+
refs = (*refs, _virtual_ligand(atom, descriptor.center))
|
|
423
|
+
probe = TetrahedralStereo((descriptor.center, *refs), 1)
|
|
424
|
+
desired = descriptor.canonical_form()[-1]
|
|
425
|
+
probe_parity = probe.canonical_form()[-1]
|
|
426
|
+
raw_parity = None if desired is None else int(desired) * int(probe_parity)
|
|
427
|
+
tag = {
|
|
428
|
+
1: Chem.ChiralType.CHI_TETRAHEDRAL_CW,
|
|
429
|
+
-1: Chem.ChiralType.CHI_TETRAHEDRAL_CCW,
|
|
430
|
+
None: Chem.ChiralType.CHI_UNSPECIFIED,
|
|
431
|
+
}[raw_parity]
|
|
432
|
+
atom.SetChiralTag(tag)
|
|
433
|
+
elif isinstance(descriptor, SquarePlanarStereo):
|
|
434
|
+
if (
|
|
435
|
+
not isinstance(descriptor.center, int)
|
|
436
|
+
or descriptor.center not in by_map
|
|
437
|
+
):
|
|
438
|
+
raise ValueError("Square-planar center is absent from RDKit molecule.")
|
|
439
|
+
if descriptor.parity is None:
|
|
440
|
+
raise NotImplementedError(
|
|
441
|
+
"RDKit projection of an unknown square-planar orientation "
|
|
442
|
+
"would lose the distinction between an unknown descriptor "
|
|
443
|
+
"and no descriptor."
|
|
444
|
+
)
|
|
445
|
+
atom = mol.GetAtomWithIdx(by_map[descriptor.center])
|
|
446
|
+
local_refs = _non_tetrahedral_local_references(
|
|
447
|
+
atom,
|
|
448
|
+
ids,
|
|
449
|
+
descriptor.center,
|
|
450
|
+
4,
|
|
451
|
+
"Square-planar",
|
|
452
|
+
)
|
|
453
|
+
matching_permutations = []
|
|
454
|
+
for permutation, positions in _SQUARE_PLANAR_POSITION_MAPS.items():
|
|
455
|
+
cyclic_refs = tuple(local_refs[index] for index in positions)
|
|
456
|
+
candidate = SquarePlanarStereo(
|
|
457
|
+
(descriptor.center, *cyclic_refs),
|
|
458
|
+
0,
|
|
459
|
+
)
|
|
460
|
+
if candidate == descriptor:
|
|
461
|
+
matching_permutations.append(permutation)
|
|
462
|
+
if not matching_permutations:
|
|
463
|
+
raise ValueError(
|
|
464
|
+
"Square-planar descriptor ligands do not match the RDKit "
|
|
465
|
+
f"coordination sphere at center {descriptor.center}."
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
# Duplicate ligands can make more than one raw SP permutation encode
|
|
469
|
+
# the same cyclic identity. The lowest matching value is a stable
|
|
470
|
+
# serialization choice; descriptor identity does not depend on it.
|
|
471
|
+
permutation = min(matching_permutations)
|
|
472
|
+
atom.SetChiralTag(Chem.ChiralType.CHI_SQUAREPLANAR)
|
|
473
|
+
# RDKit 2026.03 exposes permutation reads through StereoInfo but no
|
|
474
|
+
# Atom setter in Python. This is RDKit's own integer property; the
|
|
475
|
+
# public FindPotentialStereo() round-trip is exercised by tests.
|
|
476
|
+
atom.SetIntProp("_chiralPermutation", permutation)
|
|
477
|
+
elif isinstance(descriptor, TrigonalBipyramidalStereo):
|
|
478
|
+
if (
|
|
479
|
+
not isinstance(descriptor.center, int)
|
|
480
|
+
or descriptor.center not in by_map
|
|
481
|
+
):
|
|
482
|
+
raise ValueError(
|
|
483
|
+
"Trigonal-bipyramidal center is absent from RDKit molecule."
|
|
484
|
+
)
|
|
485
|
+
if descriptor.parity is None:
|
|
486
|
+
raise NotImplementedError(
|
|
487
|
+
"RDKit projection of an unknown trigonal-bipyramidal "
|
|
488
|
+
"orientation would lose the distinction between an "
|
|
489
|
+
"unknown descriptor and no descriptor."
|
|
490
|
+
)
|
|
491
|
+
atom = mol.GetAtomWithIdx(by_map[descriptor.center])
|
|
492
|
+
local_refs = _non_tetrahedral_local_references(
|
|
493
|
+
atom,
|
|
494
|
+
ids,
|
|
495
|
+
descriptor.center,
|
|
496
|
+
5,
|
|
497
|
+
"Trigonal-bipyramidal",
|
|
498
|
+
)
|
|
499
|
+
matching_permutations = []
|
|
500
|
+
for (
|
|
501
|
+
permutation,
|
|
502
|
+
positions,
|
|
503
|
+
) in _TRIGONAL_BIPYRAMIDAL_POSITION_MAPS.items():
|
|
504
|
+
positional_refs = tuple(local_refs[index] for index in positions)
|
|
505
|
+
candidate = TrigonalBipyramidalStereo(
|
|
506
|
+
(descriptor.center, *positional_refs),
|
|
507
|
+
1,
|
|
508
|
+
)
|
|
509
|
+
if candidate == descriptor:
|
|
510
|
+
matching_permutations.append(permutation)
|
|
511
|
+
if not matching_permutations:
|
|
512
|
+
raise ValueError(
|
|
513
|
+
"Trigonal-bipyramidal descriptor ligands do not match the "
|
|
514
|
+
f"RDKit coordination sphere at center {descriptor.center}."
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
permutation = min(matching_permutations)
|
|
518
|
+
atom.SetChiralTag(Chem.ChiralType.CHI_TRIGONALBIPYRAMIDAL)
|
|
519
|
+
atom.SetIntProp("_chiralPermutation", permutation)
|
|
520
|
+
elif isinstance(descriptor, OctahedralStereo):
|
|
521
|
+
if (
|
|
522
|
+
not isinstance(descriptor.center, int)
|
|
523
|
+
or descriptor.center not in by_map
|
|
524
|
+
):
|
|
525
|
+
raise ValueError("Octahedral center is absent from RDKit molecule.")
|
|
526
|
+
if descriptor.parity is None:
|
|
527
|
+
raise NotImplementedError(
|
|
528
|
+
"RDKit projection of an unknown octahedral orientation "
|
|
529
|
+
"would lose the distinction between an unknown descriptor "
|
|
530
|
+
"and no descriptor."
|
|
531
|
+
)
|
|
532
|
+
atom = mol.GetAtomWithIdx(by_map[descriptor.center])
|
|
533
|
+
local_refs = _non_tetrahedral_local_references(
|
|
534
|
+
atom,
|
|
535
|
+
ids,
|
|
536
|
+
descriptor.center,
|
|
537
|
+
6,
|
|
538
|
+
"Octahedral",
|
|
539
|
+
)
|
|
540
|
+
matching_permutations = []
|
|
541
|
+
for permutation, positions in _OCTAHEDRAL_POSITION_MAPS.items():
|
|
542
|
+
positional_refs = tuple(local_refs[index] for index in positions)
|
|
543
|
+
candidate = OctahedralStereo(
|
|
544
|
+
(descriptor.center, *positional_refs),
|
|
545
|
+
1,
|
|
546
|
+
)
|
|
547
|
+
if candidate == descriptor:
|
|
548
|
+
matching_permutations.append(permutation)
|
|
549
|
+
if not matching_permutations:
|
|
550
|
+
raise ValueError(
|
|
551
|
+
"Octahedral descriptor ligands do not match the RDKit "
|
|
552
|
+
f"coordination sphere at center {descriptor.center}."
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
permutation = min(matching_permutations)
|
|
556
|
+
atom.SetChiralTag(Chem.ChiralType.CHI_OCTAHEDRAL)
|
|
557
|
+
atom.SetIntProp("_chiralPermutation", permutation)
|
|
558
|
+
elif isinstance(descriptor, AtropBondStereo):
|
|
559
|
+
left, right = descriptor.atoms[2:4]
|
|
560
|
+
if (
|
|
561
|
+
not isinstance(left, int)
|
|
562
|
+
or not isinstance(right, int)
|
|
563
|
+
or left not in by_map
|
|
564
|
+
or right not in by_map
|
|
565
|
+
):
|
|
566
|
+
raise ValueError("Atrop-bond centers must be mapped RDKit atoms.")
|
|
567
|
+
bond = mol.GetBondBetweenAtoms(by_map[left], by_map[right])
|
|
568
|
+
if bond is None or bond.GetBondType() != Chem.BondType.SINGLE:
|
|
569
|
+
raise ValueError("Atrop descriptor central single bond is absent.")
|
|
570
|
+
if descriptor.parity is None:
|
|
571
|
+
raise NotImplementedError(
|
|
572
|
+
"RDKit projection of an unknown atrop-bond orientation "
|
|
573
|
+
"would lose the distinction between an unknown descriptor "
|
|
574
|
+
"and no descriptor."
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
left_index = bond.GetBeginAtomIdx()
|
|
578
|
+
right_index = bond.GetEndAtomIdx()
|
|
579
|
+
local_left = ids[left_index]
|
|
580
|
+
local_right = ids[right_index]
|
|
581
|
+
left_refs = _atrop_end_references(
|
|
582
|
+
mol.GetAtomWithIdx(left_index),
|
|
583
|
+
right_index,
|
|
584
|
+
ids,
|
|
585
|
+
local_left,
|
|
586
|
+
)
|
|
587
|
+
right_refs = _atrop_end_references(
|
|
588
|
+
mol.GetAtomWithIdx(right_index),
|
|
589
|
+
left_index,
|
|
590
|
+
ids,
|
|
591
|
+
local_right,
|
|
592
|
+
)
|
|
593
|
+
candidates = {
|
|
594
|
+
AtropBondStereo(
|
|
595
|
+
(*left_refs, local_left, local_right, *right_refs),
|
|
596
|
+
parity,
|
|
597
|
+
).canonical_form(): stereo
|
|
598
|
+
for stereo, parity in (
|
|
599
|
+
(Chem.BondStereo.STEREOATROPCW, 1),
|
|
600
|
+
(Chem.BondStereo.STEREOATROPCCW, -1),
|
|
601
|
+
)
|
|
602
|
+
}
|
|
603
|
+
selected = candidates.get(descriptor.canonical_form())
|
|
604
|
+
if selected is None:
|
|
605
|
+
raise ValueError(
|
|
606
|
+
"Atrop descriptor substituents do not match the RDKit "
|
|
607
|
+
f"bond {left}-{right}."
|
|
608
|
+
)
|
|
609
|
+
bond.SetStereo(selected)
|
|
610
|
+
elif isinstance(descriptor, PlanarBondStereo):
|
|
611
|
+
left, right = descriptor.atoms[2:4]
|
|
612
|
+
if not isinstance(left, int) or not isinstance(right, int):
|
|
613
|
+
raise ValueError("Planar-bond centers must be mapped atoms.")
|
|
614
|
+
bond = mol.GetBondBetweenAtoms(by_map[left], by_map[right])
|
|
615
|
+
if bond is None:
|
|
616
|
+
raise ValueError("Planar descriptor central bond is absent.")
|
|
617
|
+
if descriptor.parity is None:
|
|
618
|
+
# A present descriptor with undefined orientation must remain
|
|
619
|
+
# distinct from a specified E/Z arrangement at the RDKit
|
|
620
|
+
# boundary. Clear neighboring slash/backslash directions too,
|
|
621
|
+
# otherwise AssignStereochemistry reconstructs the old label.
|
|
622
|
+
bond.SetStereo(Chem.BondStereo.STEREONONE)
|
|
623
|
+
for center in (by_map[left], by_map[right]):
|
|
624
|
+
atom = mol.GetAtomWithIdx(center)
|
|
625
|
+
for adjacent in atom.GetBonds():
|
|
626
|
+
if adjacent.GetIdx() != bond.GetIdx():
|
|
627
|
+
adjacent.SetBondDir(Chem.BondDir.NONE)
|
|
628
|
+
continue
|
|
629
|
+
left_refs = descriptor.atoms[:2]
|
|
630
|
+
right_refs = descriptor.atoms[4:]
|
|
631
|
+
real_left = next(
|
|
632
|
+
(value for value in left_refs if isinstance(value, int)), None
|
|
633
|
+
)
|
|
634
|
+
real_right = next(
|
|
635
|
+
(value for value in right_refs if isinstance(value, int)), None
|
|
636
|
+
)
|
|
637
|
+
if real_left is None or real_right is None:
|
|
638
|
+
continue
|
|
639
|
+
other_left = next(value for value in left_refs if value != real_left)
|
|
640
|
+
other_right = next(value for value in right_refs if value != real_right)
|
|
641
|
+
z_atoms = (real_left, other_left, left, right, real_right, other_right)
|
|
642
|
+
e_atoms = (real_left, other_left, left, right, other_right, real_right)
|
|
643
|
+
candidates = {}
|
|
644
|
+
for stereo, atoms in (
|
|
645
|
+
(Chem.BondStereo.STEREOZ, z_atoms),
|
|
646
|
+
(Chem.BondStereo.STEREOE, e_atoms),
|
|
647
|
+
):
|
|
648
|
+
candidate = PlanarBondStereo(atoms, descriptor.parity)
|
|
649
|
+
candidates[candidate.canonical_form()] = (stereo, atoms)
|
|
650
|
+
selected = candidates.get(descriptor.canonical_form())
|
|
651
|
+
if selected is None:
|
|
652
|
+
continue
|
|
653
|
+
stereo, atoms = selected
|
|
654
|
+
bond.SetStereoAtoms(by_map[real_left], by_map[real_right])
|
|
655
|
+
bond.SetStereo(stereo)
|
|
656
|
+
else:
|
|
657
|
+
raise NotImplementedError(
|
|
658
|
+
f"RDKit conversion for {descriptor.descriptor_class!r} stereo "
|
|
659
|
+
"is not implemented; keep this descriptor in SynKit graph metadata."
|
|
660
|
+
)
|
|
661
|
+
Chem.AssignStereochemistry(mol, cleanIt=False, force=True)
|
|
662
|
+
return mol
|