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,506 @@
|
|
|
1
|
+
"""Template preparation and reaction execution for the RBL engine."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
from collections import Counter
|
|
7
|
+
from typing import Any, Dict, List, Optional, Sequence, Union
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from typing import Self
|
|
11
|
+
except ImportError:
|
|
12
|
+
from typing_extensions import Self
|
|
13
|
+
|
|
14
|
+
import networkx as nx
|
|
15
|
+
|
|
16
|
+
from synkit.Chem.utils import reverse_reaction
|
|
17
|
+
from synkit.Rule.syn_rule import SynRule
|
|
18
|
+
from synkit.Synthesis.RBL.validation import (
|
|
19
|
+
FusionIssue,
|
|
20
|
+
FusionIssueCode,
|
|
21
|
+
FusionValidation,
|
|
22
|
+
WildcardRole,
|
|
23
|
+
validate_fusion_rsmi,
|
|
24
|
+
)
|
|
25
|
+
from synkit.Synthesis.RBL.policy import AcceptanceTask
|
|
26
|
+
|
|
27
|
+
ITSLike = Any
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class RBLReactionMixin:
|
|
31
|
+
@staticmethod
|
|
32
|
+
def _normalize_duplicate_atom_maps(graph: nx.Graph) -> nx.Graph:
|
|
33
|
+
"""Assign deterministic unique AAM labels when fused sources collide."""
|
|
34
|
+
result = graph.copy()
|
|
35
|
+
|
|
36
|
+
def endpoint_maps(value: Any) -> tuple[Any, ...]:
|
|
37
|
+
if isinstance(value, (tuple, list)) and len(value) == 2:
|
|
38
|
+
return tuple(value)
|
|
39
|
+
return (value,)
|
|
40
|
+
|
|
41
|
+
seen: List[set[Any]] = [set(), set()]
|
|
42
|
+
duplicate = False
|
|
43
|
+
for _, data in result.nodes(data=True):
|
|
44
|
+
values = endpoint_maps(data.get("atom_map"))
|
|
45
|
+
for index, value in enumerate(values):
|
|
46
|
+
if value in (None, 0):
|
|
47
|
+
continue
|
|
48
|
+
bucket = seen[min(index, 1)]
|
|
49
|
+
if value in bucket:
|
|
50
|
+
duplicate = True
|
|
51
|
+
bucket.add(value)
|
|
52
|
+
if not duplicate:
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
for atom_map, node in enumerate(sorted(result.nodes, key=repr), start=1):
|
|
56
|
+
old = result.nodes[node].get("atom_map")
|
|
57
|
+
result.nodes[node]["atom_map"] = (
|
|
58
|
+
(atom_map, atom_map)
|
|
59
|
+
if isinstance(old, (tuple, list)) and len(old) == 2
|
|
60
|
+
else atom_map
|
|
61
|
+
)
|
|
62
|
+
result.graph["atom_maps_normalized_after_fusion"] = True
|
|
63
|
+
return result
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def _identity_standardize(rsmi: str) -> str:
|
|
67
|
+
"""Return a whitespace-normalized reaction when no standardizer exists."""
|
|
68
|
+
return rsmi.strip()
|
|
69
|
+
|
|
70
|
+
def _canonical_split(self, rsmi: str) -> Optional[tuple[str, str]]:
|
|
71
|
+
"""Canonicalize and split a reaction into its two endpoints."""
|
|
72
|
+
canon = self.standardize_fn(rsmi)
|
|
73
|
+
try:
|
|
74
|
+
reactants, products = canon.split(">>", 1)
|
|
75
|
+
except (AttributeError, ValueError):
|
|
76
|
+
self.logger.debug("Canonical split failed for reaction: %s", rsmi)
|
|
77
|
+
return None
|
|
78
|
+
return reactants, products
|
|
79
|
+
|
|
80
|
+
def _reset_run_state(self) -> None:
|
|
81
|
+
"""Reset per-run outputs while retaining reusable configuration."""
|
|
82
|
+
self._forward_its = []
|
|
83
|
+
self._backward_its = []
|
|
84
|
+
self._fused_its = []
|
|
85
|
+
self._fused_rsmis = []
|
|
86
|
+
self._fusion_candidates = []
|
|
87
|
+
self._fusion_search_stats = {}
|
|
88
|
+
self._latest_postprocessed_its = None
|
|
89
|
+
self._latest_output_validation = None
|
|
90
|
+
self._diagnostics = {
|
|
91
|
+
"forward": [],
|
|
92
|
+
"backward": [],
|
|
93
|
+
"quick_check": [],
|
|
94
|
+
"fusion": [],
|
|
95
|
+
}
|
|
96
|
+
self._last_stop_mode = "not_run"
|
|
97
|
+
self._last_stop_reason = "not_run"
|
|
98
|
+
self._last_stop_metadata = {}
|
|
99
|
+
self._active_search_policy = self.search_policy
|
|
100
|
+
|
|
101
|
+
def _record_stop(
|
|
102
|
+
self,
|
|
103
|
+
*,
|
|
104
|
+
mode: str,
|
|
105
|
+
reason: str,
|
|
106
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Record the stable termination description for the current run."""
|
|
109
|
+
self._last_stop_mode = mode
|
|
110
|
+
self._last_stop_reason = reason
|
|
111
|
+
self._last_stop_metadata = dict(metadata or {})
|
|
112
|
+
|
|
113
|
+
def _prepare_from_graph(self, template: nx.Graph) -> ITSLike:
|
|
114
|
+
"""Internal helper: prepare a template from a NetworkX graph.
|
|
115
|
+
|
|
116
|
+
:param template: ITS-like NetworkX graph.
|
|
117
|
+
:type template: nx.Graph
|
|
118
|
+
:return: Standardized ITS-like object.
|
|
119
|
+
:rtype: ITSLike
|
|
120
|
+
"""
|
|
121
|
+
# Compatibility modes historically folded every explicit hydrogen into
|
|
122
|
+
# its heavy-atom ``hcount``. The verified path must retain mapped H
|
|
123
|
+
# identities: they are reaction-rule vertices, not display details.
|
|
124
|
+
temp = (
|
|
125
|
+
self.h_to_implicit_fn(template) if self.implicit_temp else template.copy()
|
|
126
|
+
)
|
|
127
|
+
return self.standardize_h_fn(temp)
|
|
128
|
+
|
|
129
|
+
def _prepare_from_str(self, template: str) -> ITSLike:
|
|
130
|
+
"""Internal helper: prepare a template from a reaction SMILES string.
|
|
131
|
+
|
|
132
|
+
:param template: Reaction SMILES.
|
|
133
|
+
:type template: str
|
|
134
|
+
:return: Standardized ITS-like object.
|
|
135
|
+
:rtype: ITSLike
|
|
136
|
+
"""
|
|
137
|
+
# Only an implicit-H template is allowed to discard explicit H atoms.
|
|
138
|
+
# In particular, a mapped transfer such as O:3-H:4 -> O:2-H:4 must
|
|
139
|
+
# retain H:4 as a first-class rule vertex in verified mode.
|
|
140
|
+
cleaned = (
|
|
141
|
+
self.remove_explicit_H_fn(template) if self.implicit_temp else template
|
|
142
|
+
)
|
|
143
|
+
temp = self.rsmi_to_its_fn(cleaned, core=True)
|
|
144
|
+
return self.standardize_h_fn(temp)
|
|
145
|
+
|
|
146
|
+
def prepare_template(
|
|
147
|
+
self,
|
|
148
|
+
template: Union[str, nx.Graph, SynRule, ITSLike],
|
|
149
|
+
) -> Self:
|
|
150
|
+
"""Prepare a reaction template into a standardized ITS representation.
|
|
151
|
+
|
|
152
|
+
:param template: Template as reaction SMILES, graph, normalized
|
|
153
|
+
:class:`SynRule`, or ITS-like value.
|
|
154
|
+
:type template: str | nx.Graph | SynRule | ITSLike
|
|
155
|
+
:return: The current engine instance (for chaining).
|
|
156
|
+
:rtype: RBLEngine
|
|
157
|
+
"""
|
|
158
|
+
self._template_raw = template
|
|
159
|
+
|
|
160
|
+
if isinstance(template, SynRule):
|
|
161
|
+
self._template_its = template
|
|
162
|
+
elif isinstance(template, nx.Graph):
|
|
163
|
+
self._template_its = self._prepare_from_graph(template)
|
|
164
|
+
elif isinstance(template, str):
|
|
165
|
+
self._template_its = self._prepare_from_str(template)
|
|
166
|
+
else:
|
|
167
|
+
self._template_its = self.standardize_h_fn(template)
|
|
168
|
+
|
|
169
|
+
self.logger.debug("Template prepared: %s", type(self._template_its))
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
# ------------------------------------------------------------------
|
|
173
|
+
# Reaction application core helpers
|
|
174
|
+
# ------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
def _safe_its_to_rsmi(
|
|
177
|
+
self,
|
|
178
|
+
its_graph: ITSLike,
|
|
179
|
+
*,
|
|
180
|
+
fmt: str = "tuple",
|
|
181
|
+
explicit_hydrogen: bool = False,
|
|
182
|
+
) -> Optional[str]:
|
|
183
|
+
"""Safely convert ITS to RSMI, returning ``None`` on failure.
|
|
184
|
+
|
|
185
|
+
:param its_graph: ITS-like graph to convert.
|
|
186
|
+
:type its_graph: ITSLike
|
|
187
|
+
:return: Reaction SMILES or ``None`` on failure.
|
|
188
|
+
:rtype: Optional[str]
|
|
189
|
+
"""
|
|
190
|
+
try:
|
|
191
|
+
kwargs: Dict[str, Any] = {"format": fmt}
|
|
192
|
+
if explicit_hydrogen:
|
|
193
|
+
kwargs["explicit_hydrogen"] = True
|
|
194
|
+
return self.its_to_rsmi_fn(its_graph, **kwargs)
|
|
195
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
196
|
+
self.logger.debug("ITS→RSMI conversion failed: %s", exc)
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def _strip_balanced_isolated_wildcards(rsmi: str) -> str:
|
|
201
|
+
"""Remove identical isolated wildcard spectators from both endpoints.
|
|
202
|
+
|
|
203
|
+
Only complete dot-separated fragments of the forms ``*``, ``[*]`` or
|
|
204
|
+
``[*:n]`` are eligible. The multiset intersection is removed, so an
|
|
205
|
+
unmatched wildcard is preserved for later validation instead of being
|
|
206
|
+
silently discarded.
|
|
207
|
+
"""
|
|
208
|
+
if rsmi.count(">>") != 1:
|
|
209
|
+
return rsmi
|
|
210
|
+
|
|
211
|
+
reactants, products = rsmi.split(">>", 1)
|
|
212
|
+
reactant_parts = [part for part in reactants.split(".") if part]
|
|
213
|
+
product_parts = [part for part in products.split(".") if part]
|
|
214
|
+
|
|
215
|
+
def is_isolated_wildcard(fragment: str) -> bool:
|
|
216
|
+
if fragment in {"*", "[*]"}:
|
|
217
|
+
return True
|
|
218
|
+
return (
|
|
219
|
+
fragment.startswith("[*:")
|
|
220
|
+
and fragment.endswith("]")
|
|
221
|
+
and fragment[3:-1].isdigit()
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
common = Counter(
|
|
225
|
+
part for part in reactant_parts if is_isolated_wildcard(part)
|
|
226
|
+
) & Counter(part for part in product_parts if is_isolated_wildcard(part))
|
|
227
|
+
|
|
228
|
+
def remove_common(parts: List[str]) -> List[str]:
|
|
229
|
+
remaining = common.copy()
|
|
230
|
+
kept: List[str] = []
|
|
231
|
+
for part in parts:
|
|
232
|
+
if remaining[part] > 0:
|
|
233
|
+
remaining[part] -= 1
|
|
234
|
+
else:
|
|
235
|
+
kept.append(part)
|
|
236
|
+
return kept
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
".".join(remove_common(reactant_parts))
|
|
240
|
+
+ ">>"
|
|
241
|
+
+ ".".join(remove_common(product_parts))
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def _validate_fusion_output(
|
|
245
|
+
self,
|
|
246
|
+
rsmi: str,
|
|
247
|
+
*,
|
|
248
|
+
allow_wildcards: bool,
|
|
249
|
+
source: str,
|
|
250
|
+
context: Optional[Dict[str, Any]] = None,
|
|
251
|
+
) -> FusionValidation:
|
|
252
|
+
"""Apply and record the common endpoint contract for an RBL result."""
|
|
253
|
+
if self._last_reaction is None:
|
|
254
|
+
validation = validate_fusion_rsmi(
|
|
255
|
+
rsmi,
|
|
256
|
+
allow_wildcards=allow_wildcards,
|
|
257
|
+
)
|
|
258
|
+
else:
|
|
259
|
+
# Resolve through the historical facade so monkeypatching and
|
|
260
|
+
# instrumentation of ``rbl_engine.validate_rbl_candidate`` keep
|
|
261
|
+
# working after this method moved into a mixin.
|
|
262
|
+
from synkit.Synthesis.RBL import engine as rbl_engine_module
|
|
263
|
+
|
|
264
|
+
if (
|
|
265
|
+
self._active_search_policy.acceptance_task
|
|
266
|
+
is AcceptanceTask.STRICT_RECONSTRUCTION
|
|
267
|
+
):
|
|
268
|
+
validation = rbl_engine_module.validate_strict_rbl_candidate(
|
|
269
|
+
self._last_reaction,
|
|
270
|
+
rsmi,
|
|
271
|
+
allow_wildcards=allow_wildcards,
|
|
272
|
+
boundary=self.conservation_boundary,
|
|
273
|
+
environment_delta=self.environment_delta,
|
|
274
|
+
)
|
|
275
|
+
else:
|
|
276
|
+
validation = rbl_engine_module.validate_rbl_candidate(
|
|
277
|
+
self._last_reaction,
|
|
278
|
+
rsmi,
|
|
279
|
+
allow_wildcards=allow_wildcards,
|
|
280
|
+
preserve_sides=self.preserve_original_sides,
|
|
281
|
+
)
|
|
282
|
+
payload = validation.to_dict()
|
|
283
|
+
payload["source"] = source
|
|
284
|
+
payload.update(context or {})
|
|
285
|
+
self._diagnostics["fusion"].append(payload)
|
|
286
|
+
self._latest_output_validation = validation
|
|
287
|
+
return validation
|
|
288
|
+
|
|
289
|
+
def _record_fusion_failure(
|
|
290
|
+
self,
|
|
291
|
+
code: FusionIssueCode,
|
|
292
|
+
message: str,
|
|
293
|
+
*,
|
|
294
|
+
source: str,
|
|
295
|
+
context: Optional[Dict[str, Any]] = None,
|
|
296
|
+
) -> None:
|
|
297
|
+
"""Record a contained construction or serialization failure."""
|
|
298
|
+
issue = FusionIssue(
|
|
299
|
+
code=code,
|
|
300
|
+
stage="fusion",
|
|
301
|
+
message=message,
|
|
302
|
+
context=context or {},
|
|
303
|
+
)
|
|
304
|
+
payload = FusionValidation(valid=False, issues=(issue,)).to_dict()
|
|
305
|
+
payload["source"] = source
|
|
306
|
+
payload.update(context or {})
|
|
307
|
+
self._diagnostics["fusion"].append(payload)
|
|
308
|
+
|
|
309
|
+
def _record_reaction_failure(
|
|
310
|
+
self,
|
|
311
|
+
code: FusionIssueCode,
|
|
312
|
+
message: str,
|
|
313
|
+
*,
|
|
314
|
+
stage: str,
|
|
315
|
+
source: str,
|
|
316
|
+
context: Optional[Dict[str, Any]] = None,
|
|
317
|
+
) -> None:
|
|
318
|
+
"""Record a typed forward/backward application-stage failure."""
|
|
319
|
+
issue = FusionIssue(
|
|
320
|
+
code=code,
|
|
321
|
+
stage=stage,
|
|
322
|
+
message=message,
|
|
323
|
+
context=context or {},
|
|
324
|
+
)
|
|
325
|
+
payload = FusionValidation(valid=False, issues=(issue,)).to_dict()
|
|
326
|
+
payload["stage"] = stage
|
|
327
|
+
payload["source"] = source
|
|
328
|
+
self._diagnostics[stage].append(payload)
|
|
329
|
+
|
|
330
|
+
def _safe_rsmi_to_its(self, rsmi: str) -> Optional[ITSLike]:
|
|
331
|
+
"""Safely convert RSMI to ITS, returning ``None`` on failure.
|
|
332
|
+
|
|
333
|
+
:param rsmi: Reaction SMILES to convert.
|
|
334
|
+
:type rsmi: str
|
|
335
|
+
:return: ITS-like object or ``None`` on failure.
|
|
336
|
+
:rtype: Optional[ITSLike]
|
|
337
|
+
"""
|
|
338
|
+
try:
|
|
339
|
+
return self.rsmi_to_its_fn(rsmi, format="tuple")
|
|
340
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
341
|
+
self.logger.debug("RSMI→ITS conversion failed: %s", exc)
|
|
342
|
+
return None
|
|
343
|
+
|
|
344
|
+
def _decorate_radical(self, rsmi: str, invert: bool) -> Optional[str]:
|
|
345
|
+
"""Apply radical wildcard decoration (and optional inversion).
|
|
346
|
+
|
|
347
|
+
:param rsmi: Reaction SMILES to decorate.
|
|
348
|
+
:type rsmi: str
|
|
349
|
+
:param invert: Whether to reverse the reaction (products↔reactants)
|
|
350
|
+
after decoration.
|
|
351
|
+
:type invert: bool
|
|
352
|
+
:return: Decorated (and possibly inverted) reaction SMILES, or
|
|
353
|
+
``None`` on failure.
|
|
354
|
+
:rtype: Optional[str]
|
|
355
|
+
"""
|
|
356
|
+
rw_adder = self.wildcard_adder_cls()
|
|
357
|
+
try:
|
|
358
|
+
decorated = rw_adder.transform(rsmi)
|
|
359
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
360
|
+
self.logger.debug("Radical wildcard decoration failed: %s", exc)
|
|
361
|
+
return None
|
|
362
|
+
|
|
363
|
+
if invert:
|
|
364
|
+
return reverse_reaction(decorated)
|
|
365
|
+
return decorated
|
|
366
|
+
|
|
367
|
+
def _run_reaction(
|
|
368
|
+
self,
|
|
369
|
+
substrate: Union[str, ITSLike],
|
|
370
|
+
pattern: ITSLike,
|
|
371
|
+
invert: bool,
|
|
372
|
+
) -> List[ITSLike]:
|
|
373
|
+
"""Internal helper: apply template to substrate using :class:`SynReactor`.
|
|
374
|
+
|
|
375
|
+
For each resulting ITS, the method performs:
|
|
376
|
+
|
|
377
|
+
1. ITS → RSMI
|
|
378
|
+
2. Radical wildcard decoration
|
|
379
|
+
3. Optional inversion
|
|
380
|
+
4. RSMI → ITS
|
|
381
|
+
|
|
382
|
+
Any failing conversions are skipped.
|
|
383
|
+
|
|
384
|
+
:param substrate: Substrate reaction string or ITS-like object.
|
|
385
|
+
:type substrate: str | ITSLike
|
|
386
|
+
:param pattern: Template ITS-like object.
|
|
387
|
+
:type pattern: ITSLike
|
|
388
|
+
:param invert: Whether to run the reactor in inverted mode.
|
|
389
|
+
:type invert: bool
|
|
390
|
+
:return: List of ITS-like objects after decoration.
|
|
391
|
+
:rtype: list[ITSLike]
|
|
392
|
+
"""
|
|
393
|
+
self.logger.debug(
|
|
394
|
+
"Running reaction: invert=%s, substrate type=%s",
|
|
395
|
+
invert,
|
|
396
|
+
type(substrate),
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
reactor = self.reactor_cls(
|
|
400
|
+
substrate,
|
|
401
|
+
pattern,
|
|
402
|
+
partial=True,
|
|
403
|
+
implicit_temp=self.implicit_temp,
|
|
404
|
+
explicit_h=self.explicit_h,
|
|
405
|
+
automorphism=False,
|
|
406
|
+
invert=invert,
|
|
407
|
+
embed_threshold=self.embed_threshold,
|
|
408
|
+
electron_diagnostics=self.electron_diagnostics,
|
|
409
|
+
dedup_its=not self.verified_mode,
|
|
410
|
+
)
|
|
411
|
+
stage = "backward" if invert else "forward"
|
|
412
|
+
self._diagnostics[stage].extend(getattr(reactor, "diagnostics", []) or [])
|
|
413
|
+
|
|
414
|
+
out: List[ITSLike] = []
|
|
415
|
+
its_list: Sequence[ITSLike] = getattr(reactor, "its", []) or []
|
|
416
|
+
|
|
417
|
+
for its_graph in its_list:
|
|
418
|
+
rsmi = self._safe_its_to_rsmi(
|
|
419
|
+
its_graph,
|
|
420
|
+
fmt="typesGH",
|
|
421
|
+
explicit_hydrogen=self.explicit_h,
|
|
422
|
+
)
|
|
423
|
+
if rsmi is None:
|
|
424
|
+
self._record_reaction_failure(
|
|
425
|
+
FusionIssueCode.SERIALIZATION_FAILED,
|
|
426
|
+
"Could not serialize a rule-application graph.",
|
|
427
|
+
stage=stage,
|
|
428
|
+
source=f"{stage}_application",
|
|
429
|
+
context={"invert": invert},
|
|
430
|
+
)
|
|
431
|
+
continue
|
|
432
|
+
|
|
433
|
+
rsmi_decorated = self._decorate_radical(rsmi, invert)
|
|
434
|
+
if rsmi_decorated is None:
|
|
435
|
+
self._record_reaction_failure(
|
|
436
|
+
FusionIssueCode.POSTPROCESS_FAILED,
|
|
437
|
+
"Could not decorate a rule-application graph with typed ports.",
|
|
438
|
+
stage=stage,
|
|
439
|
+
source=f"{stage}_application",
|
|
440
|
+
context={"invert": invert},
|
|
441
|
+
)
|
|
442
|
+
continue
|
|
443
|
+
|
|
444
|
+
its_back = self._safe_rsmi_to_its(rsmi_decorated)
|
|
445
|
+
if its_back is not None:
|
|
446
|
+
application_provenance = its_graph.graph.get("application_provenance")
|
|
447
|
+
if application_provenance is not None:
|
|
448
|
+
its_back.graph["application_provenance"] = copy.deepcopy(
|
|
449
|
+
application_provenance
|
|
450
|
+
)
|
|
451
|
+
its_back.graph["application_direction"] = stage
|
|
452
|
+
its_back = self._annotate_wildcard_roles(
|
|
453
|
+
its_back,
|
|
454
|
+
WildcardRole.RADICAL_COMPLETION,
|
|
455
|
+
)
|
|
456
|
+
out.append(its_back)
|
|
457
|
+
else:
|
|
458
|
+
self._record_reaction_failure(
|
|
459
|
+
FusionIssueCode.POSTPROCESS_FAILED,
|
|
460
|
+
"Could not restore a decorated rule-application graph.",
|
|
461
|
+
stage=stage,
|
|
462
|
+
source=f"{stage}_application",
|
|
463
|
+
context={"invert": invert},
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
self.logger.debug("Reaction produced %d ITS graphs", len(out))
|
|
467
|
+
return out
|
|
468
|
+
|
|
469
|
+
def react(
|
|
470
|
+
self,
|
|
471
|
+
substrate: Union[str, ITSLike],
|
|
472
|
+
pattern: Optional[ITSLike] = None,
|
|
473
|
+
invert: bool = False,
|
|
474
|
+
) -> Self:
|
|
475
|
+
"""Public wrapper around :meth:`_run_reaction` that updates engine state.
|
|
476
|
+
|
|
477
|
+
If ``pattern`` is ``None``, the last prepared template
|
|
478
|
+
(:attr:`template_its`) is used.
|
|
479
|
+
|
|
480
|
+
Results are stored in :attr:`forward_its` (for ``invert=False``)
|
|
481
|
+
or :attr:`backward_its` (for ``invert=True``).
|
|
482
|
+
|
|
483
|
+
:param substrate: Substrate reaction string or ITS-like object.
|
|
484
|
+
:type substrate: str | ITSLike
|
|
485
|
+
:param pattern: Optional template ITS; if ``None``, use
|
|
486
|
+
:attr:`template_its`.
|
|
487
|
+
:type pattern: ITSLike or None
|
|
488
|
+
:param invert: If ``True``, store results as backward ITS.
|
|
489
|
+
:type invert: bool
|
|
490
|
+
:return: The current engine instance.
|
|
491
|
+
:rtype: RBLEngine
|
|
492
|
+
:raises ValueError: If no template pattern was provided or prepared.
|
|
493
|
+
"""
|
|
494
|
+
if pattern is None:
|
|
495
|
+
pattern = self._template_its
|
|
496
|
+
if pattern is None:
|
|
497
|
+
raise ValueError("No template pattern provided or prepared.")
|
|
498
|
+
|
|
499
|
+
its_list = self._run_reaction(substrate, pattern, invert=invert)
|
|
500
|
+
|
|
501
|
+
if invert:
|
|
502
|
+
self._backward_its = its_list
|
|
503
|
+
else:
|
|
504
|
+
self._forward_its = its_list
|
|
505
|
+
|
|
506
|
+
return self
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Read-only run-state views for the RBL engine."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from synkit.Graph.Fusion import (
|
|
8
|
+
FUSION_PROOF_SCHEMA,
|
|
9
|
+
FusionCandidate,
|
|
10
|
+
graph_identity_digest,
|
|
11
|
+
)
|
|
12
|
+
from synkit.Synthesis.RBL.policy import (
|
|
13
|
+
AcceptanceTask,
|
|
14
|
+
SearchOutcomeStatus,
|
|
15
|
+
)
|
|
16
|
+
from synkit.Synthesis.RBL.proof import RBL_PROOF_SCHEMA
|
|
17
|
+
|
|
18
|
+
ITSLike = Any
|
|
19
|
+
RBL_RESULT_SCHEMA = "synkit.rbl-result/2"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RBLStateMixin:
|
|
23
|
+
"""Expose defensive copies of RBL outputs and diagnostics."""
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def template_its(self) -> Optional[ITSLike]:
|
|
27
|
+
"""Return the standardized representation of the prepared template."""
|
|
28
|
+
return self._template_its
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def forward_its(self) -> List[ITSLike]:
|
|
32
|
+
"""Return ITS graphs from the last forward application."""
|
|
33
|
+
return list(self._forward_its)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def backward_its(self) -> List[ITSLike]:
|
|
37
|
+
"""Return ITS graphs from the last backward application."""
|
|
38
|
+
return list(self._backward_its)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def fused_its(self) -> List[ITSLike]:
|
|
42
|
+
"""Return accepted fused ITS graphs."""
|
|
43
|
+
return list(self._fused_its)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def fused_rsmis(self) -> List[str]:
|
|
47
|
+
"""Return accepted fused reaction SMILES."""
|
|
48
|
+
return list(self._fused_rsmis)
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def fusion_candidates(self) -> List[FusionCandidate]:
|
|
52
|
+
"""Return proof-bearing candidates from the fusion stage."""
|
|
53
|
+
return list(self._fusion_candidates)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def rbl_proofs(self) -> List[Any]:
|
|
57
|
+
"""Return independently replayable RBL certificates."""
|
|
58
|
+
return list(self._rbl_proofs)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def last_reaction(self) -> Optional[str]:
|
|
62
|
+
"""Return the last processed reaction, if any."""
|
|
63
|
+
return self._last_reaction
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def result(self) -> Dict[str, Any]:
|
|
67
|
+
"""Return the stable result and termination record for the last run."""
|
|
68
|
+
search = dict(self._fusion_search_stats)
|
|
69
|
+
complete = bool(search.get("complete", False))
|
|
70
|
+
incomplete_reasons = list(search.get("incomplete_reasons", ()))
|
|
71
|
+
if self._fused_rsmis:
|
|
72
|
+
status = SearchOutcomeStatus.FOUND
|
|
73
|
+
elif complete:
|
|
74
|
+
status = SearchOutcomeStatus.PROVED_NONE
|
|
75
|
+
elif search.get("operational_failures", 0) or any(
|
|
76
|
+
issue.get("code")
|
|
77
|
+
in {
|
|
78
|
+
"FUSION_OPERATION_FAILED",
|
|
79
|
+
"FUSION_SERIALIZATION_FAILED",
|
|
80
|
+
}
|
|
81
|
+
for reports in self._diagnostics.values()
|
|
82
|
+
for report in reports
|
|
83
|
+
for issue in report.get("issues", ())
|
|
84
|
+
) and not search:
|
|
85
|
+
status = SearchOutcomeStatus.ERROR
|
|
86
|
+
else:
|
|
87
|
+
status = SearchOutcomeStatus.INCOMPLETE
|
|
88
|
+
|
|
89
|
+
strict = (
|
|
90
|
+
self._active_search_policy.acceptance_task
|
|
91
|
+
is AcceptanceTask.STRICT_RECONSTRUCTION
|
|
92
|
+
)
|
|
93
|
+
acceptance_policy = (
|
|
94
|
+
{
|
|
95
|
+
"task": "strict_reconstruction",
|
|
96
|
+
"relation": "exact_component_multiset_inclusion",
|
|
97
|
+
"preserve_original_sides": ["reactants", "products"],
|
|
98
|
+
"conservation_boundary": self.conservation_boundary,
|
|
99
|
+
"environment_delta": dict(self.environment_delta),
|
|
100
|
+
"require_mapped_material": True,
|
|
101
|
+
"use_chirality": True,
|
|
102
|
+
}
|
|
103
|
+
if strict
|
|
104
|
+
else {
|
|
105
|
+
"task": "compatibility",
|
|
106
|
+
"preserve_original_sides": list(self.preserve_original_sides),
|
|
107
|
+
"relation": "component_injective_subgraph",
|
|
108
|
+
"use_chirality": True,
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
proof_digests_by_outcome: dict[str, list[str]] = {}
|
|
112
|
+
for proof in self._rbl_proofs:
|
|
113
|
+
payload = proof.to_dict()
|
|
114
|
+
proof_digests_by_outcome.setdefault(proof.final_digest, []).append(
|
|
115
|
+
payload["document_digest"]
|
|
116
|
+
)
|
|
117
|
+
outcomes = []
|
|
118
|
+
for index, rsmi in enumerate(self._fused_rsmis):
|
|
119
|
+
signature = (
|
|
120
|
+
graph_identity_digest(self._fused_its[index])
|
|
121
|
+
if index < len(self._fused_its)
|
|
122
|
+
else None
|
|
123
|
+
)
|
|
124
|
+
proof_digests = (
|
|
125
|
+
sorted(proof_digests_by_outcome.get(signature, ()))
|
|
126
|
+
if signature is not None
|
|
127
|
+
else []
|
|
128
|
+
)
|
|
129
|
+
outcomes.append(
|
|
130
|
+
{
|
|
131
|
+
"rsmi": rsmi,
|
|
132
|
+
"canonical_signature": signature,
|
|
133
|
+
"proof_digests": proof_digests,
|
|
134
|
+
"proof_count": len(proof_digests),
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
return {
|
|
138
|
+
"schema": RBL_RESULT_SCHEMA,
|
|
139
|
+
"fused_rsmis": list(self._fused_rsmis),
|
|
140
|
+
"mode": self._last_stop_mode,
|
|
141
|
+
"reason": self._last_stop_reason,
|
|
142
|
+
"metadata": dict(self._last_stop_metadata),
|
|
143
|
+
"n_forward_its": len(self._forward_its),
|
|
144
|
+
"n_backward_its": len(self._backward_its),
|
|
145
|
+
"n_fused_its": len(self._fused_its),
|
|
146
|
+
"fusion_proof_schema": FUSION_PROOF_SCHEMA,
|
|
147
|
+
"rbl_proof_schema": RBL_PROOF_SCHEMA,
|
|
148
|
+
"fusion_candidates": [
|
|
149
|
+
candidate.to_dict() for candidate in self._fusion_candidates
|
|
150
|
+
],
|
|
151
|
+
"rbl_proofs": [proof.to_dict() for proof in self._rbl_proofs],
|
|
152
|
+
"outcomes": outcomes,
|
|
153
|
+
"fusion_search": search,
|
|
154
|
+
"search_status": status.value,
|
|
155
|
+
"complete": complete,
|
|
156
|
+
"reason_incomplete": incomplete_reasons,
|
|
157
|
+
"verified_fusion_mode": self.verified_mode,
|
|
158
|
+
"search_policy": self._active_search_policy.to_dict(),
|
|
159
|
+
"acceptance_policy": acceptance_policy,
|
|
160
|
+
"diagnostics": self.diagnostics,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def diagnostics(self) -> Dict[str, List[Dict[str, Any]]]:
|
|
165
|
+
"""Return diagnostics grouped by reactor stage."""
|
|
166
|
+
return {stage: list(reports) for stage, reports in self._diagnostics.items()}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
__all__ = ["RBL_RESULT_SCHEMA", "RBLStateMixin"]
|