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
|
File without changes
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""Route search over rounds of reaction SMILES for multi-step retrosynthesis.
|
|
2
|
+
|
|
3
|
+
This is the *synthesis-planning* path finder: it consumes the round-structured
|
|
4
|
+
reaction SMILES produced by an MSR expansion and searches molecule-to-molecule
|
|
5
|
+
routes under a carbon-count constraint. It has no notion of stoichiometry,
|
|
6
|
+
markings or reaction networks.
|
|
7
|
+
|
|
8
|
+
For pathway search over a reaction *network* —
|
|
9
|
+
:class:`~synkit.CRN.Structure.syncrn.SynCRN` incidence, reaction flows, and
|
|
10
|
+
Petri-net realizability of a candidate route — use
|
|
11
|
+
:class:`synkit.CRN.Pathway.pathfinder.PathwayFinder` instead. The two solve
|
|
12
|
+
different problems and are not alternative implementations of one algorithm.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import heapq
|
|
16
|
+
from collections import deque
|
|
17
|
+
from typing import List, Dict, Optional
|
|
18
|
+
from synkit.Chem.utils import count_carbons
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PathFinder:
|
|
22
|
+
"""Search synthesis routes through rounds of reaction SMILES.
|
|
23
|
+
|
|
24
|
+
See the module docstring for how this relates to
|
|
25
|
+
:class:`synkit.CRN.Pathway.pathfinder.PathwayFinder`.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
reaction_rounds: List[Dict[str, List[str]]],
|
|
31
|
+
):
|
|
32
|
+
"""Initialize with a list of dictionaries, each representing a reaction
|
|
33
|
+
round, plus an optional random state for reproducible Monte Carlo
|
|
34
|
+
search.
|
|
35
|
+
|
|
36
|
+
:param reaction_rounds: A list where each dictionary
|
|
37
|
+
contains the reaction SMILES strings for a given round
|
|
38
|
+
(e.g. {"Round 1": [...] }).
|
|
39
|
+
:type reaction_rounds: List[Dict[str, List[str]]]
|
|
40
|
+
"""
|
|
41
|
+
self.reaction_rounds = reaction_rounds
|
|
42
|
+
|
|
43
|
+
# Build adjacency structure:
|
|
44
|
+
# self._adjacency[round_idx] => { reactant_smiles: [(reaction_smiles, [products])] }
|
|
45
|
+
self._adjacency = []
|
|
46
|
+
for round_idx, round_dict in enumerate(self.reaction_rounds):
|
|
47
|
+
round_key = f"Round {round_idx + 1}"
|
|
48
|
+
reactions = round_dict.get(round_key, [])
|
|
49
|
+
adjacency_map = {}
|
|
50
|
+
for rxn in reactions:
|
|
51
|
+
reactants, products = rxn.split(">>")
|
|
52
|
+
reactant_list = reactants.split(".")
|
|
53
|
+
product_list = products.split(".")
|
|
54
|
+
for rct in reactant_list:
|
|
55
|
+
adjacency_map.setdefault(rct, []).append((rxn, product_list))
|
|
56
|
+
self._adjacency.append(adjacency_map)
|
|
57
|
+
|
|
58
|
+
def _valid_intermediate(
|
|
59
|
+
self, smiles: str, input_smiles: str, target_smiles: str
|
|
60
|
+
) -> bool:
|
|
61
|
+
"""
|
|
62
|
+
Checks whether the given molecule satisfies the carbon_distance constraint:
|
|
63
|
+
n_C(input_smiles) <= n_C(smiles) <= n_C(target_smiles)
|
|
64
|
+
"""
|
|
65
|
+
return (
|
|
66
|
+
count_carbons(input_smiles)
|
|
67
|
+
<= count_carbons(smiles)
|
|
68
|
+
<= count_carbons(target_smiles)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def search_paths(
|
|
72
|
+
self,
|
|
73
|
+
input_smiles: str,
|
|
74
|
+
target_smiles: str,
|
|
75
|
+
method: str = "bfs",
|
|
76
|
+
max_solutions: Optional[int] = None,
|
|
77
|
+
cheapest: bool = True,
|
|
78
|
+
) -> List[List[str]]:
|
|
79
|
+
"""Search for reaction pathways from the input molecule to the target
|
|
80
|
+
molecule using a specified method, optionally limiting the number of
|
|
81
|
+
solutions.
|
|
82
|
+
|
|
83
|
+
Additionally, `cheapest` can be set to True or False:
|
|
84
|
+
- If cheapest=True, BFS uses a visited set and A* prunes costlier routes (typical approach).
|
|
85
|
+
- If cheapest=False, BFS does *not* track visited states (returns more solutions),
|
|
86
|
+
and A* does *not* prune costlier routes (also returns more solutions).
|
|
87
|
+
(May lead to duplicates or many solutions if cycles exist.)
|
|
88
|
+
|
|
89
|
+
:param input_smiles: SMILES of the starting molecule.
|
|
90
|
+
:type input_smiles: str
|
|
91
|
+
:param target_smiles: SMILES of the target molecule.
|
|
92
|
+
:type target_smiles: str
|
|
93
|
+
:param method: 'bfs', 'astar', or 'mc'.
|
|
94
|
+
:type method: str, optional
|
|
95
|
+
:param max_solutions: If set, stop after finding this many solutions.
|
|
96
|
+
:type max_solutions: int, optional
|
|
97
|
+
:param cheapest: Controls pruning.
|
|
98
|
+
Default True => standard BFS/A*; False => "unrestricted" BFS/A*.
|
|
99
|
+
:type cheapest: bool, optional
|
|
100
|
+
|
|
101
|
+
:return: Each solution path is a list of reaction SMILES from start to target.
|
|
102
|
+
:rtype: List[List[str]]
|
|
103
|
+
"""
|
|
104
|
+
if method == "bfs":
|
|
105
|
+
return self._bfs(input_smiles, target_smiles, max_solutions, cheapest)
|
|
106
|
+
elif method == "astar":
|
|
107
|
+
return self._astar(input_smiles, target_smiles, max_solutions, cheapest)
|
|
108
|
+
else:
|
|
109
|
+
raise ValueError("Invalid method. Choose 'bfs', 'astar', or 'mc'.")
|
|
110
|
+
|
|
111
|
+
def _bfs(
|
|
112
|
+
self,
|
|
113
|
+
input_smiles: str,
|
|
114
|
+
target_smiles: str,
|
|
115
|
+
max_solutions: Optional[int],
|
|
116
|
+
cheapest: bool,
|
|
117
|
+
) -> List[List[str]]:
|
|
118
|
+
"""Perform a BFS search. If cheapest=True, use a visited set to avoid
|
|
119
|
+
re-processing the same (molecule, round_index). If cheapest=False, skip
|
|
120
|
+
that pruning and collect *all* possible solutions (potentially large if
|
|
121
|
+
cycles exist).
|
|
122
|
+
|
|
123
|
+
Returns a list of successful reaction pathways, up to
|
|
124
|
+
max_solutions if specified.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
queue = deque([(input_smiles, [], 0)])
|
|
128
|
+
pathways = []
|
|
129
|
+
visited = set() if cheapest else None # Only track visited if cheapest=True
|
|
130
|
+
|
|
131
|
+
while queue:
|
|
132
|
+
current_smiles, current_path, round_index = queue.popleft()
|
|
133
|
+
if round_index >= len(self._adjacency):
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
# For BFS with cheapest=True, skip repeated states
|
|
137
|
+
if cheapest:
|
|
138
|
+
if (current_smiles, round_index) in visited:
|
|
139
|
+
continue
|
|
140
|
+
visited.add((current_smiles, round_index))
|
|
141
|
+
|
|
142
|
+
adjacency_map = self._adjacency[round_index]
|
|
143
|
+
if current_smiles not in adjacency_map:
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
for rxn_string, product_list in adjacency_map[current_smiles]:
|
|
147
|
+
updated_path = current_path + [rxn_string]
|
|
148
|
+
# If any product is the target, record a solution
|
|
149
|
+
if target_smiles in product_list:
|
|
150
|
+
pathways.append(updated_path)
|
|
151
|
+
if max_solutions is not None and len(pathways) >= max_solutions:
|
|
152
|
+
return pathways
|
|
153
|
+
# Otherwise queue each valid product
|
|
154
|
+
for product in product_list:
|
|
155
|
+
if self._valid_intermediate(product, input_smiles, target_smiles):
|
|
156
|
+
queue.append((product, updated_path, round_index + 1))
|
|
157
|
+
|
|
158
|
+
return pathways
|
|
159
|
+
|
|
160
|
+
def _heuristic(self, smiles: str, target_smiles: str) -> int:
|
|
161
|
+
"""Heuristic function for A* search.
|
|
162
|
+
|
|
163
|
+
Returns difference in SMILES lengths as a stand-in for
|
|
164
|
+
"distance."
|
|
165
|
+
"""
|
|
166
|
+
return abs(len(smiles) - len(target_smiles))
|
|
167
|
+
|
|
168
|
+
def _astar(
|
|
169
|
+
self,
|
|
170
|
+
input_smiles: str,
|
|
171
|
+
target_smiles: str,
|
|
172
|
+
max_solutions: Optional[int],
|
|
173
|
+
cheapest: bool,
|
|
174
|
+
) -> List[List[str]]:
|
|
175
|
+
"""A* search. If cheapest=True, we track the best cost visited for each
|
|
176
|
+
state and prune costlier paths. If cheapest=False, we do not prune, so
|
|
177
|
+
we collect all solutions (but it may be large).
|
|
178
|
+
|
|
179
|
+
Returns a list of successful reaction pathways, up to
|
|
180
|
+
max_solutions if specified.
|
|
181
|
+
"""
|
|
182
|
+
start_cost = self._heuristic(input_smiles, target_smiles)
|
|
183
|
+
# Heap stores (cost, current_smiles, current_path, round_index)
|
|
184
|
+
heap = [(start_cost, input_smiles, [], 0)]
|
|
185
|
+
pathways = []
|
|
186
|
+
visited_cost = {} if cheapest else None
|
|
187
|
+
|
|
188
|
+
while heap:
|
|
189
|
+
cost, current_smiles, current_path, round_index = heapq.heappop(heap)
|
|
190
|
+
|
|
191
|
+
if cheapest and visited_cost is not None:
|
|
192
|
+
# If we've seen this state with a cheaper or equal cost, skip
|
|
193
|
+
if (current_smiles, round_index) in visited_cost:
|
|
194
|
+
if visited_cost[(current_smiles, round_index)] <= cost:
|
|
195
|
+
continue
|
|
196
|
+
visited_cost[(current_smiles, round_index)] = cost
|
|
197
|
+
|
|
198
|
+
if round_index >= len(self._adjacency):
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
adjacency_map = self._adjacency[round_index]
|
|
202
|
+
if current_smiles not in adjacency_map:
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
for rxn_string, product_list in adjacency_map[current_smiles]:
|
|
206
|
+
updated_path = current_path + [rxn_string]
|
|
207
|
+
|
|
208
|
+
# If any product is the target, record a solution
|
|
209
|
+
if target_smiles in product_list:
|
|
210
|
+
pathways.append(updated_path)
|
|
211
|
+
if max_solutions is not None and len(pathways) >= max_solutions:
|
|
212
|
+
return pathways
|
|
213
|
+
else:
|
|
214
|
+
# Otherwise expand each product
|
|
215
|
+
next_round = round_index + 1
|
|
216
|
+
for product in product_list:
|
|
217
|
+
if self._valid_intermediate(
|
|
218
|
+
product, input_smiles, target_smiles
|
|
219
|
+
):
|
|
220
|
+
new_cost = len(updated_path) + self._heuristic(
|
|
221
|
+
product, target_smiles
|
|
222
|
+
)
|
|
223
|
+
if cheapest and visited_cost is not None:
|
|
224
|
+
old_cost = visited_cost.get(
|
|
225
|
+
(product, next_round), float("inf")
|
|
226
|
+
)
|
|
227
|
+
# Only push if cheaper route
|
|
228
|
+
if new_cost < old_cost:
|
|
229
|
+
heapq.heappush(
|
|
230
|
+
heap,
|
|
231
|
+
(new_cost, product, updated_path, next_round),
|
|
232
|
+
)
|
|
233
|
+
else:
|
|
234
|
+
# cheapest=False => always push
|
|
235
|
+
heapq.heappush(
|
|
236
|
+
heap, (new_cost, product, updated_path, next_round)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
return pathways
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import List, Dict
|
|
2
|
+
from ._ranking import (
|
|
3
|
+
_novelty_rate,
|
|
4
|
+
_coverage,
|
|
5
|
+
_recognition_rate,
|
|
6
|
+
_top_k_accuracy,
|
|
7
|
+
_calculate_f_beta_score,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _compute_metrics(
|
|
12
|
+
reactions_data: List[Dict[str, any]],
|
|
13
|
+
key_ground_truth: str,
|
|
14
|
+
key_prediction: str,
|
|
15
|
+
k: int = 5,
|
|
16
|
+
beta: float = 1,
|
|
17
|
+
) -> Dict[str, float]:
|
|
18
|
+
"""Computes the metrics for a list of reactions data.
|
|
19
|
+
|
|
20
|
+
:param reactions_data: List of dictionaries containing RSMI strings.
|
|
21
|
+
:type reactions_data: List[Dict[str, any]]
|
|
22
|
+
:param key_ground_truth: Key in the dictionary for the ground truth RSMI.
|
|
23
|
+
:type key_ground_truth: str
|
|
24
|
+
:param key_prediction: Key in the dictionary for the predicted RSMIs
|
|
25
|
+
(list of predictions).
|
|
26
|
+
:type key_prediction: str
|
|
27
|
+
:param k: The number of top predictions to consider. Defaults to 5.
|
|
28
|
+
:type k: int, optional
|
|
29
|
+
:param beta: Beta parameter for the F-beta score. Defaults to 1.
|
|
30
|
+
:type beta: float, optional
|
|
31
|
+
|
|
32
|
+
:return: A dictionary with the metrics.
|
|
33
|
+
:rtype: Dict[str, float]
|
|
34
|
+
"""
|
|
35
|
+
return {
|
|
36
|
+
"Novelty": _novelty_rate(reactions_data, key_ground_truth, key_prediction)
|
|
37
|
+
/ 100,
|
|
38
|
+
"Coverage": _coverage(reactions_data, key_ground_truth, key_prediction) / 100,
|
|
39
|
+
"Recognition": _recognition_rate(
|
|
40
|
+
reactions_data, key_ground_truth, key_prediction
|
|
41
|
+
)
|
|
42
|
+
/ 100,
|
|
43
|
+
f"Top_{k}_Accuracy": _top_k_accuracy(
|
|
44
|
+
reactions_data, key_ground_truth, key_prediction, k
|
|
45
|
+
)
|
|
46
|
+
/ 100,
|
|
47
|
+
f"F{beta}_score": _calculate_f_beta_score(
|
|
48
|
+
_recognition_rate(reactions_data, key_ground_truth, key_prediction),
|
|
49
|
+
_coverage(reactions_data, key_ground_truth, key_prediction),
|
|
50
|
+
beta,
|
|
51
|
+
),
|
|
52
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
import seaborn as sns
|
|
4
|
+
import matplotlib
|
|
5
|
+
|
|
6
|
+
# Enable LaTeX rendering in Matplotlib
|
|
7
|
+
matplotlib.rcParams["text.usetex"] = True
|
|
8
|
+
matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{amsmath}"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def plot_recognition_coverage_curve(
|
|
12
|
+
data,
|
|
13
|
+
coverage_col="Coverage",
|
|
14
|
+
recognition_col="Recognition",
|
|
15
|
+
f2_score_col="F2_score",
|
|
16
|
+
figsize=(8, 6),
|
|
17
|
+
show_f2=True,
|
|
18
|
+
show_legend=True,
|
|
19
|
+
):
|
|
20
|
+
"""Plots a Recognition-Coverage curve using provided data, including
|
|
21
|
+
optional F2 scores annotated. Styled with Seaborn for enhanced visual
|
|
22
|
+
appearance.
|
|
23
|
+
|
|
24
|
+
:param data: Nested dictionary containing the data for each radii,
|
|
25
|
+
formatted as shown in example.
|
|
26
|
+
:type data: dict
|
|
27
|
+
:param coverage_col: Key name for the coverage data in the dictionary.
|
|
28
|
+
:type coverage_col: str
|
|
29
|
+
:param recognition_col: Key name for the recognition data in the dictionary.
|
|
30
|
+
:type recognition_col: str
|
|
31
|
+
:param f2_score_col: Key name for the F2 score data in the dictionary.
|
|
32
|
+
:type f2_score_col: str
|
|
33
|
+
:param figsize: Figure size for the plot, default is (8, 6).
|
|
34
|
+
:type figsize: tuple
|
|
35
|
+
:param show_f2: Whether to show F2 scores on the curve, default is True.
|
|
36
|
+
|
|
37
|
+
Example Data format:
|
|
38
|
+
{'radii_0': {'Novelty': 96.44, 'Coverage': 93.98, 'Recognition': 3.55, ...}}
|
|
39
|
+
:type show_f2: bool
|
|
40
|
+
"""
|
|
41
|
+
df = pd.DataFrame(data).T
|
|
42
|
+
|
|
43
|
+
sns.set_theme(style="whitegrid")
|
|
44
|
+
|
|
45
|
+
plt.figure(figsize=figsize)
|
|
46
|
+
ax = sns.lineplot(
|
|
47
|
+
data=df,
|
|
48
|
+
x=coverage_col,
|
|
49
|
+
y=recognition_col,
|
|
50
|
+
marker="o",
|
|
51
|
+
label="Recognition-Coverage Curve" if show_legend else None,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if show_f2:
|
|
55
|
+
for i, txt in enumerate(df[f2_score_col]):
|
|
56
|
+
ax.annotate(
|
|
57
|
+
r"$F_2=" + f"{txt:.2f}" + "$",
|
|
58
|
+
(df[coverage_col].iloc[i], df[recognition_col].iloc[i]),
|
|
59
|
+
textcoords="offset points",
|
|
60
|
+
xytext=(0, 10),
|
|
61
|
+
ha="center",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Adding labels, title, and legend with LaTeX
|
|
65
|
+
plt.xlabel(r"$\mathrm{{Coverage\%}}$", fontsize=18)
|
|
66
|
+
plt.ylabel(r"$\mathrm{{Recognition\%}}$", fontsize=18)
|
|
67
|
+
plt.title(r"Recognition-Coverage Curve", fontsize=24)
|
|
68
|
+
plt.legend()
|
|
69
|
+
plt.grid(True)
|
|
70
|
+
plt.show()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def plot_f2_scores_line(data, figsize=(8, 6), show_f2=True, show_legend=True):
|
|
74
|
+
"""Plots F2 scores across different radii using a line plot, showing the
|
|
75
|
+
trend of F2 score changes, and annotated with optional F2 scores.
|
|
76
|
+
|
|
77
|
+
:param data: Dictionary containing nested dictionaries with 'F2_score'
|
|
78
|
+
and possibly other metrics.
|
|
79
|
+
:type data: dict
|
|
80
|
+
:param figsize: Figure size for the plot, default is (8, 6).
|
|
81
|
+
:type figsize: tuple
|
|
82
|
+
:param show_f2: Whether to show F2 scores on the curve, default is True.
|
|
83
|
+
:type show_f2: bool
|
|
84
|
+
:param show_legend: Whether to show the legend on the plot, default is True.
|
|
85
|
+
|
|
86
|
+
Example Data format:
|
|
87
|
+
{'radii_0': {'Novelty': 96.44, 'Coverage': 93.98, 'Recognition': 3.55,
|
|
88
|
+
'F2_score': 0.15}, ...}
|
|
89
|
+
:type show_legend: bool
|
|
90
|
+
"""
|
|
91
|
+
# Convert the nested dictionary into a DataFrame and prepare for plotting
|
|
92
|
+
df = pd.DataFrame(data).T
|
|
93
|
+
df["Radii"] = [int(key.split("_")[1]) for key in data.keys()]
|
|
94
|
+
df.sort_values("Radii", inplace=True) # Ensure data is sorted by radii
|
|
95
|
+
|
|
96
|
+
# Setting up Seaborn for enhanced plotting style
|
|
97
|
+
sns.set_theme(style="whitegrid")
|
|
98
|
+
|
|
99
|
+
# Create the plot
|
|
100
|
+
plt.figure(figsize=figsize)
|
|
101
|
+
sns.lineplot(
|
|
102
|
+
data=df,
|
|
103
|
+
x="Radii",
|
|
104
|
+
y="F2_score",
|
|
105
|
+
marker="o",
|
|
106
|
+
label="F2 Score Trend" if show_legend else None,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Optionally annotate each point with its F2 score
|
|
110
|
+
if show_f2:
|
|
111
|
+
for i in range(len(df)):
|
|
112
|
+
plt.text(
|
|
113
|
+
df.iloc[i]["Radii"],
|
|
114
|
+
df.iloc[i]["F2_score"] + 0.01,
|
|
115
|
+
r"$F_2=" + f'{df.iloc[i]["F2_score"]:.2f}' + "$",
|
|
116
|
+
color="black",
|
|
117
|
+
ha="center",
|
|
118
|
+
va="bottom",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Adding labels, title, and legend with LaTeX
|
|
122
|
+
plt.xlabel(r"$\text{Radii}$", fontsize=18)
|
|
123
|
+
plt.ylabel(r"$F_2\ \text{Score}$", fontsize=18)
|
|
124
|
+
plt.title(r"$F_2\ \text{Score}$ Across Different Radii", fontsize=24)
|
|
125
|
+
if show_legend:
|
|
126
|
+
plt.legend()
|
|
127
|
+
|
|
128
|
+
plt.grid(True)
|
|
129
|
+
plt.show()
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import statistics
|
|
2
|
+
from typing import List, Dict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _coverage(
|
|
6
|
+
reactions_data: List[Dict[str, str]], key_ground_truth: str, key_prediction: str
|
|
7
|
+
) -> float:
|
|
8
|
+
"""Calculates the coverage percentage, which measures how many of the
|
|
9
|
+
predicted reactions exactly match the ground truth reactions given in a
|
|
10
|
+
list of dictionaries.
|
|
11
|
+
|
|
12
|
+
:param reactions_data: List of dictionaries containing
|
|
13
|
+
reaction SMILES strings.
|
|
14
|
+
:type reactions_data: List[Dict[str, str]]
|
|
15
|
+
:param key_ground_truth: Key in the dictionary for the ground truth reaction SMILES.
|
|
16
|
+
:type key_ground_truth: str
|
|
17
|
+
:param key_prediction: Key in the dictionary for the predicted reaction SMILES.
|
|
18
|
+
:type key_prediction: str
|
|
19
|
+
|
|
20
|
+
:return: The coverage percentage.
|
|
21
|
+
:rtype: float
|
|
22
|
+
"""
|
|
23
|
+
correct_matches = sum(
|
|
24
|
+
1
|
|
25
|
+
for reaction in reactions_data
|
|
26
|
+
if reaction.get(key_ground_truth) in reaction.get(key_prediction)
|
|
27
|
+
)
|
|
28
|
+
return (correct_matches / len(reactions_data)) * 100 if reactions_data else 0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _novelty_rate(
|
|
32
|
+
reactions_data: List[Dict[str, any]], key_ground_truth: str, key_prediction: str
|
|
33
|
+
) -> float:
|
|
34
|
+
"""Calculates the False Positive Rate (FPR) for each observation and then
|
|
35
|
+
averages these values across all observations. The FPR represents the
|
|
36
|
+
proportion of predictions that do not match the ground truth for each
|
|
37
|
+
individual entry in the dataset.
|
|
38
|
+
|
|
39
|
+
:param reactions_data: List of dictionaries containing
|
|
40
|
+
the ground truth and predicted reactions, where predictions are given as
|
|
41
|
+
a list of RSMIs.
|
|
42
|
+
:type reactions_data: List[Dict[str, any]]
|
|
43
|
+
:param key_ground_truth: Dictionary key to access the ground truth reaction RSMI.
|
|
44
|
+
:type key_ground_truth: str
|
|
45
|
+
:param key_prediction: Dictionary key to access the list of predicted reaction RSMIs.
|
|
46
|
+
:type key_prediction: str
|
|
47
|
+
|
|
48
|
+
:return: Average false-positive rate as a percentage.
|
|
49
|
+
:rtype: float
|
|
50
|
+
"""
|
|
51
|
+
fpr_list = [] # List to store FPR for each observation
|
|
52
|
+
|
|
53
|
+
for entry in reactions_data:
|
|
54
|
+
ground_truth = entry.get(key_ground_truth)
|
|
55
|
+
predictions = entry.get(key_prediction, [])
|
|
56
|
+
|
|
57
|
+
if not predictions: # Skip if no predictions
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
# Calculate FPR for this entry
|
|
61
|
+
false_positives = sum(1 for pred in predictions if pred != ground_truth)
|
|
62
|
+
total_predictions = len(predictions)
|
|
63
|
+
fpr_list.append((false_positives / total_predictions) * 100)
|
|
64
|
+
|
|
65
|
+
# Calculate and return the mean FPR
|
|
66
|
+
return statistics.mean(fpr_list) if fpr_list else 0.0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _recognition_rate(
|
|
70
|
+
reactions_data: List[Dict[str, any]], key_ground_truth: str, key_prediction: str
|
|
71
|
+
) -> float:
|
|
72
|
+
"""Calculates the recognition rate for each observation and averages these
|
|
73
|
+
rates across all observations. The recognition rate measures the proportion
|
|
74
|
+
of the prediction list that matches the single ground truth reaction for
|
|
75
|
+
each entry.
|
|
76
|
+
|
|
77
|
+
:param reactions_data: List of dictionaries containing
|
|
78
|
+
the ground truth
|
|
79
|
+
and predicted reactions, where the ground truth is a single RSMI and predictions
|
|
80
|
+
are lists of RSMIs.
|
|
81
|
+
:type reactions_data: List[Dict[str, any]]
|
|
82
|
+
:param key_ground_truth: Dictionary key to access the ground truth reaction RSMIs.
|
|
83
|
+
:type key_ground_truth: str
|
|
84
|
+
:param key_prediction: Dictionary key to access the list of predicted reaction RSMIs.
|
|
85
|
+
:type key_prediction: str
|
|
86
|
+
|
|
87
|
+
:return: Average recognition rate as a percentage.
|
|
88
|
+
:rtype: float
|
|
89
|
+
"""
|
|
90
|
+
recognition_rates = []
|
|
91
|
+
|
|
92
|
+
for entry in reactions_data:
|
|
93
|
+
ground_truth = entry.get(key_ground_truth)
|
|
94
|
+
predictions = entry.get(key_prediction, [])
|
|
95
|
+
|
|
96
|
+
if predictions:
|
|
97
|
+
|
|
98
|
+
matches = sum(1 for pred in predictions if pred == ground_truth)
|
|
99
|
+
|
|
100
|
+
recognition_rate = (matches / len(predictions)) * 100
|
|
101
|
+
recognition_rates.append(recognition_rate)
|
|
102
|
+
else:
|
|
103
|
+
recognition_rates.append(0.0)
|
|
104
|
+
|
|
105
|
+
return statistics.mean(recognition_rates) if recognition_rates else 0.0
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _top_k_accuracy(
|
|
109
|
+
reactions_data: List[Dict[str, any]],
|
|
110
|
+
key_ground_truth: str,
|
|
111
|
+
key_prediction: str,
|
|
112
|
+
k: int,
|
|
113
|
+
) -> float:
|
|
114
|
+
"""Calculates the Top-K accuracy by using the coverage function on the top
|
|
115
|
+
K predictions. This measures the probability that the true reaction is
|
|
116
|
+
within the top K predictions.
|
|
117
|
+
|
|
118
|
+
:param reactions_data: List of dictionaries containing
|
|
119
|
+
RSMI strings.
|
|
120
|
+
:type reactions_data: List[Dict[str, any]]
|
|
121
|
+
:param key_ground_truth: Key in the dictionary for the ground truth RSMI.
|
|
122
|
+
:type key_ground_truth: str
|
|
123
|
+
:param key_prediction: Key in the dictionary for the predicted RSMIs
|
|
124
|
+
(list of predictions).
|
|
125
|
+
:type key_prediction: str
|
|
126
|
+
:param k: The number of top predictions to consider.
|
|
127
|
+
:type k: int
|
|
128
|
+
|
|
129
|
+
:return: The Top-K accuracy percentage.
|
|
130
|
+
:rtype: float
|
|
131
|
+
"""
|
|
132
|
+
modified_data = [
|
|
133
|
+
{**entry, "Top_K_Predictions": entry[key_prediction][:k]}
|
|
134
|
+
for entry in reactions_data
|
|
135
|
+
]
|
|
136
|
+
return _coverage(modified_data, key_ground_truth, "Top_K_Predictions")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _calculate_f_beta_score(
|
|
140
|
+
recognition_rate: float, # This serves as the precision
|
|
141
|
+
coverage_rate: float, # This serves as the recall
|
|
142
|
+
beta: float = 1.0, # Beta factor, default is 1.0 for F1 score
|
|
143
|
+
) -> float:
|
|
144
|
+
"""Computes the F-beta Score, which is a weighted harmonic mean of
|
|
145
|
+
recognition rate and coverage rate. The recognition rate (precision) and
|
|
146
|
+
coverage rate (recall) must be expressed as percentages. A beta value of
|
|
147
|
+
1.0 means equal importance to precision and recall (F1 Score), greater than
|
|
148
|
+
1.0 gives more importance to recall (e.g., F2 Score), and less than 1.0
|
|
149
|
+
prioritizes precision (e.g., F0.5 Score).
|
|
150
|
+
|
|
151
|
+
:param recognition_rate: The recognition rate of the predictions,
|
|
152
|
+
acting as precision, expected to be between 0 and 100.
|
|
153
|
+
:type recognition_rate: float
|
|
154
|
+
:param coverage_rate: The coverage rate of the predictions, acting as recall,
|
|
155
|
+
expected to be between 0 and 100.
|
|
156
|
+
:type coverage_rate: float
|
|
157
|
+
:param beta: The weight emphasizing recall over precision. Default is 1.0.
|
|
158
|
+
:type beta: float
|
|
159
|
+
|
|
160
|
+
:return: The F-beta Score as a percentage, which balances precision and recall based on the beta factor.
|
|
161
|
+
:rtype: float
|
|
162
|
+
"""
|
|
163
|
+
if recognition_rate == 0 or coverage_rate == 0:
|
|
164
|
+
return 0 # If either rate is zero, F-beta is zero to avoid division by zero
|
|
165
|
+
|
|
166
|
+
# Calculate precision and recall
|
|
167
|
+
precision = recognition_rate / 100
|
|
168
|
+
recall = coverage_rate / 100
|
|
169
|
+
|
|
170
|
+
# Calculate F-beta Score using the formula:
|
|
171
|
+
# F-beta = (1 + beta^2) * (precision * recall) / (beta^2 * precision + recall)
|
|
172
|
+
beta_squared = beta**2
|
|
173
|
+
f_beta_score = (
|
|
174
|
+
(1 + beta_squared)
|
|
175
|
+
* (precision * recall)
|
|
176
|
+
/ ((beta_squared * precision) + recall)
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return f_beta_score
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Radical-based linking search, validation, and replayable proofs."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from .overlap import (
|
|
6
|
+
TypedOverlapCertificate,
|
|
7
|
+
TypedOverlapLimits,
|
|
8
|
+
TypedOverlapResult,
|
|
9
|
+
enumerate_typed_overlaps,
|
|
10
|
+
)
|
|
11
|
+
from .policy import (
|
|
12
|
+
AcceptanceTask,
|
|
13
|
+
OverlapScope,
|
|
14
|
+
ProofLevel,
|
|
15
|
+
RBLSearchPolicy,
|
|
16
|
+
SearchOutcomeStatus,
|
|
17
|
+
SearchScope,
|
|
18
|
+
TerminationPolicy,
|
|
19
|
+
)
|
|
20
|
+
from .proof import (
|
|
21
|
+
RBL_PROOF_SCHEMA,
|
|
22
|
+
RBLProofReplay,
|
|
23
|
+
RBLReplayCertificate,
|
|
24
|
+
read_rbl_proof,
|
|
25
|
+
)
|
|
26
|
+
from .state import RBL_RESULT_SCHEMA
|
|
27
|
+
from .validation import (
|
|
28
|
+
FusionIssue,
|
|
29
|
+
FusionIssueCode,
|
|
30
|
+
FusionValidation,
|
|
31
|
+
WildcardRole,
|
|
32
|
+
certify_fusion_postprocessing,
|
|
33
|
+
validate_endpoint_preservation,
|
|
34
|
+
validate_fusion_rsmi,
|
|
35
|
+
validate_rbl_candidate,
|
|
36
|
+
validate_strict_rbl_candidate,
|
|
37
|
+
validate_wildcard_mapping_roles,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from .engine import RBLEngine
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"AcceptanceTask",
|
|
45
|
+
"FusionIssue",
|
|
46
|
+
"FusionIssueCode",
|
|
47
|
+
"FusionValidation",
|
|
48
|
+
"OverlapScope",
|
|
49
|
+
"ProofLevel",
|
|
50
|
+
"RBLEngine",
|
|
51
|
+
"RBLProofReplay",
|
|
52
|
+
"RBLReplayCertificate",
|
|
53
|
+
"RBLSearchPolicy",
|
|
54
|
+
"RBL_PROOF_SCHEMA",
|
|
55
|
+
"RBL_RESULT_SCHEMA",
|
|
56
|
+
"SearchOutcomeStatus",
|
|
57
|
+
"SearchScope",
|
|
58
|
+
"TerminationPolicy",
|
|
59
|
+
"TypedOverlapCertificate",
|
|
60
|
+
"TypedOverlapLimits",
|
|
61
|
+
"TypedOverlapResult",
|
|
62
|
+
"WildcardRole",
|
|
63
|
+
"certify_fusion_postprocessing",
|
|
64
|
+
"enumerate_typed_overlaps",
|
|
65
|
+
"read_rbl_proof",
|
|
66
|
+
"validate_endpoint_preservation",
|
|
67
|
+
"validate_fusion_rsmi",
|
|
68
|
+
"validate_rbl_candidate",
|
|
69
|
+
"validate_strict_rbl_candidate",
|
|
70
|
+
"validate_wildcard_mapping_roles",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def __getattr__(name: str) -> object:
|
|
75
|
+
"""Load the engine lazily so lightweight policy imports stay cheap."""
|
|
76
|
+
if name == "RBLEngine":
|
|
77
|
+
from .engine import RBLEngine
|
|
78
|
+
|
|
79
|
+
return RBLEngine
|
|
80
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|