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,685 @@
|
|
|
1
|
+
"""Select mapping methods through one interface and report their search scope."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
from collections import Counter
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from numbers import Integral
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from .solvers.exact.distance_search.exhaustive import ExactMapper
|
|
13
|
+
from .solvers.exact.distance_search.records import normalize_distance_target
|
|
14
|
+
from .solvers.exact.distance_search.search import enumerate_distance_mappings
|
|
15
|
+
from .solvers.exact.hybrid import enumerate_hybrid_distance_mappings
|
|
16
|
+
from .solvers.exact.kernel_solvers.enumerate import enumerate_kernel_optima
|
|
17
|
+
from .solvers.exact.kernel_solvers.kernel import apply_kernel_solution, extract_kernel
|
|
18
|
+
from .solvers.exact.kernel_solvers.milp import solve_kernel_milp
|
|
19
|
+
from .solvers.exact.search import enumerate_pabs_mappings
|
|
20
|
+
from .graph.labeled_graph import LabeledGraph
|
|
21
|
+
from .reaction_search import ReactionMappingResult, _map_reaction_with_search
|
|
22
|
+
from .solvers.slap.lap import _adjacency_and_elements, chemical_distance, recover_mapping
|
|
23
|
+
from .solvers.slap.sequential import GraphMatcher
|
|
24
|
+
|
|
25
|
+
_SCOPES = {
|
|
26
|
+
"slap": "heuristic",
|
|
27
|
+
"kernel": "reduced_kernel",
|
|
28
|
+
"milp": "reduced_kernel",
|
|
29
|
+
"distance": "full_space",
|
|
30
|
+
"propagate": "full_space",
|
|
31
|
+
"native": "full_space",
|
|
32
|
+
"edits": "full_space",
|
|
33
|
+
"exhaustive": "full_space",
|
|
34
|
+
}
|
|
35
|
+
_ENUMERATORS = {"distance", "propagate", "native", "edits"}
|
|
36
|
+
_REACTION_OPTIONS = {
|
|
37
|
+
"hydrogen",
|
|
38
|
+
"objective",
|
|
39
|
+
"balance",
|
|
40
|
+
"max_hydrogen_plans",
|
|
41
|
+
"classification_max_search_nodes",
|
|
42
|
+
}
|
|
43
|
+
_DEFAULTS = {
|
|
44
|
+
"backend": None,
|
|
45
|
+
"CD": "minimal",
|
|
46
|
+
"CD_mode": "exact",
|
|
47
|
+
"binary": False,
|
|
48
|
+
"hydrogen": None,
|
|
49
|
+
"objective": "lewis",
|
|
50
|
+
"balance": "strict",
|
|
51
|
+
"max_hydrogen_plans": 10_000,
|
|
52
|
+
"classification_max_search_nodes": 100_000,
|
|
53
|
+
"library_path": None,
|
|
54
|
+
"search_config": None,
|
|
55
|
+
"max_edit_support_pairs": 50_000,
|
|
56
|
+
"max_lap_fingerprints": 10_000,
|
|
57
|
+
"solver": "pabs",
|
|
58
|
+
"allowed_domains": None,
|
|
59
|
+
"hydrogen_quotient": False,
|
|
60
|
+
}
|
|
61
|
+
_OPTION_NAMES = _DEFAULTS.keys() | {
|
|
62
|
+
"time_limit_seconds",
|
|
63
|
+
"max_mappings",
|
|
64
|
+
"max_bijections",
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
class MappingResult:
|
|
70
|
+
"""Common result for graph pairs and reaction SMILES.
|
|
71
|
+
|
|
72
|
+
``mappings[i][j]`` is the product index assigned to reactant atom ``j``.
|
|
73
|
+
SMILES results retain symmetry class representatives. ``minimum_cost`` and
|
|
74
|
+
``optimality_proven`` apply within ``search_scope`` and the chosen objective.
|
|
75
|
+
``complete`` means enumeration and any chemical classification completed in
|
|
76
|
+
that scope. It is always false for heuristic or single-optimum methods.
|
|
77
|
+
A proven minimum can coexist with incomplete enumeration.
|
|
78
|
+
|
|
79
|
+
For compressed hydrogen, the minimum is for heavy bonds; returned distances
|
|
80
|
+
include conditional hydrogen lifts. See ``reaction_result`` for that scope.
|
|
81
|
+
``search_result`` preserves the underlying solver's records and statistics.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
method: str
|
|
85
|
+
search_scope: str
|
|
86
|
+
mappings: tuple[tuple[int, ...], ...]
|
|
87
|
+
distances: tuple[float, ...]
|
|
88
|
+
minimum_cost: float | None
|
|
89
|
+
optimality_proven: bool
|
|
90
|
+
complete: bool
|
|
91
|
+
incomplete_reason: str | None
|
|
92
|
+
elapsed_seconds: float
|
|
93
|
+
search_result: object
|
|
94
|
+
reaction_result: ReactionMappingResult | None = None
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def mapped_reactions(self) -> tuple[str, ...]:
|
|
98
|
+
"""Mapped reaction SMILES, or an empty tuple for graph input."""
|
|
99
|
+
return (
|
|
100
|
+
()
|
|
101
|
+
if self.reaction_result is None
|
|
102
|
+
else self.reaction_result.mapped_reactions
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def as_dict(self) -> dict[str, object]:
|
|
106
|
+
"""Export common metadata and chemistry records without solver internals."""
|
|
107
|
+
return {
|
|
108
|
+
"method": self.method,
|
|
109
|
+
"search_scope": self.search_scope,
|
|
110
|
+
"mappings": [list(mapping) for mapping in self.mappings],
|
|
111
|
+
"distances": list(self.distances),
|
|
112
|
+
"minimum_cost": self.minimum_cost,
|
|
113
|
+
"optimality_proven": self.optimality_proven,
|
|
114
|
+
"complete": self.complete,
|
|
115
|
+
"incomplete_reason": self.incomplete_reason,
|
|
116
|
+
"elapsed_seconds": self.elapsed_seconds,
|
|
117
|
+
"reaction_result": (
|
|
118
|
+
None if self.reaction_result is None else self.reaction_result.as_dict()
|
|
119
|
+
),
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@dataclass
|
|
124
|
+
class _SearchOutcome:
|
|
125
|
+
"""Search results consumed by the reaction-SMILES frontend."""
|
|
126
|
+
|
|
127
|
+
mappings: list[list[int]]
|
|
128
|
+
distances: list[float]
|
|
129
|
+
minimum_cost: float | None
|
|
130
|
+
optimality_proven: bool
|
|
131
|
+
complete: bool
|
|
132
|
+
truncation_reason: str | None
|
|
133
|
+
backend: str
|
|
134
|
+
selected_mapping_count: int
|
|
135
|
+
raw_result: object
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def backend_statistics(self):
|
|
139
|
+
return getattr(self.raw_result, "backend_statistics", None)
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def selected_labeled_mapping_count(self):
|
|
143
|
+
return getattr(
|
|
144
|
+
self.raw_result,
|
|
145
|
+
"selected_labeled_mapping_count",
|
|
146
|
+
self.selected_mapping_count,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _prepare_graphs(data):
|
|
151
|
+
if (
|
|
152
|
+
not isinstance(data, (list, tuple))
|
|
153
|
+
or len(data) != 2
|
|
154
|
+
or not all(isinstance(graph, LabeledGraph) for graph in data)
|
|
155
|
+
):
|
|
156
|
+
raise TypeError(
|
|
157
|
+
"data must be reaction SMILES or a pair of LabeledGraph objects"
|
|
158
|
+
)
|
|
159
|
+
graphs = []
|
|
160
|
+
inventories = []
|
|
161
|
+
label_codes = {}
|
|
162
|
+
for source in data:
|
|
163
|
+
if any(source.graph[i].get(i, 0) != 0 for i in range(len(source.labels))):
|
|
164
|
+
raise ValueError("Mapper requires loop-free graphs")
|
|
165
|
+
adjacency, elements = _adjacency_and_elements(source, False)
|
|
166
|
+
if len(elements) != len(source.labels):
|
|
167
|
+
raise ValueError("Atom labels must have one entry per node")
|
|
168
|
+
if not np.isfinite(adjacency).all() or (adjacency < 0).any():
|
|
169
|
+
raise ValueError("Bond weights must be finite and non-negative")
|
|
170
|
+
if not np.array_equal(adjacency, adjacency.T):
|
|
171
|
+
raise ValueError("Mapper requires symmetric undirected graphs")
|
|
172
|
+
graph = LabeledGraph(
|
|
173
|
+
{
|
|
174
|
+
i: {int(j): float(row[j]) for j in np.flatnonzero(row)}
|
|
175
|
+
for i, row in enumerate(adjacency)
|
|
176
|
+
},
|
|
177
|
+
[label_codes.setdefault(element, len(label_codes)) for element in elements],
|
|
178
|
+
)
|
|
179
|
+
graph.props = dict(source.props)
|
|
180
|
+
graph.props["atomic numbers"] = elements
|
|
181
|
+
graphs.append(graph)
|
|
182
|
+
inventories.append(Counter(elements))
|
|
183
|
+
if inventories[0] != inventories[1]:
|
|
184
|
+
raise ValueError("Endpoints must have equal atom-type inventories")
|
|
185
|
+
return graphs
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# Keep the independent method/option compatibility checks together.
|
|
189
|
+
def _check_method_options(method, config, requested): # noqa: C901
|
|
190
|
+
"""Reject queries and limits unsupported by the selected method."""
|
|
191
|
+
backend = config["backend"]
|
|
192
|
+
if {"solver", "allowed_domains", "hydrogen_quotient"} & requested.keys():
|
|
193
|
+
if method != "native":
|
|
194
|
+
raise ValueError(
|
|
195
|
+
"solver, allowed_domains and hydrogen_quotient require method='native'"
|
|
196
|
+
)
|
|
197
|
+
from .solvers.native.runtime import BACKENDS
|
|
198
|
+
|
|
199
|
+
if config["solver"] not in BACKENDS:
|
|
200
|
+
raise ValueError(f"Unknown native solver: {config['solver']}")
|
|
201
|
+
if config["allowed_domains"] is not None and config["solver"] not in {
|
|
202
|
+
"kbb",
|
|
203
|
+
"kmilp",
|
|
204
|
+
}:
|
|
205
|
+
raise ValueError("allowed_domains requires solver='kbb' or 'kmilp'")
|
|
206
|
+
if not isinstance(config["hydrogen_quotient"], bool):
|
|
207
|
+
raise TypeError("hydrogen_quotient must be boolean")
|
|
208
|
+
if config["hydrogen_quotient"] and config["solver"] in {
|
|
209
|
+
"kbb",
|
|
210
|
+
"kmilp",
|
|
211
|
+
"slap",
|
|
212
|
+
"edit",
|
|
213
|
+
}:
|
|
214
|
+
raise ValueError(
|
|
215
|
+
"hydrogen_quotient requires a full-space weighted exact solver"
|
|
216
|
+
)
|
|
217
|
+
if backend not in {"python", "cpp"}:
|
|
218
|
+
raise ValueError(
|
|
219
|
+
"backend must be 'python', 'cpp', or None for automatic selection"
|
|
220
|
+
)
|
|
221
|
+
native_slap = method == "slap" and backend == "cpp"
|
|
222
|
+
if method == "native" and backend != "cpp":
|
|
223
|
+
raise ValueError("method='native' requires backend='cpp'")
|
|
224
|
+
if backend == "cpp" and method not in {"native", "slap"}:
|
|
225
|
+
raise ValueError(
|
|
226
|
+
"backend='cpp' currently supports method='slap' or method='native'"
|
|
227
|
+
)
|
|
228
|
+
if config["CD_mode"] not in {"exact", "at_most"}:
|
|
229
|
+
raise ValueError("CD_mode must be 'exact' or 'at_most'")
|
|
230
|
+
if config["CD_mode"] == "at_most" and (
|
|
231
|
+
method != "native" or config["CD"] == "minimal"
|
|
232
|
+
):
|
|
233
|
+
raise ValueError("CD_mode='at_most' requires method='native' and numeric CD")
|
|
234
|
+
if method not in _ENUMERATORS:
|
|
235
|
+
if config["CD"] != "minimal":
|
|
236
|
+
raise ValueError(f"method='{method}' only supports CD='minimal'")
|
|
237
|
+
for name in ("time_limit_seconds", "max_mappings", "max_bijections"):
|
|
238
|
+
if native_slap and name != "max_bijections":
|
|
239
|
+
continue
|
|
240
|
+
if config[name] is not None:
|
|
241
|
+
raise ValueError(f"method='{method}' does not support {name}")
|
|
242
|
+
if method != "native" and not native_slap and config["library_path"] is not None:
|
|
243
|
+
raise ValueError(
|
|
244
|
+
"library_path requires method='native' or method='slap', backend='cpp'"
|
|
245
|
+
)
|
|
246
|
+
if (method == "native" or native_slap) and config["library_path"] is None:
|
|
247
|
+
from .solvers.native.runtime import resolve_library_path
|
|
248
|
+
|
|
249
|
+
config["library_path"] = resolve_library_path()
|
|
250
|
+
if "max_lap_fingerprints" in requested and method != "slap":
|
|
251
|
+
raise ValueError("max_lap_fingerprints requires method='slap'")
|
|
252
|
+
if method == "slap" and (
|
|
253
|
+
isinstance(config["max_lap_fingerprints"], bool)
|
|
254
|
+
or not isinstance(config["max_lap_fingerprints"], Integral)
|
|
255
|
+
or not 1 <= config["max_lap_fingerprints"] < 2**31
|
|
256
|
+
):
|
|
257
|
+
raise ValueError("max_lap_fingerprints must be a positive C ABI integer")
|
|
258
|
+
if method != "propagate" and config["search_config"] is not None:
|
|
259
|
+
raise ValueError("search_config requires method='propagate'")
|
|
260
|
+
if method != "edits" and "max_edit_support_pairs" in requested:
|
|
261
|
+
raise ValueError("max_edit_support_pairs requires method='edits'")
|
|
262
|
+
if method == "edits":
|
|
263
|
+
if config["CD"] == "minimal" or not config["binary"]:
|
|
264
|
+
raise ValueError("method='edits' requires numeric CD and binary=True")
|
|
265
|
+
if config["max_bijections"] is not None:
|
|
266
|
+
raise ValueError("method='edits' does not support max_bijections")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class Mapper:
|
|
270
|
+
"""Select a solver by a concise name and map SMILES or labeled graph pairs.
|
|
271
|
+
|
|
272
|
+
``Mapper(method='propagate')`` defaults to full-space exact Python search.
|
|
273
|
+
:meth:`methods` lists the eight accepted names. ``slap`` is heuristic;
|
|
274
|
+
``kernel`` enumerates optima in a SLAP-derived restricted problem; ``milp``
|
|
275
|
+
solves that problem for one optimum using optional PuLP/CBC. ``distance``
|
|
276
|
+
and ``propagate`` enumerate full-space minimum or numeric CD shells.
|
|
277
|
+
``native`` loads the bundled wheel library or an explicit ``library_path``.
|
|
278
|
+
``edits`` requires
|
|
279
|
+
numeric ``CD`` and ``binary=True``. ``exhaustive`` returns one global optimum
|
|
280
|
+
and is intended for small graphs.
|
|
281
|
+
|
|
282
|
+
Constructor options become defaults; options passed to :meth:`map` override
|
|
283
|
+
them for that call. Reaction input defaults to Lewis CD with explicit H;
|
|
284
|
+
``objective='bond'`` selects the previous heavy-atom bond-only default.
|
|
285
|
+
Graph input uses its supplied weighted bonds and must be symmetric and
|
|
286
|
+
loop-free, with equal atom-type inventories. Inputs are copied before matching.
|
|
287
|
+
|
|
288
|
+
Enumeration methods default to a 10-second shared deadline and 100,000
|
|
289
|
+
mappings. Assignment enumerators cap graph input at 1,000,000 bijections;
|
|
290
|
+
reaction input has no default factorial admission cap. An explicit
|
|
291
|
+
``max_bijections`` limits either input. SLAP, kernel, MILP and exhaustive
|
|
292
|
+
methods have no deadline or
|
|
293
|
+
output-cap support; supplying these limits raises an error. Existing solver
|
|
294
|
+
APIs remain available for their specialized options.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
def __init__(self, method="propagate", **options):
|
|
298
|
+
if not isinstance(method, str) or method not in _SCOPES:
|
|
299
|
+
raise ValueError(
|
|
300
|
+
f"Unknown mapping method {method!r}; choose from {', '.join(_SCOPES)}"
|
|
301
|
+
)
|
|
302
|
+
self._check_option_names(options)
|
|
303
|
+
self.method = method
|
|
304
|
+
self._options = dict(options)
|
|
305
|
+
|
|
306
|
+
@staticmethod
|
|
307
|
+
def methods() -> tuple[str, ...]:
|
|
308
|
+
"""Return the supported mapping method names."""
|
|
309
|
+
return tuple(_SCOPES)
|
|
310
|
+
|
|
311
|
+
@staticmethod
|
|
312
|
+
def native_methods(*, available_only=False, library_path=None) -> tuple[str, ...]:
|
|
313
|
+
"""Native solver names for ``Mapper('native', solver=..., ...)``.
|
|
314
|
+
|
|
315
|
+
Availability depends on the explicitly supplied library's capabilities;
|
|
316
|
+
optional SDKs and restricted-domain methods retain their own scope.
|
|
317
|
+
``available_only=True`` inspects the explicit or bundled library.
|
|
318
|
+
"""
|
|
319
|
+
from .solvers.native.runtime import BACKENDS, available_native_methods
|
|
320
|
+
|
|
321
|
+
if available_only:
|
|
322
|
+
return available_native_methods(library_path)
|
|
323
|
+
return tuple(BACKENDS)
|
|
324
|
+
|
|
325
|
+
@staticmethod
|
|
326
|
+
def _check_option_names(options):
|
|
327
|
+
unknown = options.keys() - _OPTION_NAMES
|
|
328
|
+
if unknown:
|
|
329
|
+
raise TypeError(f"Unknown Mapper option(s): {', '.join(sorted(unknown))}")
|
|
330
|
+
|
|
331
|
+
def map(self, data, **options) -> MappingResult:
|
|
332
|
+
"""Map reaction SMILES or ``(reactant_graph, product_graph)``.
|
|
333
|
+
|
|
334
|
+
Common options are ``CD='minimal'`` and ``binary=False``. Enumeration
|
|
335
|
+
methods accept ``time_limit_seconds`` and ``max_mappings``. Assignment
|
|
336
|
+
enumerators accept ``max_bijections``. Reaction inputs also accept
|
|
337
|
+
``hydrogen``, ``objective``, ``balance``, ``max_hydrogen_plans``, and
|
|
338
|
+
``classification_max_search_nodes``, as documented by ``map_reaction``.
|
|
339
|
+
``CD_mode='at_most'`` selects distance <= numeric CD for native search;
|
|
340
|
+
the default ``'exact'`` selects exactly CD. With CD omitted, exact
|
|
341
|
+
enumerators return every minimum-distance class for reaction input.
|
|
342
|
+
``search_config`` is propagation-only; ``library_path`` is native-only;
|
|
343
|
+
``max_edit_support_pairs`` limits the edit-support method.
|
|
344
|
+
``backend='cpp'`` also selects opt-in deterministic weighted SLAP with
|
|
345
|
+
a library built by ``_native.build.build_mapper_native``. Its search
|
|
346
|
+
remains heuristic; exact chemistry/classification is shared.
|
|
347
|
+
"""
|
|
348
|
+
self._check_option_names(options)
|
|
349
|
+
requested = self._options | options
|
|
350
|
+
method = self.method
|
|
351
|
+
if method not in _SCOPES:
|
|
352
|
+
raise ValueError(f"Unknown mapping method {method!r}")
|
|
353
|
+
enumerating = method in _ENUMERATORS
|
|
354
|
+
backend = requested.get("backend")
|
|
355
|
+
if backend is None:
|
|
356
|
+
backend = "cpp" if method == "native" else "python"
|
|
357
|
+
native_slap = method == "slap" and backend == "cpp"
|
|
358
|
+
reaction_input = isinstance(data, str)
|
|
359
|
+
config = (
|
|
360
|
+
_DEFAULTS
|
|
361
|
+
| {
|
|
362
|
+
"time_limit_seconds": 10.0 if enumerating or native_slap else None,
|
|
363
|
+
"max_mappings": 100_000 if enumerating or native_slap else None,
|
|
364
|
+
"max_bijections": (
|
|
365
|
+
1_000_000
|
|
366
|
+
if not reaction_input
|
|
367
|
+
and method in {"distance", "propagate", "native"}
|
|
368
|
+
else None
|
|
369
|
+
),
|
|
370
|
+
}
|
|
371
|
+
| requested
|
|
372
|
+
| {"backend": backend}
|
|
373
|
+
)
|
|
374
|
+
config["CD"] = normalize_distance_target(config["CD"])
|
|
375
|
+
if not isinstance(config["binary"], bool):
|
|
376
|
+
raise TypeError("binary must be boolean")
|
|
377
|
+
_check_method_options(method, config, requested)
|
|
378
|
+
if not reaction_input and requested.keys() & _REACTION_OPTIONS:
|
|
379
|
+
raise ValueError(
|
|
380
|
+
"Hydrogen, objective, balance and classification options require reaction SMILES"
|
|
381
|
+
)
|
|
382
|
+
started = time.perf_counter()
|
|
383
|
+
shared_core = False
|
|
384
|
+
if method == "native":
|
|
385
|
+
from .solvers.native.runtime import has_core
|
|
386
|
+
|
|
387
|
+
shared_core = has_core(str(config["library_path"]))
|
|
388
|
+
if not shared_core and config["solver"] != "pabs":
|
|
389
|
+
raise ValueError("solver requires a library from build_mapper_native")
|
|
390
|
+
native_classes = shared_core
|
|
391
|
+
scope = (
|
|
392
|
+
"reduced_kernel"
|
|
393
|
+
if method == "native" and config["solver"] in {"kbb", "kmilp"}
|
|
394
|
+
else "heuristic"
|
|
395
|
+
if method == "native" and config["solver"] == "slap"
|
|
396
|
+
else _SCOPES[method]
|
|
397
|
+
)
|
|
398
|
+
if reaction_input:
|
|
399
|
+
|
|
400
|
+
def search(graphs, **query):
|
|
401
|
+
return self._solve(
|
|
402
|
+
graphs,
|
|
403
|
+
config | {"time_limit_seconds": query["time_limit_seconds"]},
|
|
404
|
+
mapping_callback=query["mapping_callback"],
|
|
405
|
+
collect_mappings=False,
|
|
406
|
+
native_symmetry=query.get("symmetry", False),
|
|
407
|
+
node_properties=query.get("node_properties", ()),
|
|
408
|
+
native_classifier=query.get("_native_classifier"),
|
|
409
|
+
native_class_registry=query.get("_native_class_registry"),
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
reaction = _map_reaction_with_search(
|
|
413
|
+
data,
|
|
414
|
+
search_function=search,
|
|
415
|
+
backend=backend,
|
|
416
|
+
native_classification_library=config["library_path"]
|
|
417
|
+
if native_classes
|
|
418
|
+
else None,
|
|
419
|
+
**{name: config[name] for name in _REACTION_OPTIONS},
|
|
420
|
+
**{
|
|
421
|
+
name: config[name]
|
|
422
|
+
for name in (
|
|
423
|
+
"CD",
|
|
424
|
+
"CD_mode",
|
|
425
|
+
"binary",
|
|
426
|
+
"time_limit_seconds",
|
|
427
|
+
"max_mappings",
|
|
428
|
+
"max_bijections",
|
|
429
|
+
"search_config",
|
|
430
|
+
"library_path",
|
|
431
|
+
)
|
|
432
|
+
},
|
|
433
|
+
)
|
|
434
|
+
outcome = reaction.search_result
|
|
435
|
+
return MappingResult(
|
|
436
|
+
method,
|
|
437
|
+
scope,
|
|
438
|
+
tuple(item.mapping for item in reaction.reactions),
|
|
439
|
+
tuple(item.distance for item in reaction.reactions),
|
|
440
|
+
outcome.minimum_cost,
|
|
441
|
+
outcome.optimality_proven,
|
|
442
|
+
reaction.complete,
|
|
443
|
+
reaction.incomplete_reason,
|
|
444
|
+
time.perf_counter() - started,
|
|
445
|
+
outcome.raw_result,
|
|
446
|
+
reaction,
|
|
447
|
+
)
|
|
448
|
+
outcome = self._solve(data, config)
|
|
449
|
+
return MappingResult(
|
|
450
|
+
method,
|
|
451
|
+
scope,
|
|
452
|
+
tuple(tuple(mapping) for mapping in outcome.mappings),
|
|
453
|
+
tuple(outcome.distances),
|
|
454
|
+
outcome.minimum_cost,
|
|
455
|
+
outcome.optimality_proven,
|
|
456
|
+
outcome.complete,
|
|
457
|
+
outcome.truncation_reason,
|
|
458
|
+
time.perf_counter() - started,
|
|
459
|
+
outcome.raw_result,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
def _enumerate_graphs(
|
|
463
|
+
self,
|
|
464
|
+
graphs,
|
|
465
|
+
options,
|
|
466
|
+
mapping_callback,
|
|
467
|
+
collect_mappings,
|
|
468
|
+
native_symmetry=False,
|
|
469
|
+
node_properties=(),
|
|
470
|
+
native_classifier=None,
|
|
471
|
+
native_class_registry=None,
|
|
472
|
+
):
|
|
473
|
+
"""Adapt distance-shell enumerators to the common result fields."""
|
|
474
|
+
method = self.method
|
|
475
|
+
query = {
|
|
476
|
+
name: options[name]
|
|
477
|
+
for name in (
|
|
478
|
+
"CD",
|
|
479
|
+
"binary",
|
|
480
|
+
"time_limit_seconds",
|
|
481
|
+
"max_mappings",
|
|
482
|
+
"max_bijections",
|
|
483
|
+
)
|
|
484
|
+
}
|
|
485
|
+
query.update(
|
|
486
|
+
collect_mappings=collect_mappings,
|
|
487
|
+
mapping_callback=mapping_callback,
|
|
488
|
+
compute_minimum_cost=(options["CD"] == "minimal"),
|
|
489
|
+
)
|
|
490
|
+
if method == "distance":
|
|
491
|
+
result = enumerate_distance_mappings(graphs, **query)
|
|
492
|
+
elif method == "edits":
|
|
493
|
+
result = enumerate_hybrid_distance_mappings(
|
|
494
|
+
graphs,
|
|
495
|
+
backend="edit_support",
|
|
496
|
+
max_edit_support_pairs=options["max_edit_support_pairs"],
|
|
497
|
+
**query,
|
|
498
|
+
)
|
|
499
|
+
else:
|
|
500
|
+
if options["search_config"] is not None:
|
|
501
|
+
query["config"] = options["search_config"]
|
|
502
|
+
if method == "native":
|
|
503
|
+
query.update(
|
|
504
|
+
CD_mode=options["CD_mode"],
|
|
505
|
+
symmetry=native_symmetry and options["solver"] in {"pabs", "cpabs"},
|
|
506
|
+
node_properties=node_properties,
|
|
507
|
+
)
|
|
508
|
+
from .solvers.native.runtime import has_core
|
|
509
|
+
|
|
510
|
+
if has_core(str(options["library_path"])):
|
|
511
|
+
from .solvers.native.core import enumerate_core_mappings
|
|
512
|
+
|
|
513
|
+
enumerate_native = enumerate_core_mappings
|
|
514
|
+
additional = {"allowed_domains": options["allowed_domains"]}
|
|
515
|
+
if options["hydrogen_quotient"]:
|
|
516
|
+
from .solvers.native.hydrogen import enumerate_hydrogen_mappings
|
|
517
|
+
|
|
518
|
+
enumerate_native = enumerate_hydrogen_mappings
|
|
519
|
+
additional = {
|
|
520
|
+
"max_transport_plans": options["max_hydrogen_plans"],
|
|
521
|
+
"max_canonical_nodes": options[
|
|
522
|
+
"classification_max_search_nodes"
|
|
523
|
+
],
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
result = enumerate_native(
|
|
527
|
+
graphs,
|
|
528
|
+
backend=options["solver"],
|
|
529
|
+
library_path=options["library_path"],
|
|
530
|
+
**additional,
|
|
531
|
+
_native_classifier=native_classifier,
|
|
532
|
+
_native_class_registry=native_class_registry,
|
|
533
|
+
**query,
|
|
534
|
+
)
|
|
535
|
+
return _SearchOutcome(
|
|
536
|
+
result.mappings,
|
|
537
|
+
result.distances,
|
|
538
|
+
result.minimum_cost,
|
|
539
|
+
result.minimum_cost is not None,
|
|
540
|
+
result.complete,
|
|
541
|
+
result.truncation_reason,
|
|
542
|
+
result.backend,
|
|
543
|
+
result.selected_mapping_count,
|
|
544
|
+
result,
|
|
545
|
+
)
|
|
546
|
+
result = enumerate_pabs_mappings(
|
|
547
|
+
graphs,
|
|
548
|
+
backend="cpp" if method == "native" else "python",
|
|
549
|
+
library_path=options["library_path"],
|
|
550
|
+
**query,
|
|
551
|
+
)
|
|
552
|
+
return _SearchOutcome(
|
|
553
|
+
result.mappings,
|
|
554
|
+
result.distances,
|
|
555
|
+
result.minimum_cost,
|
|
556
|
+
result.minimum_cost is not None,
|
|
557
|
+
result.complete,
|
|
558
|
+
result.truncation_reason,
|
|
559
|
+
result.backend,
|
|
560
|
+
result.selected_mapping_count,
|
|
561
|
+
result,
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
def _solve(
|
|
565
|
+
self,
|
|
566
|
+
data,
|
|
567
|
+
options,
|
|
568
|
+
*,
|
|
569
|
+
mapping_callback=None,
|
|
570
|
+
collect_mappings=True,
|
|
571
|
+
native_symmetry=False,
|
|
572
|
+
node_properties=(),
|
|
573
|
+
native_classifier=None,
|
|
574
|
+
native_class_registry=None,
|
|
575
|
+
):
|
|
576
|
+
graphs = _prepare_graphs(data)
|
|
577
|
+
method, binary = self.method, options["binary"]
|
|
578
|
+
if method in _ENUMERATORS:
|
|
579
|
+
return self._enumerate_graphs(
|
|
580
|
+
graphs,
|
|
581
|
+
options,
|
|
582
|
+
mapping_callback,
|
|
583
|
+
collect_mappings,
|
|
584
|
+
native_symmetry,
|
|
585
|
+
node_properties,
|
|
586
|
+
native_classifier,
|
|
587
|
+
native_class_registry,
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
if method == "slap" and options["backend"] == "cpp":
|
|
591
|
+
from .solvers.native.slap import solve_slap
|
|
592
|
+
|
|
593
|
+
raw = solve_slap(
|
|
594
|
+
graphs,
|
|
595
|
+
library_path=options["library_path"],
|
|
596
|
+
binary=binary,
|
|
597
|
+
max_lap_fingerprints=options["max_lap_fingerprints"],
|
|
598
|
+
time_limit_seconds=options["time_limit_seconds"],
|
|
599
|
+
max_mappings=options["max_mappings"],
|
|
600
|
+
collect_mappings=collect_mappings,
|
|
601
|
+
mapping_callback=mapping_callback,
|
|
602
|
+
)
|
|
603
|
+
return _SearchOutcome(
|
|
604
|
+
raw.mappings,
|
|
605
|
+
raw.distances,
|
|
606
|
+
None,
|
|
607
|
+
False,
|
|
608
|
+
False,
|
|
609
|
+
raw.truncation_reason or "heuristic",
|
|
610
|
+
raw.backend,
|
|
611
|
+
raw.selected_mapping_count,
|
|
612
|
+
raw,
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
if method == "exhaustive":
|
|
616
|
+
if binary:
|
|
617
|
+
for graph in graphs:
|
|
618
|
+
graph.binarize_graph()
|
|
619
|
+
raw = ExactMapper().solve(*graphs)
|
|
620
|
+
mappings, proven, complete, reason = (
|
|
621
|
+
[raw.mapping],
|
|
622
|
+
True,
|
|
623
|
+
False,
|
|
624
|
+
"optimum_only",
|
|
625
|
+
)
|
|
626
|
+
else:
|
|
627
|
+
matcher = GraphMatcher(
|
|
628
|
+
binary=binary,
|
|
629
|
+
max_lap_fingerprints=options["max_lap_fingerprints"],
|
|
630
|
+
)
|
|
631
|
+
matcher.get_maps(
|
|
632
|
+
graphs, break_sym_targets=list(range(len(graphs[0].labels)))
|
|
633
|
+
)
|
|
634
|
+
if not matcher.results:
|
|
635
|
+
raise RuntimeError("SLAP did not produce a mapping")
|
|
636
|
+
if method == "slap":
|
|
637
|
+
raw = matcher
|
|
638
|
+
mappings = [recover_mapping(item["lgp"]) for item in matcher.results]
|
|
639
|
+
proven, complete, reason = False, False, "heuristic"
|
|
640
|
+
else:
|
|
641
|
+
kernel = extract_kernel(matcher.results, graphs, binary=binary)
|
|
642
|
+
if method == "kernel":
|
|
643
|
+
raw = enumerate_kernel_optima(kernel, unique=False)
|
|
644
|
+
mappings = raw.mappings
|
|
645
|
+
proven = bool(raw.proven_optimal and mappings)
|
|
646
|
+
complete = bool(raw.enumeration_complete and proven)
|
|
647
|
+
reason = None if complete else "kernel_enumeration_incomplete"
|
|
648
|
+
else:
|
|
649
|
+
raw = solve_kernel_milp(kernel)
|
|
650
|
+
mappings = [
|
|
651
|
+
apply_kernel_solution(kernel, sub) for sub in raw.sub_mappings
|
|
652
|
+
]
|
|
653
|
+
proven = bool(raw.proven_optimal and mappings)
|
|
654
|
+
complete, reason = (
|
|
655
|
+
False,
|
|
656
|
+
("optimum_only" if proven else "optimum_unproven"),
|
|
657
|
+
)
|
|
658
|
+
distances = []
|
|
659
|
+
for mapping in mappings:
|
|
660
|
+
if sorted(mapping) != list(range(len(graphs[0].labels))) or any(
|
|
661
|
+
graphs[0].labels[i] != graphs[1].labels[j]
|
|
662
|
+
for i, j in enumerate(mapping)
|
|
663
|
+
):
|
|
664
|
+
raise RuntimeError(
|
|
665
|
+
f"method='{method}' returned an invalid atom bijection"
|
|
666
|
+
)
|
|
667
|
+
cost = chemical_distance(graphs, mapping, binary)
|
|
668
|
+
distances.append(cost)
|
|
669
|
+
if mapping_callback is not None:
|
|
670
|
+
mapping_callback(mapping, cost)
|
|
671
|
+
minimum = min(distances) if proven and distances else None
|
|
672
|
+
return _SearchOutcome(
|
|
673
|
+
mappings if collect_mappings else [],
|
|
674
|
+
distances if collect_mappings else [],
|
|
675
|
+
minimum,
|
|
676
|
+
proven,
|
|
677
|
+
complete,
|
|
678
|
+
reason,
|
|
679
|
+
method,
|
|
680
|
+
len(mappings),
|
|
681
|
+
raw,
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
__all__ = ["Mapper", "MappingResult"]
|