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,375 @@
|
|
|
1
|
+
"""Reference-free exact enumeration from binary bond-edit supports.
|
|
2
|
+
|
|
3
|
+
For the undirected binary bond-presence distance, every mapping at chemical distance
|
|
4
|
+
``C`` has a unique set of reactant-only edges and product-only edges. Removing
|
|
5
|
+
those edges leaves two colour-preserving isomorphic spanning graphs. This
|
|
6
|
+
module enumerates those edit supports before atom bijections and independently
|
|
7
|
+
rescales every completed isomorphism against the original endpoints.
|
|
8
|
+
|
|
9
|
+
The backend is intended for small-CD shells. Explicit support, mapping, and
|
|
10
|
+
wall-time limits return an incomplete result and never a false completeness
|
|
11
|
+
claim.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import itertools
|
|
17
|
+
import math
|
|
18
|
+
import time
|
|
19
|
+
from collections import Counter, defaultdict
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from numbers import Integral, Real
|
|
22
|
+
|
|
23
|
+
import networkx as nx
|
|
24
|
+
import numpy as np
|
|
25
|
+
|
|
26
|
+
from ..slap.lap import _adjacency_and_elements
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class BinaryEditBudget:
|
|
31
|
+
"""Exact broken/formed-edge budget implied by one binary CD shell."""
|
|
32
|
+
|
|
33
|
+
target: float | int
|
|
34
|
+
reactant_edge_count: int
|
|
35
|
+
product_edge_count: int
|
|
36
|
+
broken_edge_count: int | None
|
|
37
|
+
formed_edge_count: int | None
|
|
38
|
+
support_pair_count: int
|
|
39
|
+
feasible: bool
|
|
40
|
+
rejection_reason: str | None = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class BinaryEditSupportResult:
|
|
45
|
+
"""Complete labeled mappings from edit-support-first enumeration."""
|
|
46
|
+
|
|
47
|
+
target: float | int
|
|
48
|
+
mappings: list[list[int]]
|
|
49
|
+
complete: bool
|
|
50
|
+
truncation_reason: str | None
|
|
51
|
+
budget: BinaryEditBudget
|
|
52
|
+
support_pairs_visited: int
|
|
53
|
+
invariant_compatible_pairs: int
|
|
54
|
+
isomorphisms_visited: int
|
|
55
|
+
selected_mapping_count: int
|
|
56
|
+
elapsed_seconds: float
|
|
57
|
+
scope: str = "complete_binary_atom_compatible_cd_shell"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _validate_limit(value, name):
|
|
61
|
+
if value is not None and (
|
|
62
|
+
isinstance(value, bool) or not isinstance(value, Integral) or value < 1
|
|
63
|
+
):
|
|
64
|
+
raise ValueError(f"{name} must be a positive integer or None")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _binary_undirected_endpoints(lgp):
|
|
68
|
+
reactant, reactant_elements = _adjacency_and_elements(lgp[0], True)
|
|
69
|
+
product, product_elements = _adjacency_and_elements(lgp[1], True)
|
|
70
|
+
if reactant.shape != product.shape:
|
|
71
|
+
raise ValueError("reactant and product must have the same number of atoms")
|
|
72
|
+
if not np.array_equal(reactant, reactant.T) or not np.array_equal(
|
|
73
|
+
product, product.T
|
|
74
|
+
):
|
|
75
|
+
raise ValueError("edit-support enumeration requires undirected graphs")
|
|
76
|
+
if np.any(np.diag(reactant)) or np.any(np.diag(product)):
|
|
77
|
+
raise ValueError("edit-support enumeration requires loop-free graphs")
|
|
78
|
+
if Counter(reactant_elements) != Counter(product_elements):
|
|
79
|
+
raise ValueError("reactant and product atom-type multisets differ")
|
|
80
|
+
return reactant, product, reactant_elements, product_elements
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _edge_tuple(adjacency):
|
|
84
|
+
return tuple(
|
|
85
|
+
(left, right)
|
|
86
|
+
for left in range(adjacency.shape[0])
|
|
87
|
+
for right in range(left + 1, adjacency.shape[0])
|
|
88
|
+
if adjacency[left, right] != 0
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def binary_edit_budget(lgp, CD, *, tolerance: float = 1e-9) -> BinaryEditBudget:
|
|
93
|
+
"""Return the exact binary broken/formed-edge budget for ``CD``.
|
|
94
|
+
|
|
95
|
+
An infeasible numeric lattice value returns ``feasible=False`` rather than
|
|
96
|
+
raising. Structural input violations still raise because this backend is
|
|
97
|
+
defined only for balanced, undirected, loop-free endpoints after bond
|
|
98
|
+
orders are reduced to bond presence.
|
|
99
|
+
"""
|
|
100
|
+
if isinstance(CD, bool) or not isinstance(CD, Real):
|
|
101
|
+
raise TypeError("CD must be a non-negative number")
|
|
102
|
+
target_value = float(CD)
|
|
103
|
+
if not math.isfinite(target_value) or target_value < 0:
|
|
104
|
+
raise ValueError("CD must be finite and non-negative")
|
|
105
|
+
if tolerance < 0 or not math.isfinite(tolerance):
|
|
106
|
+
raise ValueError("tolerance must be finite and non-negative")
|
|
107
|
+
|
|
108
|
+
reactant, product, _, _ = _binary_undirected_endpoints(lgp)
|
|
109
|
+
reactant_edges = len(_edge_tuple(reactant))
|
|
110
|
+
product_edges = len(_edge_tuple(product))
|
|
111
|
+
rounded = round(target_value)
|
|
112
|
+
if not math.isclose(target_value, rounded, abs_tol=tolerance, rel_tol=0.0):
|
|
113
|
+
return BinaryEditBudget(
|
|
114
|
+
target=target_value,
|
|
115
|
+
reactant_edge_count=reactant_edges,
|
|
116
|
+
product_edge_count=product_edges,
|
|
117
|
+
broken_edge_count=None,
|
|
118
|
+
formed_edge_count=None,
|
|
119
|
+
support_pair_count=0,
|
|
120
|
+
feasible=False,
|
|
121
|
+
rejection_reason="binary chemical distance must be integral",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
target = int(rounded)
|
|
125
|
+
broken_numerator = target + reactant_edges - product_edges
|
|
126
|
+
formed_numerator = target - reactant_edges + product_edges
|
|
127
|
+
if broken_numerator % 2 or formed_numerator % 2:
|
|
128
|
+
return BinaryEditBudget(
|
|
129
|
+
target=target,
|
|
130
|
+
reactant_edge_count=reactant_edges,
|
|
131
|
+
product_edge_count=product_edges,
|
|
132
|
+
broken_edge_count=None,
|
|
133
|
+
formed_edge_count=None,
|
|
134
|
+
support_pair_count=0,
|
|
135
|
+
feasible=False,
|
|
136
|
+
rejection_reason="target violates the binary bond-count parity lattice",
|
|
137
|
+
)
|
|
138
|
+
broken = broken_numerator // 2
|
|
139
|
+
formed = formed_numerator // 2
|
|
140
|
+
if broken < 0 or formed < 0 or broken > reactant_edges or formed > product_edges:
|
|
141
|
+
return BinaryEditBudget(
|
|
142
|
+
target=target,
|
|
143
|
+
reactant_edge_count=reactant_edges,
|
|
144
|
+
product_edge_count=product_edges,
|
|
145
|
+
broken_edge_count=broken,
|
|
146
|
+
formed_edge_count=formed,
|
|
147
|
+
support_pair_count=0,
|
|
148
|
+
feasible=False,
|
|
149
|
+
rejection_reason="target implies an impossible broken/formed-edge budget",
|
|
150
|
+
)
|
|
151
|
+
support_pairs = math.comb(reactant_edges, broken) * math.comb(product_edges, formed)
|
|
152
|
+
return BinaryEditBudget(
|
|
153
|
+
target=target,
|
|
154
|
+
reactant_edge_count=reactant_edges,
|
|
155
|
+
product_edge_count=product_edges,
|
|
156
|
+
broken_edge_count=broken,
|
|
157
|
+
formed_edge_count=formed,
|
|
158
|
+
support_pair_count=support_pairs,
|
|
159
|
+
feasible=True,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _typed_label(value):
|
|
164
|
+
return f"{type(value).__module__}.{type(value).__qualname__}:{value!r}"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _endpoint_graph(adjacency, elements):
|
|
168
|
+
graph = nx.Graph()
|
|
169
|
+
graph.add_nodes_from(
|
|
170
|
+
(atom, {"element": _typed_label(element)})
|
|
171
|
+
for atom, element in enumerate(elements)
|
|
172
|
+
)
|
|
173
|
+
graph.add_edges_from(_edge_tuple(adjacency))
|
|
174
|
+
return graph
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _residual_graph(endpoint, deleted_edges):
|
|
178
|
+
residual = endpoint.copy()
|
|
179
|
+
residual.remove_edges_from(deleted_edges)
|
|
180
|
+
return residual
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _residual_invariant(graph):
|
|
184
|
+
"""Return an isomorphism-invariant, collision-tolerant bucket key."""
|
|
185
|
+
components = []
|
|
186
|
+
for nodes in nx.connected_components(graph):
|
|
187
|
+
subgraph = graph.subgraph(nodes)
|
|
188
|
+
labels = Counter(subgraph.nodes[node]["element"] for node in nodes)
|
|
189
|
+
degree_labels = Counter(
|
|
190
|
+
(subgraph.nodes[node]["element"], subgraph.degree[node]) for node in nodes
|
|
191
|
+
)
|
|
192
|
+
components.append(
|
|
193
|
+
(
|
|
194
|
+
len(nodes),
|
|
195
|
+
subgraph.number_of_edges(),
|
|
196
|
+
tuple(sorted(labels.items())),
|
|
197
|
+
tuple(sorted(degree_labels.items())),
|
|
198
|
+
)
|
|
199
|
+
)
|
|
200
|
+
return tuple(sorted(components))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _mapping_cost(reactant, product, mapping):
|
|
204
|
+
images = np.asarray(mapping, dtype=int)
|
|
205
|
+
mapped_product = product[images[:, None], images[None, :]]
|
|
206
|
+
return 0.5 * float(np.abs(reactant - mapped_product).sum())
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def enumerate_binary_edit_support_mappings( # noqa: C901
|
|
210
|
+
lgp,
|
|
211
|
+
CD,
|
|
212
|
+
*,
|
|
213
|
+
tolerance: float = 1e-9,
|
|
214
|
+
max_support_pairs: int | None = 100_000,
|
|
215
|
+
max_mappings: int | None = 100_000,
|
|
216
|
+
time_limit_seconds: float | None = None,
|
|
217
|
+
collect_mappings: bool = True,
|
|
218
|
+
mapping_callback=None,
|
|
219
|
+
) -> BinaryEditSupportResult:
|
|
220
|
+
"""Enumerate the complete global binary shell at a supplied numeric CD.
|
|
221
|
+
|
|
222
|
+
The default support and mapping caps protect interactive use. A cap never
|
|
223
|
+
changes the mathematical shell: reaching one returns ``complete=False``.
|
|
224
|
+
For exact counting with bounded output memory, use
|
|
225
|
+
``collect_mappings=False, max_mappings=None`` and optionally a callback.
|
|
226
|
+
The wall-time check is cooperative at support and yielded-isomorphism
|
|
227
|
+
boundaries; use an external process limit when a hard deadline is needed.
|
|
228
|
+
"""
|
|
229
|
+
started = time.perf_counter()
|
|
230
|
+
_validate_limit(max_support_pairs, "max_support_pairs")
|
|
231
|
+
_validate_limit(max_mappings, "max_mappings")
|
|
232
|
+
if time_limit_seconds is not None and (
|
|
233
|
+
isinstance(time_limit_seconds, bool)
|
|
234
|
+
or not isinstance(time_limit_seconds, Real)
|
|
235
|
+
or not math.isfinite(float(time_limit_seconds))
|
|
236
|
+
or time_limit_seconds < 0
|
|
237
|
+
):
|
|
238
|
+
raise ValueError("time_limit_seconds must be finite and non-negative")
|
|
239
|
+
if not isinstance(collect_mappings, bool):
|
|
240
|
+
raise TypeError("collect_mappings must be boolean")
|
|
241
|
+
if mapping_callback is not None and not callable(mapping_callback):
|
|
242
|
+
raise TypeError("mapping_callback must be callable or None")
|
|
243
|
+
|
|
244
|
+
reactant, product, reactant_elements, product_elements = (
|
|
245
|
+
_binary_undirected_endpoints(lgp)
|
|
246
|
+
)
|
|
247
|
+
budget = binary_edit_budget(lgp, CD, tolerance=tolerance)
|
|
248
|
+
if not budget.feasible:
|
|
249
|
+
return BinaryEditSupportResult(
|
|
250
|
+
target=budget.target,
|
|
251
|
+
mappings=[],
|
|
252
|
+
complete=True,
|
|
253
|
+
truncation_reason=None,
|
|
254
|
+
budget=budget,
|
|
255
|
+
support_pairs_visited=0,
|
|
256
|
+
invariant_compatible_pairs=0,
|
|
257
|
+
isomorphisms_visited=0,
|
|
258
|
+
selected_mapping_count=0,
|
|
259
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
260
|
+
)
|
|
261
|
+
if max_support_pairs is not None and budget.support_pair_count > max_support_pairs:
|
|
262
|
+
return BinaryEditSupportResult(
|
|
263
|
+
target=budget.target,
|
|
264
|
+
mappings=[],
|
|
265
|
+
complete=False,
|
|
266
|
+
truncation_reason="support_pair_limit",
|
|
267
|
+
budget=budget,
|
|
268
|
+
support_pairs_visited=0,
|
|
269
|
+
invariant_compatible_pairs=0,
|
|
270
|
+
isomorphisms_visited=0,
|
|
271
|
+
selected_mapping_count=0,
|
|
272
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
deadline = (
|
|
276
|
+
None if time_limit_seconds is None else started + float(time_limit_seconds)
|
|
277
|
+
)
|
|
278
|
+
reactant_edges = _edge_tuple(reactant)
|
|
279
|
+
product_edges = _edge_tuple(product)
|
|
280
|
+
reactant_graph = _endpoint_graph(reactant, reactant_elements)
|
|
281
|
+
product_graph = _endpoint_graph(product, product_elements)
|
|
282
|
+
product_variants = defaultdict(list)
|
|
283
|
+
for deleted in itertools.combinations(product_edges, budget.formed_edge_count):
|
|
284
|
+
if deadline is not None and time.perf_counter() >= deadline:
|
|
285
|
+
return BinaryEditSupportResult(
|
|
286
|
+
target=budget.target,
|
|
287
|
+
mappings=[],
|
|
288
|
+
complete=False,
|
|
289
|
+
truncation_reason="time_limit",
|
|
290
|
+
budget=budget,
|
|
291
|
+
support_pairs_visited=0,
|
|
292
|
+
invariant_compatible_pairs=0,
|
|
293
|
+
isomorphisms_visited=0,
|
|
294
|
+
selected_mapping_count=0,
|
|
295
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
296
|
+
)
|
|
297
|
+
residual = _residual_graph(product_graph, deleted)
|
|
298
|
+
product_variants[_residual_invariant(residual)].append(deleted)
|
|
299
|
+
|
|
300
|
+
node_match = nx.algorithms.isomorphism.categorical_node_match("element", None)
|
|
301
|
+
mappings = []
|
|
302
|
+
support_pairs_visited = 0
|
|
303
|
+
compatible_pairs = 0
|
|
304
|
+
isomorphisms_visited = 0
|
|
305
|
+
selected_mapping_count = 0
|
|
306
|
+
truncation_reason = None
|
|
307
|
+
|
|
308
|
+
for reactant_deleted in itertools.combinations(
|
|
309
|
+
reactant_edges, budget.broken_edge_count
|
|
310
|
+
):
|
|
311
|
+
if deadline is not None and time.perf_counter() >= deadline:
|
|
312
|
+
truncation_reason = "time_limit"
|
|
313
|
+
break
|
|
314
|
+
reactant_residual = _residual_graph(reactant_graph, reactant_deleted)
|
|
315
|
+
key = _residual_invariant(reactant_residual)
|
|
316
|
+
candidates = product_variants.get(key, ())
|
|
317
|
+
support_pairs_visited += math.comb(len(product_edges), budget.formed_edge_count)
|
|
318
|
+
for product_deleted in candidates:
|
|
319
|
+
if deadline is not None and time.perf_counter() >= deadline:
|
|
320
|
+
truncation_reason = "time_limit"
|
|
321
|
+
break
|
|
322
|
+
compatible_pairs += 1
|
|
323
|
+
product_residual = _residual_graph(product_graph, product_deleted)
|
|
324
|
+
matcher = nx.algorithms.isomorphism.GraphMatcher(
|
|
325
|
+
reactant_residual,
|
|
326
|
+
product_residual,
|
|
327
|
+
node_match=node_match,
|
|
328
|
+
)
|
|
329
|
+
for isomorphism in matcher.isomorphisms_iter():
|
|
330
|
+
if deadline is not None and time.perf_counter() >= deadline:
|
|
331
|
+
truncation_reason = "time_limit"
|
|
332
|
+
break
|
|
333
|
+
isomorphisms_visited += 1
|
|
334
|
+
mapping = [int(isomorphism[atom]) for atom in range(reactant.shape[0])]
|
|
335
|
+
cost = _mapping_cost(reactant, product, mapping)
|
|
336
|
+
if not math.isclose(
|
|
337
|
+
cost,
|
|
338
|
+
budget.target,
|
|
339
|
+
abs_tol=tolerance,
|
|
340
|
+
rel_tol=0.0,
|
|
341
|
+
):
|
|
342
|
+
continue
|
|
343
|
+
selected_mapping_count += 1
|
|
344
|
+
if collect_mappings:
|
|
345
|
+
mappings.append(mapping)
|
|
346
|
+
if mapping_callback is not None:
|
|
347
|
+
mapping_callback(mapping, cost)
|
|
348
|
+
if max_mappings is not None and selected_mapping_count >= max_mappings:
|
|
349
|
+
truncation_reason = "mapping_limit"
|
|
350
|
+
break
|
|
351
|
+
if truncation_reason is not None:
|
|
352
|
+
break
|
|
353
|
+
if truncation_reason is not None:
|
|
354
|
+
break
|
|
355
|
+
|
|
356
|
+
return BinaryEditSupportResult(
|
|
357
|
+
target=budget.target,
|
|
358
|
+
mappings=mappings,
|
|
359
|
+
complete=truncation_reason is None,
|
|
360
|
+
truncation_reason=truncation_reason,
|
|
361
|
+
budget=budget,
|
|
362
|
+
support_pairs_visited=support_pairs_visited,
|
|
363
|
+
invariant_compatible_pairs=compatible_pairs,
|
|
364
|
+
isomorphisms_visited=isomorphisms_visited,
|
|
365
|
+
selected_mapping_count=selected_mapping_count,
|
|
366
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
__all__ = [
|
|
371
|
+
"BinaryEditBudget",
|
|
372
|
+
"BinaryEditSupportResult",
|
|
373
|
+
"binary_edit_budget",
|
|
374
|
+
"enumerate_binary_edit_support_mappings",
|
|
375
|
+
]
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""Choose an exact solver for a distance shell and record the selection."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from collections import Counter
|
|
7
|
+
from dataclasses import asdict, dataclass
|
|
8
|
+
from numbers import Integral
|
|
9
|
+
from typing import Literal
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from ..slap.lap import _adjacency_and_elements
|
|
14
|
+
from .distance_search.search import enumerate_distance_mappings, normalize_distance_target
|
|
15
|
+
from .distance_search.records import DistanceEnumerationResult
|
|
16
|
+
from .edit_support import (
|
|
17
|
+
BinaryEditBudget,
|
|
18
|
+
binary_edit_budget,
|
|
19
|
+
enumerate_binary_edit_support_mappings,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
HybridBackend = Literal["auto", "assignment", "edit_support"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True)
|
|
26
|
+
class HybridBackendDecision:
|
|
27
|
+
"""Machine-readable explanation of one exact backend choice."""
|
|
28
|
+
|
|
29
|
+
requested_backend: HybridBackend
|
|
30
|
+
selected_backend: str
|
|
31
|
+
selection_reason: str
|
|
32
|
+
edit_support_pair_count: int | None
|
|
33
|
+
edit_support_pair_limit: int | None
|
|
34
|
+
output_scope: str
|
|
35
|
+
|
|
36
|
+
def as_dict(self) -> dict[str, object]:
|
|
37
|
+
return asdict(self)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _total_bijections(lgp, binary):
|
|
41
|
+
reactant, reactant_elements = _adjacency_and_elements(lgp[0], binary)
|
|
42
|
+
product, product_elements = _adjacency_and_elements(lgp[1], binary)
|
|
43
|
+
if reactant.shape != product.shape:
|
|
44
|
+
raise ValueError("reactant and product must have the same number of atoms")
|
|
45
|
+
reactant_counts = Counter(reactant_elements)
|
|
46
|
+
if reactant_counts != Counter(product_elements):
|
|
47
|
+
raise ValueError("reactant and product atom-type multisets differ")
|
|
48
|
+
total = math.prod(math.factorial(count) for count in reactant_counts.values())
|
|
49
|
+
maximum = 0.5 * float(np.abs(reactant).sum() + np.abs(product).sum())
|
|
50
|
+
return total, maximum
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _edit_ineligibility(target, binary, options):
|
|
54
|
+
if target == "minimal":
|
|
55
|
+
return "edit-support backend requires a numeric shell"
|
|
56
|
+
if not binary:
|
|
57
|
+
return "edit-support backend requires binary bond presence"
|
|
58
|
+
if options.get("certify", False):
|
|
59
|
+
return "edit-support backend does not emit prefix certificates"
|
|
60
|
+
if options.get("symmetry_pruning", False):
|
|
61
|
+
return "edit-support backend currently returns labeled mappings only"
|
|
62
|
+
if options.get("expand_symmetry", False):
|
|
63
|
+
return "edit-support backend does not use symmetry expansion"
|
|
64
|
+
if options.get("fixed_mapping"):
|
|
65
|
+
return "edit-support backend does not support fixed assignments"
|
|
66
|
+
if options.get("compute_minimum_cost", False):
|
|
67
|
+
return "edit-support backend does not run the optimization pass"
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def enumerate_hybrid_distance_mappings(
|
|
72
|
+
lgp,
|
|
73
|
+
*,
|
|
74
|
+
CD="minimal",
|
|
75
|
+
binary=True,
|
|
76
|
+
backend: HybridBackend = "auto",
|
|
77
|
+
max_edit_support_pairs: int | None = 50_000,
|
|
78
|
+
max_bijections: int | None = 1_000_000,
|
|
79
|
+
tolerance: float = 1e-9,
|
|
80
|
+
time_limit_seconds: float | None = None,
|
|
81
|
+
max_mappings: int | None = None,
|
|
82
|
+
collect_mappings: bool = True,
|
|
83
|
+
mapping_callback=None,
|
|
84
|
+
compute_minimum_cost: bool = False,
|
|
85
|
+
**assignment_options,
|
|
86
|
+
) -> DistanceEnumerationResult:
|
|
87
|
+
"""Select an exact backend while preserving the requested output scope.
|
|
88
|
+
|
|
89
|
+
The edit-support route is selected only for a numeric, binary, labeled
|
|
90
|
+
shell without fixed assignments or certificate requests. Otherwise the
|
|
91
|
+
complete assignment branch-and-bound implementation is used. Every result
|
|
92
|
+
records the backend and selection evidence; automatic selection never
|
|
93
|
+
substitutes a quotient shell for a labeled shell.
|
|
94
|
+
"""
|
|
95
|
+
if backend not in {"auto", "assignment", "edit_support"}:
|
|
96
|
+
raise ValueError("backend must be 'auto', 'assignment', or 'edit_support'")
|
|
97
|
+
if max_edit_support_pairs is not None and (
|
|
98
|
+
isinstance(max_edit_support_pairs, bool)
|
|
99
|
+
or not isinstance(max_edit_support_pairs, Integral)
|
|
100
|
+
or max_edit_support_pairs < 1
|
|
101
|
+
):
|
|
102
|
+
raise ValueError("max_edit_support_pairs must be positive or None")
|
|
103
|
+
|
|
104
|
+
target = normalize_distance_target(CD)
|
|
105
|
+
options = dict(assignment_options)
|
|
106
|
+
options["compute_minimum_cost"] = compute_minimum_cost
|
|
107
|
+
reason = _edit_ineligibility(target, binary, options)
|
|
108
|
+
budget: BinaryEditBudget | None = None
|
|
109
|
+
if reason is None:
|
|
110
|
+
try:
|
|
111
|
+
budget = binary_edit_budget(lgp, target, tolerance=tolerance)
|
|
112
|
+
except ValueError as error:
|
|
113
|
+
reason = f"edit-support structural precondition failed: {error}"
|
|
114
|
+
if (
|
|
115
|
+
reason is None
|
|
116
|
+
and budget is not None
|
|
117
|
+
and max_edit_support_pairs is not None
|
|
118
|
+
and budget.support_pair_count > max_edit_support_pairs
|
|
119
|
+
):
|
|
120
|
+
reason = (
|
|
121
|
+
f"estimated support pairs {budget.support_pair_count} exceed "
|
|
122
|
+
f"selector limit {max_edit_support_pairs}"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
select_edit = backend == "edit_support" or (backend == "auto" and reason is None)
|
|
126
|
+
if backend == "edit_support" and reason is not None:
|
|
127
|
+
raise ValueError(reason)
|
|
128
|
+
if backend == "assignment":
|
|
129
|
+
reason = "assignment backend explicitly requested"
|
|
130
|
+
select_edit = False
|
|
131
|
+
|
|
132
|
+
if not select_edit:
|
|
133
|
+
decision = HybridBackendDecision(
|
|
134
|
+
requested_backend=backend,
|
|
135
|
+
selected_backend="assignment_branch_and_bound",
|
|
136
|
+
selection_reason=reason or "assignment backend selected",
|
|
137
|
+
edit_support_pair_count=(
|
|
138
|
+
None if budget is None else budget.support_pair_count
|
|
139
|
+
),
|
|
140
|
+
edit_support_pair_limit=max_edit_support_pairs,
|
|
141
|
+
output_scope="complete_atom_compatible_assignment_space",
|
|
142
|
+
)
|
|
143
|
+
result = enumerate_distance_mappings(
|
|
144
|
+
lgp,
|
|
145
|
+
CD=target,
|
|
146
|
+
binary=binary,
|
|
147
|
+
max_bijections=max_bijections,
|
|
148
|
+
tolerance=tolerance,
|
|
149
|
+
time_limit_seconds=time_limit_seconds,
|
|
150
|
+
max_mappings=max_mappings,
|
|
151
|
+
collect_mappings=collect_mappings,
|
|
152
|
+
mapping_callback=mapping_callback,
|
|
153
|
+
compute_minimum_cost=compute_minimum_cost,
|
|
154
|
+
**assignment_options,
|
|
155
|
+
)
|
|
156
|
+
result.backend = decision.selected_backend
|
|
157
|
+
result.backend_statistics = {
|
|
158
|
+
**(result.backend_statistics or {}),
|
|
159
|
+
"selector": decision.as_dict(),
|
|
160
|
+
}
|
|
161
|
+
return result
|
|
162
|
+
|
|
163
|
+
decision = HybridBackendDecision(
|
|
164
|
+
requested_backend=backend,
|
|
165
|
+
selected_backend="binary_edit_support",
|
|
166
|
+
selection_reason=(
|
|
167
|
+
"numeric binary support estimate is within the selector limit"
|
|
168
|
+
),
|
|
169
|
+
edit_support_pair_count=budget.support_pair_count,
|
|
170
|
+
edit_support_pair_limit=max_edit_support_pairs,
|
|
171
|
+
output_scope="complete_binary_atom_compatible_cd_shell",
|
|
172
|
+
)
|
|
173
|
+
edit_result = enumerate_binary_edit_support_mappings(
|
|
174
|
+
lgp,
|
|
175
|
+
target,
|
|
176
|
+
tolerance=tolerance,
|
|
177
|
+
max_support_pairs=max_edit_support_pairs,
|
|
178
|
+
max_mappings=max_mappings,
|
|
179
|
+
time_limit_seconds=time_limit_seconds,
|
|
180
|
+
collect_mappings=collect_mappings,
|
|
181
|
+
mapping_callback=mapping_callback,
|
|
182
|
+
)
|
|
183
|
+
total_bijections, maximum_cost = _total_bijections(lgp, True)
|
|
184
|
+
selected_cost = float(target) if edit_result.selected_mapping_count else None
|
|
185
|
+
status = (
|
|
186
|
+
"timeout"
|
|
187
|
+
if not edit_result.complete
|
|
188
|
+
else ("complete" if edit_result.selected_mapping_count else "no_solutions")
|
|
189
|
+
)
|
|
190
|
+
return DistanceEnumerationResult(
|
|
191
|
+
target=target,
|
|
192
|
+
cost=selected_cost,
|
|
193
|
+
minimum_cost=None,
|
|
194
|
+
mappings=edit_result.mappings,
|
|
195
|
+
distances=[float(target)] * len(edit_result.mappings),
|
|
196
|
+
total_bijections=total_bijections,
|
|
197
|
+
maximum_cost_upper_bound=maximum_cost,
|
|
198
|
+
visited_leaves=edit_result.isomorphisms_visited,
|
|
199
|
+
pruned_branches=(
|
|
200
|
+
edit_result.support_pairs_visited - edit_result.invariant_compatible_pairs
|
|
201
|
+
),
|
|
202
|
+
elapsed_seconds=edit_result.elapsed_seconds,
|
|
203
|
+
status=status,
|
|
204
|
+
complete=edit_result.complete,
|
|
205
|
+
truncation_reason=edit_result.truncation_reason,
|
|
206
|
+
scope=edit_result.scope,
|
|
207
|
+
visited_nodes=edit_result.support_pairs_visited,
|
|
208
|
+
selected_mapping_count=edit_result.selected_mapping_count,
|
|
209
|
+
selected_labeled_mapping_count=edit_result.selected_mapping_count,
|
|
210
|
+
backend=decision.selected_backend,
|
|
211
|
+
backend_statistics={
|
|
212
|
+
"selector": decision.as_dict(),
|
|
213
|
+
"support_pairs_visited": edit_result.support_pairs_visited,
|
|
214
|
+
"invariant_compatible_pairs": (edit_result.invariant_compatible_pairs),
|
|
215
|
+
"isomorphisms_visited": edit_result.isomorphisms_visited,
|
|
216
|
+
},
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
__all__ = [
|
|
221
|
+
"HybridBackend",
|
|
222
|
+
"HybridBackendDecision",
|
|
223
|
+
"enumerate_hybrid_distance_mappings",
|
|
224
|
+
]
|