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,412 @@
|
|
|
1
|
+
"""Convert fully mapped exact-ITS representatives into executable rules.
|
|
2
|
+
|
|
3
|
+
The global-shell enumerator normally operates on heavy atoms. A heavy-only
|
|
4
|
+
correspondence is intentionally insufficient here: assigning omitted explicit
|
|
5
|
+
hydrogens from the deposited map would leak the reference alignment into a
|
|
6
|
+
candidate template. This adapter therefore accepts only a declared complete
|
|
7
|
+
atom correspondence and exposes source replay as a construction check.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
import hashlib
|
|
14
|
+
from numbers import Integral
|
|
15
|
+
from typing import Any, Iterable, Mapping, Sequence
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from rdkit import Chem
|
|
19
|
+
except ImportError: # pragma: no cover - exercised only without RDKit
|
|
20
|
+
Chem = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _require_rdkit():
|
|
24
|
+
if Chem is None:
|
|
25
|
+
raise ImportError("RDKit is required for executable-template conversion")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _split_reaction(reaction: str) -> tuple[str, str]:
|
|
29
|
+
if not isinstance(reaction, str) or reaction.count(">>") != 1:
|
|
30
|
+
raise ValueError("reaction must contain exactly one '>>' separator")
|
|
31
|
+
reactants, products = reaction.split(">>")
|
|
32
|
+
if not reactants or not products:
|
|
33
|
+
raise ValueError("reaction must contain non-empty reactant and product sides")
|
|
34
|
+
return reactants, products
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _mapped_molecule(smiles: str, *, side: str):
|
|
38
|
+
_require_rdkit()
|
|
39
|
+
# Keep mapped explicit hydrogens. The mapper's full-atom contract uses
|
|
40
|
+
# them as ordinary vertices, whereas RDKit's default parser may remove
|
|
41
|
+
# them before atom-map inventory validation.
|
|
42
|
+
parameters = Chem.SmilesParserParams()
|
|
43
|
+
parameters.removeHs = False
|
|
44
|
+
molecule = Chem.MolFromSmiles(smiles, parameters)
|
|
45
|
+
if molecule is None:
|
|
46
|
+
raise ValueError(f"{side} side is not valid SMILES")
|
|
47
|
+
maps = [int(atom.GetAtomMapNum()) for atom in molecule.GetAtoms()]
|
|
48
|
+
if (
|
|
49
|
+
not maps
|
|
50
|
+
or any(atom_map <= 0 for atom_map in maps)
|
|
51
|
+
or len(set(maps)) != len(maps)
|
|
52
|
+
):
|
|
53
|
+
raise ValueError(f"{side} side must have one unique positive atom map per atom")
|
|
54
|
+
return molecule, tuple(maps)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _correspondence_pairs(correspondence):
|
|
58
|
+
try:
|
|
59
|
+
pairs = tuple(tuple(pair) for pair in correspondence)
|
|
60
|
+
except TypeError as error:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
"correspondence must contain pairs of integer atom-map IDs"
|
|
63
|
+
) from error
|
|
64
|
+
if not pairs or any(len(pair) != 2 for pair in pairs):
|
|
65
|
+
raise ValueError("each atom-map correspondence must have two entries")
|
|
66
|
+
if any(
|
|
67
|
+
isinstance(value, bool) or not isinstance(value, Integral) or value <= 0
|
|
68
|
+
for pair in pairs
|
|
69
|
+
for value in pair
|
|
70
|
+
):
|
|
71
|
+
raise ValueError("atom-map correspondence entries must be positive integers")
|
|
72
|
+
pairs = tuple((int(left), int(right)) for left, right in pairs)
|
|
73
|
+
if len({left for left, _ in pairs}) != len(pairs):
|
|
74
|
+
raise ValueError("reactant atom maps occur more than once in correspondence")
|
|
75
|
+
if len({right for _, right in pairs}) != len(pairs):
|
|
76
|
+
raise ValueError("product atom maps occur more than once in correspondence")
|
|
77
|
+
return pairs
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _validate_correspondence(
|
|
81
|
+
correspondence: Iterable[Sequence[int]],
|
|
82
|
+
reactant_maps: tuple[int, ...],
|
|
83
|
+
product_maps: tuple[int, ...],
|
|
84
|
+
) -> dict[int, int]:
|
|
85
|
+
pairs = _correspondence_pairs(correspondence)
|
|
86
|
+
remapping = dict(pairs)
|
|
87
|
+
if set(remapping) != set(reactant_maps) or set(remapping.values()) != set(
|
|
88
|
+
product_maps
|
|
89
|
+
):
|
|
90
|
+
raise ValueError(
|
|
91
|
+
"correspondence must cover each reactant and product atom once"
|
|
92
|
+
)
|
|
93
|
+
return remapping
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def mapped_reaction_from_correspondence(
|
|
97
|
+
reaction: str,
|
|
98
|
+
correspondence: Iterable[Sequence[int]],
|
|
99
|
+
) -> str:
|
|
100
|
+
"""Return a fully mapped reaction whose product uses the candidate mapping.
|
|
101
|
+
|
|
102
|
+
``correspondence`` maps original reactant atom-map identifiers to original
|
|
103
|
+
product identifiers. The returned product is relabelled into the reactant
|
|
104
|
+
identifier namespace, which is the pairing convention required by ITS and
|
|
105
|
+
executable-rule construction.
|
|
106
|
+
"""
|
|
107
|
+
reactants, products = _split_reaction(reaction)
|
|
108
|
+
reactant, reactant_maps = _mapped_molecule(reactants, side="reactant")
|
|
109
|
+
product, product_maps = _mapped_molecule(products, side="product")
|
|
110
|
+
remapping = _validate_correspondence(correspondence, reactant_maps, product_maps)
|
|
111
|
+
_validate_elements(reactant, product, remapping)
|
|
112
|
+
inverse = {
|
|
113
|
+
product_map: reactant_map for reactant_map, product_map in remapping.items()
|
|
114
|
+
}
|
|
115
|
+
for atom in product.GetAtoms():
|
|
116
|
+
atom.SetAtomMapNum(inverse[int(atom.GetAtomMapNum())])
|
|
117
|
+
product_smiles = Chem.MolToSmiles(product, canonical=True, isomericSmiles=True)
|
|
118
|
+
return f"{reactants}>>{product_smiles}"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def executable_rule_from_correspondence(
|
|
122
|
+
reaction: str,
|
|
123
|
+
correspondence: Iterable[Sequence[int]],
|
|
124
|
+
*,
|
|
125
|
+
heavy_only: bool,
|
|
126
|
+
name: str = "synister_exact_its_class",
|
|
127
|
+
):
|
|
128
|
+
"""Build a :class:`SynRule` from a complete representative mapping.
|
|
129
|
+
|
|
130
|
+
Heavy-only shell outputs cannot safely furnish a full explicit-hydrogen
|
|
131
|
+
rule, so callers must run a full-atom protocol before calling this method.
|
|
132
|
+
"""
|
|
133
|
+
if type(heavy_only) is not bool:
|
|
134
|
+
raise ValueError("heavy_only must explicitly declare Boolean scope")
|
|
135
|
+
if heavy_only:
|
|
136
|
+
raise ValueError(
|
|
137
|
+
"heavy-only correspondence cannot construct a full executable rule"
|
|
138
|
+
)
|
|
139
|
+
from synkit.Rule import SynRule
|
|
140
|
+
|
|
141
|
+
mapped_reaction = mapped_reaction_from_correspondence(reaction, correspondence)
|
|
142
|
+
return SynRule.from_smart(
|
|
143
|
+
mapped_reaction,
|
|
144
|
+
name=name,
|
|
145
|
+
format="tuple",
|
|
146
|
+
implicit_h=False,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _canonical_product(smiles: str) -> str:
|
|
151
|
+
_require_rdkit()
|
|
152
|
+
molecule = Chem.MolFromSmiles(smiles, sanitize=True)
|
|
153
|
+
if molecule is None:
|
|
154
|
+
raise ValueError("product is not valid SMILES")
|
|
155
|
+
for atom in molecule.GetAtoms():
|
|
156
|
+
atom.SetAtomMapNum(0)
|
|
157
|
+
return Chem.MolToSmiles(molecule, canonical=True, isomericSmiles=True)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@dataclass(frozen=True)
|
|
161
|
+
class SourceReplayResult:
|
|
162
|
+
"""Product-blindness-safe source construction replay outcome."""
|
|
163
|
+
|
|
164
|
+
mapped_reaction: str
|
|
165
|
+
expected_product: str
|
|
166
|
+
generated_products: tuple[str, ...]
|
|
167
|
+
recovered: bool
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@dataclass(frozen=True)
|
|
171
|
+
class ProductRecoveryScore:
|
|
172
|
+
"""Target-only score of previously generated prospective candidates."""
|
|
173
|
+
|
|
174
|
+
expected_product: str
|
|
175
|
+
candidate_count: int
|
|
176
|
+
recovered: bool
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def prospective_products(reactants: str, rules: Iterable[Any]) -> tuple[str, ...]:
|
|
180
|
+
"""Apply executable rules to reactants without observing a target product.
|
|
181
|
+
|
|
182
|
+
The returned values are canonical unmapped product SMILES. This is the
|
|
183
|
+
application half of a held-out transfer study; target-product comparison
|
|
184
|
+
belongs in a separate scoring function and must occur only after these
|
|
185
|
+
candidates have been saved.
|
|
186
|
+
"""
|
|
187
|
+
if not isinstance(reactants, str) or not reactants:
|
|
188
|
+
raise ValueError("reactants must be a non-empty SMILES string")
|
|
189
|
+
from synkit.Synthesis.Reactor import SynReactor
|
|
190
|
+
|
|
191
|
+
products = set()
|
|
192
|
+
for rule in rules:
|
|
193
|
+
reactor = SynReactor(
|
|
194
|
+
reactants,
|
|
195
|
+
rule,
|
|
196
|
+
template_format="tuple",
|
|
197
|
+
explicit_h=False,
|
|
198
|
+
stereo_mode="ignore",
|
|
199
|
+
)
|
|
200
|
+
for candidate in reactor.smarts:
|
|
201
|
+
products.add(_canonical_product(candidate.split(">>", 1)[1]))
|
|
202
|
+
return tuple(sorted(products))
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def score_product_recovery(
|
|
206
|
+
candidates: Iterable[str], expected_product: str
|
|
207
|
+
) -> ProductRecoveryScore:
|
|
208
|
+
"""Score saved candidates against a held-out product in a separate stage."""
|
|
209
|
+
normalized_candidates = tuple(
|
|
210
|
+
sorted({_canonical_product(value) for value in candidates})
|
|
211
|
+
)
|
|
212
|
+
expected = _canonical_product(expected_product)
|
|
213
|
+
return ProductRecoveryScore(
|
|
214
|
+
expected_product=expected,
|
|
215
|
+
candidate_count=len(normalized_candidates),
|
|
216
|
+
recovered=expected in normalized_candidates,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def replay_executable_rule_on_source(
|
|
221
|
+
reaction: str,
|
|
222
|
+
correspondence: Iterable[Sequence[int]],
|
|
223
|
+
*,
|
|
224
|
+
heavy_only: bool,
|
|
225
|
+
) -> SourceReplayResult:
|
|
226
|
+
"""Construct a rule and check it on its own source reactants.
|
|
227
|
+
|
|
228
|
+
This helper is a conversion audit only. It is deliberately unsuitable for
|
|
229
|
+
held-out scoring because it reads both sides of ``reaction`` to establish
|
|
230
|
+
the expected source product.
|
|
231
|
+
"""
|
|
232
|
+
correspondence = _correspondence_pairs(correspondence)
|
|
233
|
+
mapped_reaction = mapped_reaction_from_correspondence(reaction, correspondence)
|
|
234
|
+
rule = executable_rule_from_correspondence(
|
|
235
|
+
reaction,
|
|
236
|
+
correspondence,
|
|
237
|
+
heavy_only=heavy_only,
|
|
238
|
+
)
|
|
239
|
+
reactants, products = _split_reaction(mapped_reaction)
|
|
240
|
+
from synkit.Synthesis.Reactor import SynReactor
|
|
241
|
+
|
|
242
|
+
reactor = SynReactor(
|
|
243
|
+
reactants,
|
|
244
|
+
rule,
|
|
245
|
+
template_format="tuple",
|
|
246
|
+
explicit_h=False,
|
|
247
|
+
stereo_mode="ignore",
|
|
248
|
+
)
|
|
249
|
+
generated = tuple(
|
|
250
|
+
sorted(
|
|
251
|
+
{
|
|
252
|
+
_canonical_product(candidate.split(">>", 1)[1])
|
|
253
|
+
for candidate in reactor.smarts
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
expected = _canonical_product(products)
|
|
258
|
+
return SourceReplayResult(
|
|
259
|
+
mapped_reaction=mapped_reaction,
|
|
260
|
+
expected_product=expected,
|
|
261
|
+
generated_products=generated,
|
|
262
|
+
recovered=expected in generated,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def correspondence_from_export(
|
|
267
|
+
class_record: Mapping[str, object],
|
|
268
|
+
) -> tuple[tuple[int, int], ...]:
|
|
269
|
+
"""Read one representative correspondence from a version-2 class record."""
|
|
270
|
+
try:
|
|
271
|
+
value = class_record["atom_map_correspondence"]
|
|
272
|
+
except KeyError as error:
|
|
273
|
+
raise ValueError("class record lacks atom_map_correspondence") from error
|
|
274
|
+
if not isinstance(value, list):
|
|
275
|
+
raise ValueError("atom_map_correspondence must be a JSON list")
|
|
276
|
+
return _correspondence_pairs(value)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _validate_elements(reactant, product, remapping):
|
|
280
|
+
before = {atom.GetAtomMapNum(): atom.GetAtomicNum() for atom in reactant.GetAtoms()}
|
|
281
|
+
after = {atom.GetAtomMapNum(): atom.GetAtomicNum() for atom in product.GetAtoms()}
|
|
282
|
+
if any(before[left] != after[right] for left, right in remapping.items()):
|
|
283
|
+
raise ValueError("correspondence must preserve atom elements")
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@dataclass(frozen=True)
|
|
287
|
+
class ClassCorrespondence:
|
|
288
|
+
"""Reaction-bound correspondence from a declared complete ITS-class export."""
|
|
289
|
+
|
|
290
|
+
reaction_sha256: str
|
|
291
|
+
its_class_id: str
|
|
292
|
+
heavy_only: bool
|
|
293
|
+
reactant_atom_maps: tuple[int, ...]
|
|
294
|
+
product_atom_maps: tuple[int, ...]
|
|
295
|
+
correspondence: tuple[tuple[int, int], ...]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _export_inventories(payload):
|
|
299
|
+
inventories = []
|
|
300
|
+
for key in ("reactant_atom_maps", "product_atom_maps"):
|
|
301
|
+
values = payload.get(key)
|
|
302
|
+
if (
|
|
303
|
+
not isinstance(values, list)
|
|
304
|
+
or not values
|
|
305
|
+
or any(type(value) is not int or value <= 0 for value in values)
|
|
306
|
+
or len(set(values)) != len(values)
|
|
307
|
+
):
|
|
308
|
+
raise ValueError("export contains invalid endpoint atom-map inventory")
|
|
309
|
+
inventories.append(tuple(values))
|
|
310
|
+
return inventories
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def class_correspondence_from_export(
|
|
314
|
+
payload: Mapping[str, object],
|
|
315
|
+
reaction: str,
|
|
316
|
+
its_class_id: str,
|
|
317
|
+
*,
|
|
318
|
+
allow_legacy: bool = False,
|
|
319
|
+
) -> ClassCorrespondence:
|
|
320
|
+
"""Validate export version, reaction identity, scope and endpoint coordinates.
|
|
321
|
+
|
|
322
|
+
New library exports use schema version 1. Existing unversioned library
|
|
323
|
+
results can be read explicitly with ``allow_legacy=True``. This checks the
|
|
324
|
+
declared completion contract and the selected correspondence; independently
|
|
325
|
+
verifying enumeration completeness requires the search certificate/audit.
|
|
326
|
+
CLI application records wrap these library results under ``queries``.
|
|
327
|
+
"""
|
|
328
|
+
if not isinstance(payload, Mapping):
|
|
329
|
+
raise ValueError("export must be a mapping")
|
|
330
|
+
schema = payload.get("schema_version")
|
|
331
|
+
if schema is None and allow_legacy:
|
|
332
|
+
pass
|
|
333
|
+
elif (
|
|
334
|
+
type(schema) is not int
|
|
335
|
+
or schema != 1
|
|
336
|
+
or payload.get("kind") != "synister_mapped_reaction_its_alternatives"
|
|
337
|
+
):
|
|
338
|
+
raise ValueError("unsupported correspondence export schema")
|
|
339
|
+
reactants, products = _split_reaction(reaction)
|
|
340
|
+
expected_hash = hashlib.sha256(reaction.encode("utf-8")).hexdigest()
|
|
341
|
+
if payload.get("reaction_sha256") != expected_hash:
|
|
342
|
+
raise ValueError("export is bound to a different reaction")
|
|
343
|
+
heavy_only = payload.get("heavy_only")
|
|
344
|
+
if type(heavy_only) is not bool:
|
|
345
|
+
raise ValueError("export must declare Boolean heavy_only scope")
|
|
346
|
+
shell = payload.get("shell")
|
|
347
|
+
if not isinstance(shell, Mapping) or any(
|
|
348
|
+
shell.get(key) is not True
|
|
349
|
+
for key in ("complete", "shell_complete", "classification_complete")
|
|
350
|
+
):
|
|
351
|
+
raise ValueError("export lacks complete enumeration and ITS classification")
|
|
352
|
+
classes = shell.get("classes")
|
|
353
|
+
if (
|
|
354
|
+
not isinstance(classes, list)
|
|
355
|
+
or not classes
|
|
356
|
+
or any(not isinstance(record, Mapping) for record in classes)
|
|
357
|
+
):
|
|
358
|
+
raise ValueError("export lacks ITS-class records")
|
|
359
|
+
identifiers = [record.get("its_class_id") for record in classes]
|
|
360
|
+
if any(
|
|
361
|
+
not isinstance(identifier, str) or not identifier for identifier in identifiers
|
|
362
|
+
) or len(set(identifiers)) != len(identifiers):
|
|
363
|
+
raise ValueError("export contains invalid or duplicate ITS-class identifiers")
|
|
364
|
+
if its_class_id not in identifiers:
|
|
365
|
+
raise ValueError("requested ITS class is absent from export")
|
|
366
|
+
selected = classes[identifiers.index(its_class_id)]
|
|
367
|
+
pairs = correspondence_from_export(selected)
|
|
368
|
+
inventories = _export_inventories(payload)
|
|
369
|
+
before_maps, after_maps = inventories
|
|
370
|
+
_validate_correspondence(pairs, before_maps, after_maps)
|
|
371
|
+
representative = selected.get("representative_mapping")
|
|
372
|
+
if (
|
|
373
|
+
not isinstance(representative, list)
|
|
374
|
+
or len(representative) != len(before_maps)
|
|
375
|
+
or any(type(value) is not int for value in representative)
|
|
376
|
+
or sorted(representative) != list(range(len(after_maps)))
|
|
377
|
+
or dict(pairs)
|
|
378
|
+
!= {before_maps[i]: after_maps[j] for i, j in enumerate(representative)}
|
|
379
|
+
):
|
|
380
|
+
raise ValueError("correspondence differs from exported endpoint coordinates")
|
|
381
|
+
molecules = [
|
|
382
|
+
_mapped_molecule(smiles, side=side)[0]
|
|
383
|
+
for smiles, side in ((reactants, "reactant"), (products, "product"))
|
|
384
|
+
]
|
|
385
|
+
for molecule, declared in zip(molecules, inventories):
|
|
386
|
+
actual = {
|
|
387
|
+
atom.GetAtomMapNum()
|
|
388
|
+
for atom in molecule.GetAtoms()
|
|
389
|
+
if not heavy_only or atom.GetAtomicNum() != 1
|
|
390
|
+
}
|
|
391
|
+
if set(declared) != actual:
|
|
392
|
+
raise ValueError(
|
|
393
|
+
"endpoint inventory differs from the declared reaction scope"
|
|
394
|
+
)
|
|
395
|
+
_validate_elements(*molecules, dict(pairs))
|
|
396
|
+
return ClassCorrespondence(
|
|
397
|
+
expected_hash, its_class_id, heavy_only, before_maps, after_maps, pairs
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
__all__ = [
|
|
402
|
+
"SourceReplayResult",
|
|
403
|
+
"ProductRecoveryScore",
|
|
404
|
+
"correspondence_from_export",
|
|
405
|
+
"ClassCorrespondence",
|
|
406
|
+
"class_correspondence_from_export",
|
|
407
|
+
"executable_rule_from_correspondence",
|
|
408
|
+
"mapped_reaction_from_correspondence",
|
|
409
|
+
"prospective_products",
|
|
410
|
+
"score_product_recovery",
|
|
411
|
+
"replay_executable_rule_on_source",
|
|
412
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
mapper.chem — chemistry front-end (RDKit SMILES, ITS analysis).
|
|
3
|
+
|
|
4
|
+
Submodules
|
|
5
|
+
----------
|
|
6
|
+
aam
|
|
7
|
+
:class:`AAMapper`: high-level reaction-SMILES atom-to-atom mapper.
|
|
8
|
+
smiles
|
|
9
|
+
SMILES ↔ LabeledGraph conversion and reaction-SMILES annotation utilities.
|
|
10
|
+
its
|
|
11
|
+
ITS graph hashing, electron-balance checks, and symmetry-distinct
|
|
12
|
+
deduplication via synkit.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from .aam import AAMapper
|
|
16
|
+
from .its import (
|
|
17
|
+
its_canonical_hash,
|
|
18
|
+
dedup_mapped_rxns,
|
|
19
|
+
mapped_rxn_is_electron_balanced,
|
|
20
|
+
is_electron_balanced,
|
|
21
|
+
electron_balance_status,
|
|
22
|
+
)
|
|
23
|
+
from .smiles import (
|
|
24
|
+
HAS_RDKIT,
|
|
25
|
+
smiles2lgp,
|
|
26
|
+
get_numbered_rxn_smiles,
|
|
27
|
+
canonicalize_rxn_smiles,
|
|
28
|
+
expand_reaction_center_hydrogens,
|
|
29
|
+
standardize_reaction_center_hydrogens,
|
|
30
|
+
)
|
|
31
|
+
from .blind import BlindedReactionProblem, blinded_mapped_reaction_problem
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
# aam
|
|
35
|
+
"AAMapper",
|
|
36
|
+
# its
|
|
37
|
+
"its_canonical_hash",
|
|
38
|
+
"dedup_mapped_rxns",
|
|
39
|
+
"mapped_rxn_is_electron_balanced",
|
|
40
|
+
"is_electron_balanced",
|
|
41
|
+
"electron_balance_status",
|
|
42
|
+
# smiles
|
|
43
|
+
"HAS_RDKIT",
|
|
44
|
+
"smiles2lgp",
|
|
45
|
+
"get_numbered_rxn_smiles",
|
|
46
|
+
"canonicalize_rxn_smiles",
|
|
47
|
+
"expand_reaction_center_hydrogens",
|
|
48
|
+
"standardize_reaction_center_hydrogens",
|
|
49
|
+
# blind reference conversion
|
|
50
|
+
"BlindedReactionProblem",
|
|
51
|
+
"blinded_mapped_reaction_problem",
|
|
52
|
+
]
|