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,967 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import warnings
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any, Dict, List, Mapping, Optional, Tuple, Union
|
|
7
|
+
|
|
8
|
+
import networkx as nx
|
|
9
|
+
from synkit.IO.chem_converter import (
|
|
10
|
+
ITSFormat,
|
|
11
|
+
detect_its_format,
|
|
12
|
+
smiles_to_graph,
|
|
13
|
+
rsmi_to_its,
|
|
14
|
+
graph_to_smi,
|
|
15
|
+
)
|
|
16
|
+
from synkit.IO import setup_logging
|
|
17
|
+
from synkit.Chem.utils import reverse_reaction
|
|
18
|
+
|
|
19
|
+
from synkit.Rule import SynRule
|
|
20
|
+
from synkit.Graph.syn_graph import SynGraph
|
|
21
|
+
from synkit.Graph.canon_graph import GraphCanonicaliser
|
|
22
|
+
from synkit.Graph.Mech.electron_accounting import refresh_electron_fields
|
|
23
|
+
from .strategy import Strategy
|
|
24
|
+
from . import product as _product_state
|
|
25
|
+
from . import rewrite as _graph_rewrite
|
|
26
|
+
from ..matching.mixin import ReactorMatchingMixin
|
|
27
|
+
from ..output import deduplication as _deduplication
|
|
28
|
+
from ..output import serialization as _serialization
|
|
29
|
+
from ..output import structural as _structural_deduplication
|
|
30
|
+
from ..output.policy import (
|
|
31
|
+
RawITSApplicationSerializationWarning,
|
|
32
|
+
)
|
|
33
|
+
from ..stereo.mixin import ReactorStereoMixin
|
|
34
|
+
|
|
35
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
# Typing aliases
|
|
37
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
38
|
+
NodeId = Any
|
|
39
|
+
EdgeAttr = Mapping[str, Any]
|
|
40
|
+
MappingDict = Dict[NodeId, NodeId]
|
|
41
|
+
|
|
42
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
# Logging setup
|
|
44
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
log = setup_logging(task_type="synreactor")
|
|
47
|
+
|
|
48
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
49
|
+
# SynReactor core
|
|
50
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class SynReactor(ReactorMatchingMixin, ReactorStereoMixin):
|
|
55
|
+
"""A hardened and typed re-write of the original SynReactor, preserving API
|
|
56
|
+
compatibility while offering safer, faster, and cleaner behavior.
|
|
57
|
+
|
|
58
|
+
:param substrate: The input reaction substrate, as a SMILES string,
|
|
59
|
+
a raw NetworkX graph, or a SynGraph.
|
|
60
|
+
:type substrate: Union[str, nx.Graph, SynGraph]
|
|
61
|
+
:param template: Reaction template, provided as SMILES/SMARTS, a raw
|
|
62
|
+
NetworkX graph, or a SynRule.
|
|
63
|
+
:type template: Union[str, nx.Graph, SynRule]
|
|
64
|
+
:param invert: Whether to invert the reaction (predict precursors).
|
|
65
|
+
Defaults to False.
|
|
66
|
+
:type invert: bool
|
|
67
|
+
:param canonicaliser: Optional canonicaliser for intermediate
|
|
68
|
+
graphs. If None, a default GraphCanonicaliser is used.
|
|
69
|
+
:type canonicaliser: Optional[GraphCanonicaliser]
|
|
70
|
+
:param explicit_h: If True, render all hydrogens explicitly in the
|
|
71
|
+
reaction-center SMARTS. Defaults to True.
|
|
72
|
+
:type explicit_h: bool
|
|
73
|
+
:param implicit_temp: If True, treat the input template as
|
|
74
|
+
implicit-H (forces explicit_h=False). Defaults to False.
|
|
75
|
+
:type implicit_temp: bool
|
|
76
|
+
:param strategy: Matching strategy, one of Strategy.ALL, 'comp', or
|
|
77
|
+
'bt'. Defaults to Strategy.ALL.
|
|
78
|
+
:type strategy: Strategy or str
|
|
79
|
+
:param partial: If True, use a partial matching fallback. Defaults
|
|
80
|
+
to False.
|
|
81
|
+
:type partial: bool
|
|
82
|
+
:param template_format: ITS representation used when ``template`` is a
|
|
83
|
+
reaction string. Defaults to ``"typesGH"`` for compatibility.
|
|
84
|
+
:type template_format: ITSFormat
|
|
85
|
+
:param electron_diagnostics: If True, expose per-result electron-accounting
|
|
86
|
+
diagnostics without changing generated products.
|
|
87
|
+
:type electron_diagnostics: bool
|
|
88
|
+
:param radical_policy: ``"strict"`` requires equal radical counts,
|
|
89
|
+
``"lower_bound"`` permits extra host radical resource for generalized
|
|
90
|
+
templates, and ``"ignore"`` preserves legacy matching behavior.
|
|
91
|
+
:type radical_policy: str
|
|
92
|
+
:param stereo_mode: Stereo application policy. ``"propagate"`` (default)
|
|
93
|
+
applies relative rule effects to the orientation actually present in
|
|
94
|
+
the substrate. ``"require"`` checks every exact rule guard, while
|
|
95
|
+
``"strict"`` additionally rejects undeclared host descriptors in the
|
|
96
|
+
mapped dependency scope. ``"ignore"`` preserves fixed-template legacy
|
|
97
|
+
behaviour without filtering structural mappings.
|
|
98
|
+
:type stereo_mode: str
|
|
99
|
+
:param stereo_query_mode: Meaning of an unknown-parity rule descriptor.
|
|
100
|
+
``"exact"`` matches only unknown host stereo; ``"wildcard"`` matches
|
|
101
|
+
either orientation. Per-descriptor rule policies override this value.
|
|
102
|
+
:type stereo_query_mode: str
|
|
103
|
+
:param stereo_semantics: Reaction stereo execution mode: authoritative
|
|
104
|
+
``"orbit"`` (default), frozen ``"legacy"``, or orbit-authoritative
|
|
105
|
+
``"compare"`` with structured diagnostics.
|
|
106
|
+
:type stereo_semantics: str
|
|
107
|
+
:param preserve_mapped_hydrogens: Preserve positive explicit-H atom maps
|
|
108
|
+
through implicit matching. This is intended for mapped mechanism/rule
|
|
109
|
+
agreement; the default keeps legacy implicit-output projection.
|
|
110
|
+
:type preserve_mapped_hydrogens: bool
|
|
111
|
+
:param dedup_its: If True, consolidate equivalent post-rewrite ITS graphs.
|
|
112
|
+
If False, retain deterministic mapping and stereo-branch multiplicity
|
|
113
|
+
while still finalizing electron fields and validating stereo state.
|
|
114
|
+
This policy is independent of mapping-level ``automorphism`` pruning.
|
|
115
|
+
:type dedup_its: bool
|
|
116
|
+
:param product_deduplication: Post-rewrite quotient policy when
|
|
117
|
+
``dedup_its`` is true. ``"structural"`` keeps the exact internal
|
|
118
|
+
application and ITS quotients. ``"deferred"`` finalizes every product
|
|
119
|
+
state but leaves application/product endpoint identity to downstream
|
|
120
|
+
serialized-output canonicalization; it is restricted to
|
|
121
|
+
``stereo_mode="ignore"``.
|
|
122
|
+
:type product_deduplication: str
|
|
123
|
+
:param serialization_errors: Raw ITS serialization policy. ``"raise"``
|
|
124
|
+
preserves the compatibility behavior; ``"skip"`` returns all
|
|
125
|
+
serializable results in their original order and reports omitted raw
|
|
126
|
+
application indices.
|
|
127
|
+
:type serialization_errors: str
|
|
128
|
+
:param stereo_assignment_limit: Optional hard cap on admissible injective
|
|
129
|
+
typed stereo-port assignments. Exceeding it raises instead of silently
|
|
130
|
+
truncating the search.
|
|
131
|
+
:type stereo_assignment_limit: Optional[int]
|
|
132
|
+
:param stereo_branch_limit: Optional hard cap on stereo product branches
|
|
133
|
+
across all accepted applications. Exceeding it raises a typed error
|
|
134
|
+
before a partial result can be returned.
|
|
135
|
+
:type stereo_branch_limit: Optional[int]
|
|
136
|
+
:ivar _graph: Cached SynGraph for the substrate.
|
|
137
|
+
:vartype _graph: Optional[SynGraph]
|
|
138
|
+
:ivar _rule: Cached SynRule for the template.
|
|
139
|
+
:vartype _rule: Optional[SynRule]
|
|
140
|
+
:ivar _mappings: Cached list of subgraph-mapping dicts.
|
|
141
|
+
:vartype _mappings: Optional[List[MappingDict]]
|
|
142
|
+
:ivar _its: Cached list of ITS graphs.
|
|
143
|
+
:vartype _its: Optional[List[nx.Graph]]
|
|
144
|
+
:ivar _smarts: Cached list of SMARTS strings.
|
|
145
|
+
:vartype _smarts: Optional[List[str]]
|
|
146
|
+
:ivar _flag_pattern_has_explicit_H: Internal flag indicating
|
|
147
|
+
explicit-H constraints.
|
|
148
|
+
:vartype _flag_pattern_has_explicit_H: bool
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
substrate: Union[str, nx.Graph, SynGraph]
|
|
152
|
+
template: Union[str, nx.Graph, SynRule]
|
|
153
|
+
invert: bool = False
|
|
154
|
+
canonicaliser: GraphCanonicaliser | None = None
|
|
155
|
+
explicit_h: bool = True
|
|
156
|
+
implicit_temp: bool = False
|
|
157
|
+
strategy: Strategy | str = Strategy.ALL
|
|
158
|
+
partial: bool = False
|
|
159
|
+
template_format: ITSFormat = "typesGH"
|
|
160
|
+
electron_diagnostics: bool = False
|
|
161
|
+
radical_policy: str = "strict"
|
|
162
|
+
stereo_mode: str = "propagate"
|
|
163
|
+
stereo_query_mode: str = "exact"
|
|
164
|
+
stereo_semantics: str = "orbit"
|
|
165
|
+
embed_threshold: Optional[int] = None
|
|
166
|
+
embed_pre_filter: bool = False
|
|
167
|
+
automorphism: bool = True
|
|
168
|
+
preserve_mapped_hydrogens: bool = False
|
|
169
|
+
dedup_its: bool = True
|
|
170
|
+
product_deduplication: str = "structural"
|
|
171
|
+
stereo_assignment_limit: int | None = None
|
|
172
|
+
stereo_branch_limit: int | None = None
|
|
173
|
+
serialization_errors: str = "raise"
|
|
174
|
+
|
|
175
|
+
# Private caches – populated on demand -------------------------------
|
|
176
|
+
_graph: SynGraph | None = field(init=False, default=None, repr=False)
|
|
177
|
+
_rule: SynRule | None = field(init=False, default=None, repr=False)
|
|
178
|
+
_mappings: List[MappingDict] | None = field(init=False, default=None, repr=False)
|
|
179
|
+
_its: List[nx.Graph] | None = field(init=False, default=None, repr=False)
|
|
180
|
+
_smarts: List[str] | None = field(init=False, default=None, repr=False)
|
|
181
|
+
_serialization_failure_indices: Tuple[int, ...] = field(
|
|
182
|
+
init=False,
|
|
183
|
+
default=(),
|
|
184
|
+
repr=False,
|
|
185
|
+
)
|
|
186
|
+
_host_for_matching: nx.Graph | None = field(init=False, default=None, repr=False)
|
|
187
|
+
_stereo_semantic_diagnostics: List[Any] = field(
|
|
188
|
+
init=False,
|
|
189
|
+
default_factory=list,
|
|
190
|
+
repr=False,
|
|
191
|
+
)
|
|
192
|
+
_stereo_morphism_issues: List[Any] = field(
|
|
193
|
+
init=False,
|
|
194
|
+
default_factory=list,
|
|
195
|
+
repr=False,
|
|
196
|
+
)
|
|
197
|
+
_flag_pattern_has_explicit_H: bool = field(init=False, default=False, repr=False)
|
|
198
|
+
_stereo_branch_count: int = field(init=False, default=0, repr=False)
|
|
199
|
+
|
|
200
|
+
def __post_init__(self) -> None:
|
|
201
|
+
"""Validate and enforce consistency of `explicit_h` and
|
|
202
|
+
`implicit_temp`.
|
|
203
|
+
|
|
204
|
+
:raises ValueError: If `explicit_h` is True while `implicit_temp` is False.
|
|
205
|
+
"""
|
|
206
|
+
if self.implicit_temp and self.explicit_h:
|
|
207
|
+
raise ValueError(
|
|
208
|
+
"`explicit_h` cannot be True when `implicit_temp` is False."
|
|
209
|
+
)
|
|
210
|
+
if self.radical_policy not in {"strict", "lower_bound", "ignore"}:
|
|
211
|
+
raise ValueError(
|
|
212
|
+
"radical_policy must be 'strict', 'lower_bound', or 'ignore'."
|
|
213
|
+
)
|
|
214
|
+
if self.stereo_mode not in {"ignore", "require", "propagate", "strict"}:
|
|
215
|
+
raise ValueError(
|
|
216
|
+
"stereo_mode must be 'ignore', 'require', 'propagate', or 'strict'."
|
|
217
|
+
)
|
|
218
|
+
if self.stereo_query_mode not in {"exact", "wildcard"}:
|
|
219
|
+
raise ValueError("stereo_query_mode must be 'exact' or 'wildcard'.")
|
|
220
|
+
if self.stereo_semantics not in {"orbit", "legacy", "compare"}:
|
|
221
|
+
raise ValueError(
|
|
222
|
+
"stereo_semantics must be 'orbit', 'legacy', or 'compare'."
|
|
223
|
+
)
|
|
224
|
+
if not isinstance(self.dedup_its, bool):
|
|
225
|
+
raise TypeError("dedup_its must be a bool.")
|
|
226
|
+
if self.product_deduplication not in {"structural", "deferred"}:
|
|
227
|
+
raise ValueError(
|
|
228
|
+
"product_deduplication must be 'structural' or 'deferred'."
|
|
229
|
+
)
|
|
230
|
+
if self.product_deduplication == "deferred" and self.stereo_mode != "ignore":
|
|
231
|
+
raise ValueError(
|
|
232
|
+
"deferred product deduplication requires stereo_mode='ignore'."
|
|
233
|
+
)
|
|
234
|
+
if self.serialization_errors not in {"raise", "skip"}:
|
|
235
|
+
raise ValueError("serialization_errors must be 'raise' or 'skip'.")
|
|
236
|
+
if self.stereo_assignment_limit is not None and (
|
|
237
|
+
type(self.stereo_assignment_limit) is not int
|
|
238
|
+
or self.stereo_assignment_limit < 1
|
|
239
|
+
):
|
|
240
|
+
raise ValueError("stereo_assignment_limit must be a positive integer.")
|
|
241
|
+
if self.stereo_branch_limit is not None and (
|
|
242
|
+
type(self.stereo_branch_limit) is not int or self.stereo_branch_limit < 1
|
|
243
|
+
):
|
|
244
|
+
raise ValueError("stereo_branch_limit must be a positive integer.")
|
|
245
|
+
|
|
246
|
+
# ------------------------------------------------------------------
|
|
247
|
+
# Construction helpers
|
|
248
|
+
# ------------------------------------------------------------------
|
|
249
|
+
@classmethod
|
|
250
|
+
def from_smiles(
|
|
251
|
+
cls,
|
|
252
|
+
smiles: str,
|
|
253
|
+
template: Union[str, nx.Graph, SynRule],
|
|
254
|
+
*,
|
|
255
|
+
invert: bool = False,
|
|
256
|
+
canonicaliser: Optional[GraphCanonicaliser] = None,
|
|
257
|
+
explicit_h: bool = True,
|
|
258
|
+
implicit_temp: bool = False,
|
|
259
|
+
automorphism: bool = False,
|
|
260
|
+
strategy: Strategy | str = Strategy.ALL,
|
|
261
|
+
template_format: ITSFormat = "typesGH",
|
|
262
|
+
electron_diagnostics: bool = False,
|
|
263
|
+
radical_policy: str = "strict",
|
|
264
|
+
stereo_mode: str = "propagate",
|
|
265
|
+
stereo_query_mode: str = "exact",
|
|
266
|
+
stereo_semantics: str = "orbit",
|
|
267
|
+
preserve_mapped_hydrogens: bool = False,
|
|
268
|
+
dedup_its: bool = True,
|
|
269
|
+
product_deduplication: str = "structural",
|
|
270
|
+
serialization_errors: str = "raise",
|
|
271
|
+
stereo_assignment_limit: int | None = None,
|
|
272
|
+
stereo_branch_limit: int | None = None,
|
|
273
|
+
) -> "SynReactor":
|
|
274
|
+
"""Alternate constructor: build a SynReactor directly from SMILES.
|
|
275
|
+
|
|
276
|
+
:param smiles: SMILES string for the substrate.
|
|
277
|
+
:type smiles: str
|
|
278
|
+
:param template: Reaction template (SMILES/SMARTS string, Graph, or SynRule).
|
|
279
|
+
:type template: str or networkx.Graph or SynRule
|
|
280
|
+
:param invert: If True, perform backward prediction (target→precursors).
|
|
281
|
+
Defaults to False (forward prediction).
|
|
282
|
+
:type invert: bool
|
|
283
|
+
:param canonicaliser: Optional GraphCanonicaliser to use for internal graphs.
|
|
284
|
+
:type canonicaliser: GraphCanonicaliser or None
|
|
285
|
+
:param explicit_h: If True, keep explicit hydrogens in the reaction center.
|
|
286
|
+
:type explicit_h: bool
|
|
287
|
+
:param implicit_temp: If True, treat the template as implicit-H (forces explicit_h=False).
|
|
288
|
+
:type implicit_temp: bool
|
|
289
|
+
:param strategy: Matching strategy: ALL, 'comp', or 'bt'. Defaults to ALL.
|
|
290
|
+
:type strategy: Strategy or str
|
|
291
|
+
:param template_format: ITS representation used when ``template`` is a
|
|
292
|
+
reaction string. Defaults to ``"typesGH"``.
|
|
293
|
+
:type template_format: ITSFormat
|
|
294
|
+
:param electron_diagnostics: If True, expose per-result electron
|
|
295
|
+
diagnostics without changing products.
|
|
296
|
+
:type electron_diagnostics: bool
|
|
297
|
+
:param radical_policy: Radical matching policy: ``"strict"``,
|
|
298
|
+
``"lower_bound"``, or ``"ignore"``.
|
|
299
|
+
:type radical_policy: str
|
|
300
|
+
:param stereo_mode: Stereo application policy: chemical-relative
|
|
301
|
+
``"propagate"`` (default), fixed-template ``"ignore"``, or the
|
|
302
|
+
stereoisomer-selective ``"require"`` / ``"strict"`` modes.
|
|
303
|
+
:type stereo_mode: str
|
|
304
|
+
:param stereo_query_mode: Unknown-parity query policy, either
|
|
305
|
+
``"exact"`` or ``"wildcard"``.
|
|
306
|
+
:type stereo_query_mode: str
|
|
307
|
+
:param stereo_semantics: ``"orbit"``, ``"legacy"``, or ``"compare"``
|
|
308
|
+
reaction-stereo execution.
|
|
309
|
+
:type stereo_semantics: str
|
|
310
|
+
:param dedup_its: Consolidate equivalent post-rewrite ITS graphs while
|
|
311
|
+
preserving all correctness finalization and validation steps.
|
|
312
|
+
:type dedup_its: bool
|
|
313
|
+
:param product_deduplication: ``"structural"`` performs exact internal
|
|
314
|
+
application and ITS quotienting. ``"deferred"`` leaves endpoint
|
|
315
|
+
identity to downstream canonicalized serialization and requires
|
|
316
|
+
``stereo_mode="ignore"``.
|
|
317
|
+
:type product_deduplication: str
|
|
318
|
+
:param serialization_errors: Raw ITS serialization policy, either
|
|
319
|
+
``"raise"`` (default) or ``"skip"``.
|
|
320
|
+
:type serialization_errors: str
|
|
321
|
+
:param stereo_assignment_limit: Optional hard cap on exhaustive typed
|
|
322
|
+
stereo-port assignments.
|
|
323
|
+
:type stereo_assignment_limit: Optional[int]
|
|
324
|
+
:param stereo_branch_limit: Optional hard cap on generated stereo
|
|
325
|
+
product branches.
|
|
326
|
+
:type stereo_branch_limit: Optional[int]
|
|
327
|
+
:return: A new `SynReactor` instance.
|
|
328
|
+
:rtype: SynReactor
|
|
329
|
+
"""
|
|
330
|
+
return cls(
|
|
331
|
+
substrate=smiles,
|
|
332
|
+
template=template,
|
|
333
|
+
invert=invert,
|
|
334
|
+
canonicaliser=canonicaliser,
|
|
335
|
+
explicit_h=explicit_h,
|
|
336
|
+
implicit_temp=implicit_temp,
|
|
337
|
+
strategy=strategy,
|
|
338
|
+
automorphism=automorphism,
|
|
339
|
+
template_format=template_format,
|
|
340
|
+
electron_diagnostics=electron_diagnostics,
|
|
341
|
+
radical_policy=radical_policy,
|
|
342
|
+
stereo_mode=stereo_mode,
|
|
343
|
+
stereo_query_mode=stereo_query_mode,
|
|
344
|
+
stereo_semantics=stereo_semantics,
|
|
345
|
+
preserve_mapped_hydrogens=preserve_mapped_hydrogens,
|
|
346
|
+
dedup_its=dedup_its,
|
|
347
|
+
product_deduplication=product_deduplication,
|
|
348
|
+
serialization_errors=serialization_errors,
|
|
349
|
+
stereo_assignment_limit=stereo_assignment_limit,
|
|
350
|
+
stereo_branch_limit=stereo_branch_limit,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# ------------------------------------------------------------------
|
|
354
|
+
# Public read‑only properties (lazily computed) ----------------------
|
|
355
|
+
# ------------------------------------------------------------------
|
|
356
|
+
@property
|
|
357
|
+
def stereo_semantic_diagnostics(self) -> tuple[Any, ...]:
|
|
358
|
+
"""Return accumulated orbit/legacy mapping and application audits."""
|
|
359
|
+
return tuple(self._stereo_semantic_diagnostics)
|
|
360
|
+
|
|
361
|
+
@property
|
|
362
|
+
def stereo_morphism_issues(self) -> tuple[Any, ...]:
|
|
363
|
+
"""Return structured reasons rejected typed stereo mappings failed."""
|
|
364
|
+
return tuple(self._stereo_morphism_issues)
|
|
365
|
+
|
|
366
|
+
@property
|
|
367
|
+
def serialization_failure_indices(self) -> Tuple[int, ...]:
|
|
368
|
+
"""Return raw ITS indices omitted or rejected during serialization."""
|
|
369
|
+
return self._serialization_failure_indices
|
|
370
|
+
|
|
371
|
+
@property
|
|
372
|
+
def graph(self) -> SynGraph: # noqa: D401 – read‑only property
|
|
373
|
+
"""Lazily wrap the substrate into a SynGraph.
|
|
374
|
+
:return: The reaction substrate as a `SynGraph`.
|
|
375
|
+
:rtype: SynGraph
|
|
376
|
+
"""
|
|
377
|
+
if self._graph is None:
|
|
378
|
+
self._graph = self._wrap_input(self.substrate)
|
|
379
|
+
return self._graph
|
|
380
|
+
|
|
381
|
+
@property
|
|
382
|
+
def rule(self) -> SynRule: # noqa: D401
|
|
383
|
+
"""Lazily wrap the template into a SynRule.
|
|
384
|
+
:return: The reaction template as a `SynRule`.
|
|
385
|
+
:rtype: SynRule
|
|
386
|
+
"""
|
|
387
|
+
if self._rule is None:
|
|
388
|
+
self._rule = self._wrap_template(self.template)
|
|
389
|
+
return self._rule
|
|
390
|
+
|
|
391
|
+
@property
|
|
392
|
+
def its_list(self) -> List[nx.Graph]:
|
|
393
|
+
"""Build ITS graphs for exact rewrite representatives.
|
|
394
|
+
:return: A list of ITS (Internal Transition State) graphs.
|
|
395
|
+
"""
|
|
396
|
+
if self._its is None:
|
|
397
|
+
host_raw = self._matching_host_graph()
|
|
398
|
+
rc_raw = self.rule.rc.raw
|
|
399
|
+
pattern_explicit = self.rule.left.raw
|
|
400
|
+
strategy = Strategy.from_string(self.strategy)
|
|
401
|
+
relative_pi_edges = self._relative_pi_rewrite_edges(rc_raw)
|
|
402
|
+
electron_aware = self._is_electron_aware_template(rc_raw)
|
|
403
|
+
stereo_substitutions = self._typed_stereo_wildcard_substitutions(
|
|
404
|
+
pattern_explicit
|
|
405
|
+
)
|
|
406
|
+
certified_generic = bool(
|
|
407
|
+
self.rule.rc.raw.graph.get("generic_stereo_extraction")
|
|
408
|
+
)
|
|
409
|
+
application_mappings = self.mappings
|
|
410
|
+
stereo_sensitive = bool(
|
|
411
|
+
self.rule.stereo_guards
|
|
412
|
+
or self.rule.stereo_effects
|
|
413
|
+
or self.rule.stereo_outcomes
|
|
414
|
+
or self.rule.stereo_couplings
|
|
415
|
+
)
|
|
416
|
+
exact_endpoint_certificate = (
|
|
417
|
+
self.dedup_its
|
|
418
|
+
and self.product_deduplication == "structural"
|
|
419
|
+
and not host_raw.is_directed()
|
|
420
|
+
and not host_raw.is_multigraph()
|
|
421
|
+
)
|
|
422
|
+
if (
|
|
423
|
+
self.dedup_its
|
|
424
|
+
and self.product_deduplication == "structural"
|
|
425
|
+
and not certified_generic
|
|
426
|
+
and not stereo_sensitive
|
|
427
|
+
and not exact_endpoint_certificate
|
|
428
|
+
):
|
|
429
|
+
mapping_population = len(application_mappings)
|
|
430
|
+
application_mappings = self._deduplicate_rewrite_equivalent_mappings(
|
|
431
|
+
application_mappings,
|
|
432
|
+
host_raw,
|
|
433
|
+
rc_raw,
|
|
434
|
+
)
|
|
435
|
+
log.debug(
|
|
436
|
+
"Rewrite-equivalence quotient: %d -> %d application(s)",
|
|
437
|
+
mapping_population,
|
|
438
|
+
len(application_mappings),
|
|
439
|
+
)
|
|
440
|
+
elif exact_endpoint_certificate and not certified_generic:
|
|
441
|
+
# Complete mapping enumeration followed by an injective
|
|
442
|
+
# canonical certificate is exact and cheaper here than an
|
|
443
|
+
# additional sufficient-but-not-necessary source quotient.
|
|
444
|
+
# The finalized endpoint certificate remains the only merge
|
|
445
|
+
# authority, so no application is discarded heuristically.
|
|
446
|
+
log.debug(
|
|
447
|
+
"Retained %d application(s) for exact endpoint certificates",
|
|
448
|
+
len(application_mappings),
|
|
449
|
+
)
|
|
450
|
+
rewrite_host, rewrite_host_prepared = (
|
|
451
|
+
_graph_rewrite._prepare_rewrite_batch_host(
|
|
452
|
+
host_raw,
|
|
453
|
+
application_mappings,
|
|
454
|
+
rc_raw,
|
|
455
|
+
self._flag_pattern_has_explicit_H,
|
|
456
|
+
electron_aware,
|
|
457
|
+
seed_structural_signatures=(
|
|
458
|
+
self.dedup_its and self.product_deduplication == "structural"
|
|
459
|
+
),
|
|
460
|
+
)
|
|
461
|
+
)
|
|
462
|
+
self._its = []
|
|
463
|
+
expanded_host_cache: Dict[frozenset[Any], nx.Graph] = {}
|
|
464
|
+
self._stereo_branch_count = 0
|
|
465
|
+
raw_application_index = 0
|
|
466
|
+
for mapping_index, m in enumerate(application_mappings):
|
|
467
|
+
retain_provenance = not self.dedup_its or certified_generic
|
|
468
|
+
mapping_provenance = (
|
|
469
|
+
self._mapping_provenance(m, pattern_explicit, host_raw)
|
|
470
|
+
if retain_provenance
|
|
471
|
+
else ()
|
|
472
|
+
)
|
|
473
|
+
port_assignment = tuple(
|
|
474
|
+
pair
|
|
475
|
+
for pair in mapping_provenance
|
|
476
|
+
if pair[0]
|
|
477
|
+
in {
|
|
478
|
+
pattern_explicit.nodes[node].get("atom_map", node)
|
|
479
|
+
for node in stereo_substitutions
|
|
480
|
+
}
|
|
481
|
+
)
|
|
482
|
+
stereo_proof = (
|
|
483
|
+
self._stereo_application_provenance(
|
|
484
|
+
pattern_explicit,
|
|
485
|
+
host_raw,
|
|
486
|
+
m,
|
|
487
|
+
stereo_substitutions,
|
|
488
|
+
)
|
|
489
|
+
if certified_generic
|
|
490
|
+
else None
|
|
491
|
+
)
|
|
492
|
+
its_batch = _graph_rewrite._glue_graph(
|
|
493
|
+
rewrite_host,
|
|
494
|
+
rc_raw,
|
|
495
|
+
m,
|
|
496
|
+
self._flag_pattern_has_explicit_H,
|
|
497
|
+
pattern_explicit,
|
|
498
|
+
strategy,
|
|
499
|
+
embed_threshold=self.embed_threshold,
|
|
500
|
+
embed_pre_filter=False,
|
|
501
|
+
relative_pi_edges=relative_pi_edges,
|
|
502
|
+
restore_unmatched_explicit_h=not self.explicit_h,
|
|
503
|
+
refresh_electrons=False,
|
|
504
|
+
electron_aware=electron_aware,
|
|
505
|
+
relative_match_resources=(
|
|
506
|
+
frozenset({"radical"})
|
|
507
|
+
if self.radical_policy == "lower_bound"
|
|
508
|
+
else frozenset()
|
|
509
|
+
),
|
|
510
|
+
anchor_explicit_embedding=self.dedup_its,
|
|
511
|
+
host_prepared=rewrite_host_prepared,
|
|
512
|
+
expanded_host_cache=expanded_host_cache,
|
|
513
|
+
consume_prepared_host=(
|
|
514
|
+
rewrite_host_prepared
|
|
515
|
+
and mapping_index == len(application_mappings) - 1
|
|
516
|
+
),
|
|
517
|
+
)
|
|
518
|
+
stereo_batch: List[nx.Graph] = []
|
|
519
|
+
for rewrite_index, candidate in enumerate(its_batch):
|
|
520
|
+
branches = self._apply_stereo_rule_metadata(candidate, host_raw, m)
|
|
521
|
+
if retain_provenance:
|
|
522
|
+
for stereo_branch_index, branch in enumerate(branches):
|
|
523
|
+
provenance = {
|
|
524
|
+
"application_index": raw_application_index,
|
|
525
|
+
"mapping_index": mapping_index,
|
|
526
|
+
"rewrite_index": rewrite_index,
|
|
527
|
+
"stereo_branch_index": stereo_branch_index,
|
|
528
|
+
"mapping": mapping_provenance,
|
|
529
|
+
"port_assignment": port_assignment,
|
|
530
|
+
}
|
|
531
|
+
if stereo_proof is not None:
|
|
532
|
+
provenance["stereo_morphism"] = stereo_proof
|
|
533
|
+
branch.graph["application_provenance"] = provenance
|
|
534
|
+
if certified_generic:
|
|
535
|
+
branch.graph["application_orbit"] = {
|
|
536
|
+
"multiplicity": 1,
|
|
537
|
+
"applications": [provenance],
|
|
538
|
+
}
|
|
539
|
+
raw_application_index += 1
|
|
540
|
+
stereo_batch.extend(branches)
|
|
541
|
+
self._its.extend(stereo_batch)
|
|
542
|
+
if self.explicit_h:
|
|
543
|
+
self._its = [self._explicit_h(g) for g in self._its]
|
|
544
|
+
self._its = [
|
|
545
|
+
its for its in self._its if self._validate_product_stereo_registry(its)
|
|
546
|
+
]
|
|
547
|
+
if self.dedup_its:
|
|
548
|
+
if self.product_deduplication == "structural":
|
|
549
|
+
self._its = self._deduplicate_coupling_face_products(self._its)
|
|
550
|
+
self._its = self._deduplicate_structural_its(self._its)
|
|
551
|
+
else:
|
|
552
|
+
self._its = self._finalize_product_electron_fields(self._its)
|
|
553
|
+
else:
|
|
554
|
+
self._its = self._finalize_product_electron_fields(self._its)
|
|
555
|
+
log.debug("Built %d ITS graph(s)", len(self._its))
|
|
556
|
+
return self._its
|
|
557
|
+
|
|
558
|
+
@property
|
|
559
|
+
def smarts_list(self) -> List[str]:
|
|
560
|
+
"""Serialise each ITS graph to a reaction-SMARTS string.
|
|
561
|
+
:return: A list of SMARTS strings (inverted if `invert=True`).
|
|
562
|
+
"""
|
|
563
|
+
if self._smarts is None:
|
|
564
|
+
serializer_parameters = inspect.signature(self._to_smarts).parameters
|
|
565
|
+
cache_supported = {
|
|
566
|
+
"reactant_smiles",
|
|
567
|
+
"preserved_hydrogen_maps",
|
|
568
|
+
}.issubset(serializer_parameters)
|
|
569
|
+
reactant_cache: Dict[Tuple[int, ...], str] = {}
|
|
570
|
+
serialized = []
|
|
571
|
+
for graph in self.its_list:
|
|
572
|
+
if (
|
|
573
|
+
not cache_supported
|
|
574
|
+
or self._flag_pattern_has_explicit_H
|
|
575
|
+
or not graph.graph.get("electron_aware_rewrite", False)
|
|
576
|
+
):
|
|
577
|
+
serialized.append(self._to_smarts(graph))
|
|
578
|
+
continue
|
|
579
|
+
preserved = tuple(self._tuple_preserved_hydrogen_maps(graph))
|
|
580
|
+
cached_reactant = reactant_cache.get(preserved)
|
|
581
|
+
value = self._to_smarts(
|
|
582
|
+
graph,
|
|
583
|
+
reactant_smiles=cached_reactant,
|
|
584
|
+
preserved_hydrogen_maps=preserved,
|
|
585
|
+
)
|
|
586
|
+
serialized.append(value)
|
|
587
|
+
if value is not None and cached_reactant is None:
|
|
588
|
+
reactant_cache[preserved] = value.partition(">>")[0]
|
|
589
|
+
failed = tuple(
|
|
590
|
+
index for index, value in enumerate(serialized) if value is None
|
|
591
|
+
)
|
|
592
|
+
self._serialization_failure_indices = failed if not self.dedup_its else ()
|
|
593
|
+
if not self.dedup_its and failed:
|
|
594
|
+
if self.serialization_errors == "raise":
|
|
595
|
+
raise ValueError(
|
|
596
|
+
"Could not serialize raw ITS application(s): "
|
|
597
|
+
+ ", ".join(map(str, failed))
|
|
598
|
+
)
|
|
599
|
+
warnings.warn(
|
|
600
|
+
RawITSApplicationSerializationWarning(failed),
|
|
601
|
+
stacklevel=2,
|
|
602
|
+
)
|
|
603
|
+
smarts = [value for value in serialized if value]
|
|
604
|
+
if self.invert:
|
|
605
|
+
smarts = [reverse_reaction(rsmi) for rsmi in smarts]
|
|
606
|
+
if self.dedup_its:
|
|
607
|
+
smarts = list(dict.fromkeys(smarts))
|
|
608
|
+
self._smarts = smarts
|
|
609
|
+
return self._smarts
|
|
610
|
+
|
|
611
|
+
@property
|
|
612
|
+
def diagnostics(self) -> List[Dict[str, Any]]:
|
|
613
|
+
"""Return optional electron-accounting diagnostics for built ITS graphs."""
|
|
614
|
+
if not self.electron_diagnostics:
|
|
615
|
+
return []
|
|
616
|
+
|
|
617
|
+
reports: List[Dict[str, Any]] = []
|
|
618
|
+
for index, its in enumerate(self.its_list):
|
|
619
|
+
if its.graph.get("electron_aware_rewrite", False):
|
|
620
|
+
mismatches = {}
|
|
621
|
+
for node, attrs in its.nodes(data=True):
|
|
622
|
+
charge_mismatch = attrs.get("charge_mismatch")
|
|
623
|
+
mismatch = (
|
|
624
|
+
charge_mismatch[1]
|
|
625
|
+
if isinstance(charge_mismatch, tuple)
|
|
626
|
+
and len(charge_mismatch) == 2
|
|
627
|
+
else charge_mismatch
|
|
628
|
+
)
|
|
629
|
+
if mismatch:
|
|
630
|
+
template_charge = attrs.get("template_charge")
|
|
631
|
+
recomputed_charge = attrs.get("recomputed_charge")
|
|
632
|
+
mismatches[node] = {
|
|
633
|
+
"charge": (
|
|
634
|
+
template_charge[1]
|
|
635
|
+
if isinstance(template_charge, tuple)
|
|
636
|
+
and len(template_charge) == 2
|
|
637
|
+
else template_charge
|
|
638
|
+
),
|
|
639
|
+
"recomputed_charge": (
|
|
640
|
+
recomputed_charge[1]
|
|
641
|
+
if isinstance(recomputed_charge, tuple)
|
|
642
|
+
and len(recomputed_charge) == 2
|
|
643
|
+
else recomputed_charge
|
|
644
|
+
),
|
|
645
|
+
}
|
|
646
|
+
else:
|
|
647
|
+
product = self._product_graph_for_diagnostics(its)
|
|
648
|
+
refreshed = refresh_electron_fields(product)
|
|
649
|
+
mismatches = {
|
|
650
|
+
node: {
|
|
651
|
+
"charge": attrs.get("charge"),
|
|
652
|
+
"recomputed_charge": attrs.get("recomputed_charge"),
|
|
653
|
+
}
|
|
654
|
+
for node, attrs in refreshed.nodes(data=True)
|
|
655
|
+
if attrs.get("charge_mismatch")
|
|
656
|
+
}
|
|
657
|
+
reports.append(
|
|
658
|
+
{
|
|
659
|
+
"index": index,
|
|
660
|
+
"electron_aware_rewrite": bool(
|
|
661
|
+
its.graph.get("electron_aware_rewrite", False)
|
|
662
|
+
),
|
|
663
|
+
"mismatch_count": len(mismatches),
|
|
664
|
+
"mismatches": mismatches,
|
|
665
|
+
}
|
|
666
|
+
)
|
|
667
|
+
return reports
|
|
668
|
+
|
|
669
|
+
# Backward‑compat aliases (original attribute names) ----------------
|
|
670
|
+
smarts = property(lambda self: self.smarts_list)
|
|
671
|
+
its = property(lambda self: self.its_list)
|
|
672
|
+
_mappings_prop = property(lambda self: self.mappings, doc="Alias for compatibility")
|
|
673
|
+
|
|
674
|
+
# Convenience re‑exports -------------------------------------------
|
|
675
|
+
mapping_count = property(lambda self: len(self.mappings), doc="Number of mappings")
|
|
676
|
+
smiles_list = property(lambda self: [s.split(">>")[-1] for s in self.smarts_list])
|
|
677
|
+
substrate_smiles = property(lambda self: graph_to_smi(self.graph.raw))
|
|
678
|
+
|
|
679
|
+
# ------------------------------------------------------------------
|
|
680
|
+
# String‑likes ------------------------------------------------------
|
|
681
|
+
# ------------------------------------------------------------------
|
|
682
|
+
def __str__(self) -> str: # pragma: no cover
|
|
683
|
+
return (
|
|
684
|
+
f"<SynReactor atoms={self.graph.raw.number_of_nodes()} "
|
|
685
|
+
f"mappings={self.mapping_count}>"
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
__repr__ = __str__
|
|
689
|
+
|
|
690
|
+
# ------------------------------------------------------------------
|
|
691
|
+
# Public helper -----------------------------------------------------
|
|
692
|
+
# ------------------------------------------------------------------
|
|
693
|
+
def help(
|
|
694
|
+
self, print_results=False
|
|
695
|
+
) -> None: # pragma: no cover – human‑oriented output
|
|
696
|
+
print("SynReactor")
|
|
697
|
+
print(" Substrate :", self.substrate_smiles)
|
|
698
|
+
print(" Template :", self.rule)
|
|
699
|
+
print(" Implicit Template :", self.implicit_temp)
|
|
700
|
+
print(" Invert rule :", self.invert)
|
|
701
|
+
print(" Strategy :", Strategy.from_string(self.strategy).value)
|
|
702
|
+
print(" Predictions :", self.mapping_count)
|
|
703
|
+
if print_results:
|
|
704
|
+
for i, s in enumerate(self.smarts_list, 1):
|
|
705
|
+
print(f" SMARTS[{i:02d}] : {s}")
|
|
706
|
+
else:
|
|
707
|
+
print(f" First result : {self.smarts_list[0]}")
|
|
708
|
+
|
|
709
|
+
# ==================================================================
|
|
710
|
+
# Private – wrapping / canonicalising
|
|
711
|
+
# ==================================================================
|
|
712
|
+
def _wrap_input(self, obj: Union[str, nx.Graph, SynGraph]) -> SynGraph:
|
|
713
|
+
if isinstance(obj, SynGraph):
|
|
714
|
+
return obj
|
|
715
|
+
if isinstance(obj, nx.Graph):
|
|
716
|
+
return SynGraph(obj, self.canonicaliser or GraphCanonicaliser())
|
|
717
|
+
if isinstance(obj, str):
|
|
718
|
+
graph = smiles_to_graph(
|
|
719
|
+
obj, use_index_as_atom_map=False, drop_non_aam=False
|
|
720
|
+
)
|
|
721
|
+
return SynGraph(graph, self.canonicaliser or GraphCanonicaliser())
|
|
722
|
+
raise TypeError(f"Unsupported substrate type: {type(obj)}")
|
|
723
|
+
|
|
724
|
+
def _wrap_template(self, tpl: Union[str, nx.Graph, SynRule]) -> SynRule:
|
|
725
|
+
# Return early when incoming SynRule matches desired orientation
|
|
726
|
+
if not self.invert and isinstance(tpl, SynRule):
|
|
727
|
+
return tpl
|
|
728
|
+
|
|
729
|
+
# Convert to raw graph ------------------------------------------------
|
|
730
|
+
if isinstance(tpl, SynRule):
|
|
731
|
+
graph = tpl.rc.raw # raw reaction‑core graph
|
|
732
|
+
elif isinstance(tpl, nx.Graph):
|
|
733
|
+
graph = tpl
|
|
734
|
+
elif isinstance(tpl, str):
|
|
735
|
+
graph = rsmi_to_its(tpl, format=self.template_format)
|
|
736
|
+
else: # pragma: no cover
|
|
737
|
+
raise TypeError(f"Unsupported template type: {type(tpl)}")
|
|
738
|
+
# graph = normalize_h_pair_graph(graph)
|
|
739
|
+
|
|
740
|
+
format = detect_its_format(graph)
|
|
741
|
+
|
|
742
|
+
# Invert if asked -----------------------------------------------------
|
|
743
|
+
if self.invert:
|
|
744
|
+
if isinstance(tpl, SynRule):
|
|
745
|
+
return tpl.reversed(
|
|
746
|
+
balance_its=self.implicit_temp,
|
|
747
|
+
semantics=self.stereo_semantics,
|
|
748
|
+
diagnostics=self._stereo_semantic_diagnostics,
|
|
749
|
+
)
|
|
750
|
+
rich_reverse = isinstance(tpl, nx.Graph) and any(
|
|
751
|
+
key in graph.graph
|
|
752
|
+
for key in (
|
|
753
|
+
"stereo_outcomes",
|
|
754
|
+
"stereo_couplings",
|
|
755
|
+
"stereo_query_policies",
|
|
756
|
+
"stereo_reverse_outcomes",
|
|
757
|
+
)
|
|
758
|
+
)
|
|
759
|
+
audited_reverse = self.stereo_semantics != "orbit" and bool(
|
|
760
|
+
graph.graph.get("stereo_changes")
|
|
761
|
+
)
|
|
762
|
+
if rich_reverse or audited_reverse:
|
|
763
|
+
return SynRule(
|
|
764
|
+
graph,
|
|
765
|
+
canonicaliser=self.canonicaliser or GraphCanonicaliser(),
|
|
766
|
+
format=format,
|
|
767
|
+
).reversed(
|
|
768
|
+
balance_its=self.implicit_temp,
|
|
769
|
+
semantics=self.stereo_semantics,
|
|
770
|
+
diagnostics=self._stereo_semantic_diagnostics,
|
|
771
|
+
)
|
|
772
|
+
if self.implicit_temp:
|
|
773
|
+
graph = self._invert_template(
|
|
774
|
+
graph,
|
|
775
|
+
balance_its=True,
|
|
776
|
+
format=format,
|
|
777
|
+
)
|
|
778
|
+
return SynRule(
|
|
779
|
+
graph,
|
|
780
|
+
canonicaliser=self.canonicaliser or GraphCanonicaliser(),
|
|
781
|
+
format=format,
|
|
782
|
+
)
|
|
783
|
+
else:
|
|
784
|
+
graph = self._invert_template(
|
|
785
|
+
graph,
|
|
786
|
+
balance_its=False,
|
|
787
|
+
format=format,
|
|
788
|
+
)
|
|
789
|
+
return SynRule(
|
|
790
|
+
graph,
|
|
791
|
+
canonicaliser=self.canonicaliser or GraphCanonicaliser(),
|
|
792
|
+
format=format,
|
|
793
|
+
)
|
|
794
|
+
else:
|
|
795
|
+
if self.implicit_temp:
|
|
796
|
+
return SynRule(
|
|
797
|
+
graph,
|
|
798
|
+
canonicaliser=self.canonicaliser or GraphCanonicaliser(),
|
|
799
|
+
format=format,
|
|
800
|
+
)
|
|
801
|
+
return SynRule(
|
|
802
|
+
graph,
|
|
803
|
+
canonicaliser=self.canonicaliser or GraphCanonicaliser(),
|
|
804
|
+
format=format,
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
@staticmethod
|
|
808
|
+
def _implicit_heavy_hydrogens(
|
|
809
|
+
graph: nx.Graph,
|
|
810
|
+
*,
|
|
811
|
+
preserve_mapped_hydrogens: bool = False,
|
|
812
|
+
) -> nx.Graph:
|
|
813
|
+
return _graph_rewrite._implicit_heavy_hydrogens(
|
|
814
|
+
graph,
|
|
815
|
+
preserve_mapped_hydrogens=preserve_mapped_hydrogens,
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
@staticmethod
|
|
819
|
+
def _invert_template(
|
|
820
|
+
tpl: nx.Graph,
|
|
821
|
+
balance_its: bool = True,
|
|
822
|
+
format: ITSFormat | None = None,
|
|
823
|
+
) -> nx.Graph:
|
|
824
|
+
return _graph_rewrite._invert_template(tpl, balance_its, format)
|
|
825
|
+
|
|
826
|
+
@staticmethod
|
|
827
|
+
def _node_glue(
|
|
828
|
+
host_n: Dict[str, Any],
|
|
829
|
+
pat_n: Dict[str, Any],
|
|
830
|
+
key: str = "typesGH",
|
|
831
|
+
) -> None:
|
|
832
|
+
_graph_rewrite._node_glue(host_n, pat_n, key)
|
|
833
|
+
|
|
834
|
+
@staticmethod
|
|
835
|
+
def _get_explicit_map(
|
|
836
|
+
host: nx.Graph,
|
|
837
|
+
mapping: MappingDict,
|
|
838
|
+
pattern_explicit: nx.Graph | None = None,
|
|
839
|
+
strategy: Strategy = Strategy.ALL,
|
|
840
|
+
embed_threshold: float = None,
|
|
841
|
+
embed_pre_filter: bool = False,
|
|
842
|
+
):
|
|
843
|
+
return _graph_rewrite._get_explicit_map(
|
|
844
|
+
host,
|
|
845
|
+
mapping,
|
|
846
|
+
pattern_explicit,
|
|
847
|
+
strategy,
|
|
848
|
+
embed_threshold,
|
|
849
|
+
embed_pre_filter,
|
|
850
|
+
)
|
|
851
|
+
|
|
852
|
+
@staticmethod
|
|
853
|
+
def _mapping_atom_map_alignment(
|
|
854
|
+
pattern: nx.Graph,
|
|
855
|
+
host: nx.Graph,
|
|
856
|
+
mapping: MappingDict,
|
|
857
|
+
) -> int:
|
|
858
|
+
return _graph_rewrite._mapping_atom_map_alignment(pattern, host, mapping)
|
|
859
|
+
|
|
860
|
+
@staticmethod
|
|
861
|
+
def _restore_unmatched_pattern_hydrogens(
|
|
862
|
+
graph: nx.Graph,
|
|
863
|
+
mapping: MappingDict,
|
|
864
|
+
) -> None:
|
|
865
|
+
_graph_rewrite._restore_unmatched_pattern_hydrogens(graph, mapping)
|
|
866
|
+
|
|
867
|
+
@staticmethod
|
|
868
|
+
def _glue_graph(
|
|
869
|
+
host: nx.Graph,
|
|
870
|
+
rc: nx.Graph,
|
|
871
|
+
mapping: MappingDict,
|
|
872
|
+
pattern_has_explicit_H: bool = False,
|
|
873
|
+
pattern_explicit: nx.Graph | None = None,
|
|
874
|
+
strategy: Strategy = Strategy.ALL,
|
|
875
|
+
embed_threshold: float = None,
|
|
876
|
+
embed_pre_filter: bool = False,
|
|
877
|
+
relative_pi_edges: set[frozenset[Any]] | None = None,
|
|
878
|
+
restore_unmatched_explicit_h: bool = True,
|
|
879
|
+
refresh_electrons: bool = True,
|
|
880
|
+
electron_aware: bool | None = None,
|
|
881
|
+
relative_match_resources: frozenset[str] = frozenset(),
|
|
882
|
+
anchor_explicit_embedding: bool = True,
|
|
883
|
+
) -> List[nx.Graph]:
|
|
884
|
+
return _graph_rewrite._glue_graph(
|
|
885
|
+
host,
|
|
886
|
+
rc,
|
|
887
|
+
mapping,
|
|
888
|
+
pattern_has_explicit_H,
|
|
889
|
+
pattern_explicit,
|
|
890
|
+
strategy,
|
|
891
|
+
embed_threshold,
|
|
892
|
+
embed_pre_filter,
|
|
893
|
+
relative_pi_edges,
|
|
894
|
+
restore_unmatched_explicit_h,
|
|
895
|
+
refresh_electrons,
|
|
896
|
+
electron_aware,
|
|
897
|
+
relative_match_resources,
|
|
898
|
+
anchor_explicit_embedding,
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
_is_electron_aware_template = staticmethod(
|
|
902
|
+
_graph_rewrite._is_electron_aware_template
|
|
903
|
+
)
|
|
904
|
+
_merge_application_orbits = staticmethod(_deduplication._merge_application_orbits)
|
|
905
|
+
_chemical_rewrite_role = staticmethod(_deduplication._chemical_rewrite_role)
|
|
906
|
+
_prepare_its_for_structural_cluster = staticmethod(
|
|
907
|
+
_structural_deduplication._prepare_its_for_structural_cluster
|
|
908
|
+
)
|
|
909
|
+
_cluster_structural_its = staticmethod(
|
|
910
|
+
_structural_deduplication._cluster_structural_its
|
|
911
|
+
)
|
|
912
|
+
_finalize_product_electron_fields = staticmethod(
|
|
913
|
+
_deduplication._finalize_product_electron_fields
|
|
914
|
+
)
|
|
915
|
+
_deduplicate_structural_its = staticmethod(
|
|
916
|
+
_deduplication._deduplicate_structural_its
|
|
917
|
+
)
|
|
918
|
+
_deduplicate_coupling_face_products = staticmethod(
|
|
919
|
+
_deduplication._deduplicate_coupling_face_products
|
|
920
|
+
)
|
|
921
|
+
_deduplicate_rewrite_equivalent_mappings = staticmethod(
|
|
922
|
+
_deduplication._deduplicate_rewrite_equivalent_mappings
|
|
923
|
+
)
|
|
924
|
+
_components_are_equivalent = staticmethod(_deduplication._components_are_equivalent)
|
|
925
|
+
_pair_electron_aware_node_attrs = staticmethod(
|
|
926
|
+
_product_state._pair_electron_aware_node_attrs
|
|
927
|
+
)
|
|
928
|
+
_ensure_host_atom_maps = staticmethod(_product_state._ensure_host_atom_maps)
|
|
929
|
+
_refresh_product_electron_fields = staticmethod(
|
|
930
|
+
_product_state._refresh_product_electron_fields
|
|
931
|
+
)
|
|
932
|
+
_refresh_product_electron_fields_direct = staticmethod(
|
|
933
|
+
_product_state._refresh_product_electron_fields_direct
|
|
934
|
+
)
|
|
935
|
+
_product_kekule_phase_is_dirty = staticmethod(
|
|
936
|
+
_product_state._product_kekule_phase_is_dirty
|
|
937
|
+
)
|
|
938
|
+
_prepared_electron_product_graph = staticmethod(
|
|
939
|
+
_product_state._prepared_electron_product_graph
|
|
940
|
+
)
|
|
941
|
+
_electron_product_charge = staticmethod(_product_state._electron_product_charge)
|
|
942
|
+
_reperceive_product_kekule_phase = staticmethod(
|
|
943
|
+
_product_state._reperceive_product_kekule_phase
|
|
944
|
+
)
|
|
945
|
+
_product_graph_for_diagnostics = staticmethod(
|
|
946
|
+
_product_state._product_graph_for_diagnostics
|
|
947
|
+
)
|
|
948
|
+
_explicit_h = staticmethod(_serialization._explicit_h)
|
|
949
|
+
_explicit_h_tuple = staticmethod(_serialization._explicit_h_tuple)
|
|
950
|
+
_ensure_tuple_atom_maps = staticmethod(_serialization._ensure_tuple_atom_maps)
|
|
951
|
+
_tuple_preserved_hydrogen_maps = staticmethod(
|
|
952
|
+
_serialization._tuple_preserved_hydrogen_maps
|
|
953
|
+
)
|
|
954
|
+
_tuple_endpoint_graphs = staticmethod(_serialization._tuple_endpoint_graphs)
|
|
955
|
+
|
|
956
|
+
@staticmethod
|
|
957
|
+
def _to_smarts(
|
|
958
|
+
its: nx.Graph,
|
|
959
|
+
*,
|
|
960
|
+
reactant_smiles: Optional[str] = None,
|
|
961
|
+
preserved_hydrogen_maps: Optional[Tuple[int, ...]] = None,
|
|
962
|
+
) -> str:
|
|
963
|
+
return _serialization._to_smarts(
|
|
964
|
+
its,
|
|
965
|
+
reactant_smiles=reactant_smiles,
|
|
966
|
+
preserved_hydrogen_maps=preserved_hydrogen_maps,
|
|
967
|
+
)
|