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,679 @@
|
|
|
1
|
+
"""Python exact graph-assignment search with propagation and assignment bounds.
|
|
2
|
+
|
|
3
|
+
This is the Python implementation selected by the PABS (Propagation and
|
|
4
|
+
Assignment-Bounded Search) interface. It maintains reversible atom-assignment
|
|
5
|
+
domains, enforces one-to-one matching, and prunes using assignment lower bounds.
|
|
6
|
+
It searches the full compatible assignment space under any explicitly supplied
|
|
7
|
+
fixed assignments; it does not extract a SLAP uncertainty kernel. Inputs outside
|
|
8
|
+
its arithmetic domain use ``enumerate_distance_mappings`` with a recorded
|
|
9
|
+
fallback. Both routes preserve the requested chemical-distance objective.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import math
|
|
15
|
+
import time
|
|
16
|
+
from collections import Counter
|
|
17
|
+
from dataclasses import dataclass, replace
|
|
18
|
+
from numbers import Integral, Real
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
|
|
22
|
+
from ....graph.automorphism import bounded_automorphism_permutations
|
|
23
|
+
from ...slap.lap import _adjacency_and_elements
|
|
24
|
+
from ..distance_search.search import enumerate_distance_mappings
|
|
25
|
+
from ..distance_search.records import (
|
|
26
|
+
DistanceEnumerationResult,
|
|
27
|
+
ExactEnumerationLimitError,
|
|
28
|
+
normalize_distance_target,
|
|
29
|
+
)
|
|
30
|
+
from .propagation_search import PropagatedSearch
|
|
31
|
+
from .propagation_symmetry import bounded_generated_subgroup
|
|
32
|
+
from .propagation_limits import PropagationDeadline, check_deadline
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class PropagationConfig:
|
|
37
|
+
"""Controls for Python exact propagation, assignment bounds, and residual spectra."""
|
|
38
|
+
|
|
39
|
+
domain_propagation: bool = True
|
|
40
|
+
adaptive_bounds: bool = True
|
|
41
|
+
incremental_assignments: bool = True
|
|
42
|
+
cache_propagation: bool = True
|
|
43
|
+
block_assignments: bool = True
|
|
44
|
+
typed_mass_bounds: bool = True
|
|
45
|
+
typed_transport_bounds: bool = True
|
|
46
|
+
batch_forced_assignments: bool = True
|
|
47
|
+
cost_lattice_pruning: bool = True
|
|
48
|
+
# These incumbent/star experiments are optional: the paired 100-case
|
|
49
|
+
# histogram+batch run showed better end-to-end performance without them.
|
|
50
|
+
seed_local_search: bool = False
|
|
51
|
+
seed_improvement_seconds: float = 0.05
|
|
52
|
+
star_assignment_bounds: bool = False
|
|
53
|
+
star_bound_residual_limit: int = 16
|
|
54
|
+
star_bound_max_anchors: int = 32
|
|
55
|
+
star_bound_seconds: float = 0.25
|
|
56
|
+
pairwise_edge_bounds: bool = False
|
|
57
|
+
pairwise_bound_residual_limit: int = 12
|
|
58
|
+
pairwise_bound_max_anchors: int = 16
|
|
59
|
+
pairwise_bound_seconds: float = 0.1
|
|
60
|
+
column_cost_bounds: bool = True
|
|
61
|
+
cycle_cost_bounds: bool = True
|
|
62
|
+
# Experimental SR-GED style exact residual bound. It is opt-in until the
|
|
63
|
+
# cohort benchmark demonstrates an end-to-end win.
|
|
64
|
+
separator_bounds: bool = False
|
|
65
|
+
separator_spectrum: bool = False
|
|
66
|
+
separator_residual_limit: int = 10
|
|
67
|
+
separator_max_size: int = 2
|
|
68
|
+
separator_max_states: int = 20_000
|
|
69
|
+
separator_spectrum_max_calls: int = 16
|
|
70
|
+
# Factor-wise bitset support is a cheaper but weaker residual CD test.
|
|
71
|
+
factor_spectrum_bounds: bool = False
|
|
72
|
+
factor_spectrum_residual_limit: int = 10
|
|
73
|
+
factor_spectrum_max_range: int = 4096
|
|
74
|
+
factor_spectrum_max_calls: int = 16
|
|
75
|
+
# Exact fixed-order suffix-state merging for small selected-CD residuals.
|
|
76
|
+
suffix_spectrum: bool = False
|
|
77
|
+
suffix_spectrum_orbit_pruning: bool = False
|
|
78
|
+
suffix_spectrum_representation: str = "cost_table"
|
|
79
|
+
suffix_spectrum_max_reward: int = 4096
|
|
80
|
+
suffix_spectrum_residual_limit: int = 10
|
|
81
|
+
suffix_spectrum_max_states: int = 20_000
|
|
82
|
+
suffix_spectrum_max_cost: int = 4096
|
|
83
|
+
suffix_spectrum_max_calls: int = 2
|
|
84
|
+
suffix_spectrum_max_seconds_per_call: float = 0.002
|
|
85
|
+
branch_order: str = "default"
|
|
86
|
+
small_residual: int = 48
|
|
87
|
+
bound_interval: int = 4
|
|
88
|
+
bound_slack: int = 16
|
|
89
|
+
|
|
90
|
+
def __post_init__(self):
|
|
91
|
+
for name in (
|
|
92
|
+
"domain_propagation",
|
|
93
|
+
"adaptive_bounds",
|
|
94
|
+
"incremental_assignments",
|
|
95
|
+
"cache_propagation",
|
|
96
|
+
"block_assignments",
|
|
97
|
+
"typed_mass_bounds",
|
|
98
|
+
"typed_transport_bounds",
|
|
99
|
+
"batch_forced_assignments",
|
|
100
|
+
"cost_lattice_pruning",
|
|
101
|
+
"seed_local_search",
|
|
102
|
+
"star_assignment_bounds",
|
|
103
|
+
"column_cost_bounds",
|
|
104
|
+
"cycle_cost_bounds",
|
|
105
|
+
"separator_bounds",
|
|
106
|
+
"separator_spectrum",
|
|
107
|
+
"factor_spectrum_bounds",
|
|
108
|
+
"suffix_spectrum",
|
|
109
|
+
"suffix_spectrum_orbit_pruning",
|
|
110
|
+
):
|
|
111
|
+
if not isinstance(getattr(self, name), bool):
|
|
112
|
+
raise TypeError(f"{name} must be Boolean")
|
|
113
|
+
for name in (
|
|
114
|
+
"small_residual",
|
|
115
|
+
"bound_interval",
|
|
116
|
+
"bound_slack",
|
|
117
|
+
"star_bound_residual_limit",
|
|
118
|
+
"star_bound_max_anchors",
|
|
119
|
+
"pairwise_bound_residual_limit",
|
|
120
|
+
"pairwise_bound_max_anchors",
|
|
121
|
+
"separator_residual_limit",
|
|
122
|
+
"separator_max_size",
|
|
123
|
+
"separator_max_states",
|
|
124
|
+
"separator_spectrum_max_calls",
|
|
125
|
+
"factor_spectrum_residual_limit",
|
|
126
|
+
"factor_spectrum_max_range",
|
|
127
|
+
"factor_spectrum_max_calls",
|
|
128
|
+
"suffix_spectrum_residual_limit",
|
|
129
|
+
"suffix_spectrum_max_states",
|
|
130
|
+
"suffix_spectrum_max_cost",
|
|
131
|
+
"suffix_spectrum_max_reward",
|
|
132
|
+
"suffix_spectrum_max_calls",
|
|
133
|
+
):
|
|
134
|
+
value = getattr(self, name)
|
|
135
|
+
if isinstance(value, bool) or not isinstance(value, Integral) or value < 1:
|
|
136
|
+
raise ValueError(f"{name} must be a positive integer")
|
|
137
|
+
if not isinstance(
|
|
138
|
+
self.suffix_spectrum_representation, str
|
|
139
|
+
) or self.suffix_spectrum_representation not in {
|
|
140
|
+
"cost_table",
|
|
141
|
+
"reward_frontier",
|
|
142
|
+
}:
|
|
143
|
+
raise ValueError(
|
|
144
|
+
"suffix_spectrum_representation must be cost_table or reward_frontier"
|
|
145
|
+
)
|
|
146
|
+
suffix_seconds = self.suffix_spectrum_max_seconds_per_call
|
|
147
|
+
if (
|
|
148
|
+
isinstance(suffix_seconds, bool)
|
|
149
|
+
or not isinstance(suffix_seconds, Real)
|
|
150
|
+
or not math.isfinite(suffix_seconds)
|
|
151
|
+
or suffix_seconds <= 0
|
|
152
|
+
or suffix_seconds > 0.1
|
|
153
|
+
):
|
|
154
|
+
raise ValueError(
|
|
155
|
+
"suffix_spectrum_max_seconds_per_call must be finite and in (0, 0.1]"
|
|
156
|
+
)
|
|
157
|
+
star_seconds = self.star_bound_seconds
|
|
158
|
+
if (
|
|
159
|
+
isinstance(star_seconds, bool)
|
|
160
|
+
or not isinstance(star_seconds, Real)
|
|
161
|
+
or not math.isfinite(star_seconds)
|
|
162
|
+
or star_seconds < 0
|
|
163
|
+
or star_seconds > 0.5
|
|
164
|
+
):
|
|
165
|
+
raise ValueError("star_bound_seconds must be finite and in [0, 0.5]")
|
|
166
|
+
seconds = self.seed_improvement_seconds
|
|
167
|
+
if (
|
|
168
|
+
isinstance(seconds, bool)
|
|
169
|
+
or not isinstance(seconds, Real)
|
|
170
|
+
or not math.isfinite(seconds)
|
|
171
|
+
or seconds < 0
|
|
172
|
+
or seconds > 0.1
|
|
173
|
+
):
|
|
174
|
+
raise ValueError("seed_improvement_seconds must be finite and in [0, 0.1]")
|
|
175
|
+
if not isinstance(self.branch_order, str) or self.branch_order not in {
|
|
176
|
+
"default",
|
|
177
|
+
"pagerank",
|
|
178
|
+
"impact",
|
|
179
|
+
"contention",
|
|
180
|
+
}:
|
|
181
|
+
raise ValueError(
|
|
182
|
+
"branch_order must be 'default', 'pagerank', 'impact', or 'contention'"
|
|
183
|
+
)
|
|
184
|
+
pairwise_seconds = self.pairwise_bound_seconds
|
|
185
|
+
if (
|
|
186
|
+
isinstance(pairwise_seconds, bool)
|
|
187
|
+
or not isinstance(pairwise_seconds, Real)
|
|
188
|
+
or not math.isfinite(pairwise_seconds)
|
|
189
|
+
or pairwise_seconds < 0
|
|
190
|
+
or pairwise_seconds > 0.5
|
|
191
|
+
):
|
|
192
|
+
raise ValueError("pairwise_bound_seconds must be finite and in [0, 0.5]")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _validate_options(tolerance, seconds, caps, flags, callback, config):
|
|
196
|
+
if (
|
|
197
|
+
isinstance(tolerance, bool)
|
|
198
|
+
or not isinstance(tolerance, Real)
|
|
199
|
+
or not math.isfinite(tolerance)
|
|
200
|
+
or tolerance < 0
|
|
201
|
+
):
|
|
202
|
+
raise ValueError("tolerance must be finite and nonnegative")
|
|
203
|
+
if seconds is not None and (
|
|
204
|
+
isinstance(seconds, bool)
|
|
205
|
+
or not isinstance(seconds, Real)
|
|
206
|
+
or not math.isfinite(seconds)
|
|
207
|
+
or seconds < 0
|
|
208
|
+
):
|
|
209
|
+
raise ValueError("time_limit_seconds must be finite and nonnegative")
|
|
210
|
+
for name, value in caps.items():
|
|
211
|
+
if value is not None and (
|
|
212
|
+
isinstance(value, bool) or not isinstance(value, Integral) or value < 1
|
|
213
|
+
):
|
|
214
|
+
raise ValueError(f"{name} must be a positive integer or None")
|
|
215
|
+
for name, value in flags.items():
|
|
216
|
+
if not isinstance(value, bool):
|
|
217
|
+
raise TypeError(f"{name} must be Boolean")
|
|
218
|
+
if callback is not None and not callable(callback):
|
|
219
|
+
raise TypeError("mapping_callback must be callable or None")
|
|
220
|
+
if not isinstance(config, PropagationConfig):
|
|
221
|
+
raise TypeError("config must be a PropagationConfig")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _fixed_and_seed(labels, product_labels, fixed_mapping, initial_mapping):
|
|
225
|
+
n = len(labels)
|
|
226
|
+
if fixed_mapping is not None and not hasattr(fixed_mapping, "items"):
|
|
227
|
+
raise TypeError("fixed_mapping must be a mapping or None")
|
|
228
|
+
fixed = dict(fixed_mapping or {})
|
|
229
|
+
if any(
|
|
230
|
+
isinstance(x, bool) or not isinstance(x, Integral)
|
|
231
|
+
for pair in fixed.items()
|
|
232
|
+
for x in pair
|
|
233
|
+
):
|
|
234
|
+
raise TypeError("fixed_mapping indices must be integers")
|
|
235
|
+
if any(not 0 <= i < n or not 0 <= j < n for i, j in fixed.items()):
|
|
236
|
+
raise ValueError("fixed_mapping index out of range")
|
|
237
|
+
if len(set(fixed.values())) != len(fixed) or any(
|
|
238
|
+
labels[i] != product_labels[j] for i, j in fixed.items()
|
|
239
|
+
):
|
|
240
|
+
raise ValueError("fixed_mapping must be injective and atom-compatible")
|
|
241
|
+
if initial_mapping is None:
|
|
242
|
+
seed = [-1] * n
|
|
243
|
+
available = set(range(n)) - set(fixed.values())
|
|
244
|
+
for i, j in fixed.items():
|
|
245
|
+
seed[i] = int(j)
|
|
246
|
+
for i in range(n):
|
|
247
|
+
if i in fixed:
|
|
248
|
+
continue
|
|
249
|
+
j = next(j for j in sorted(available) if labels[i] == product_labels[j])
|
|
250
|
+
seed[i] = j
|
|
251
|
+
available.remove(j)
|
|
252
|
+
else:
|
|
253
|
+
seed = list(initial_mapping)
|
|
254
|
+
if any(isinstance(x, bool) or not isinstance(x, Integral) for x in seed):
|
|
255
|
+
raise TypeError("initial_mapping indices must be integers")
|
|
256
|
+
if sorted(seed) != list(range(n)) or any(
|
|
257
|
+
labels[i] != product_labels[j] for i, j in enumerate(seed)
|
|
258
|
+
):
|
|
259
|
+
raise ValueError("initial_mapping must be an atom-compatible permutation")
|
|
260
|
+
if any(seed[i] != j for i, j in fixed.items()):
|
|
261
|
+
raise ValueError("initial_mapping must agree with fixed_mapping")
|
|
262
|
+
return fixed, list(map(int, seed))
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _eligible(a, b, certify):
|
|
266
|
+
if certify:
|
|
267
|
+
return "legacy_prefix_certificate_requested"
|
|
268
|
+
if len(a) > 256:
|
|
269
|
+
return "order_above_256"
|
|
270
|
+
if not np.isfinite(a).all() or not np.isfinite(b).all():
|
|
271
|
+
return "nonfinite_weights"
|
|
272
|
+
if (
|
|
273
|
+
not np.array_equal(a, a.T)
|
|
274
|
+
or not np.array_equal(b, b.T)
|
|
275
|
+
or np.any(np.diag(a))
|
|
276
|
+
or np.any(np.diag(b))
|
|
277
|
+
):
|
|
278
|
+
return "directed_or_looped_graph"
|
|
279
|
+
if (
|
|
280
|
+
not np.equal(a * 2, np.rint(a * 2)).all()
|
|
281
|
+
or not np.equal(b * 2, np.rint(b * 2)).all()
|
|
282
|
+
):
|
|
283
|
+
return "weights_outside_half_integer_lattice"
|
|
284
|
+
if 2 * (np.abs(a).sum() + np.abs(b).sum()) > 2**30:
|
|
285
|
+
return "weights_above_exact_integer_range"
|
|
286
|
+
return None
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _result(
|
|
290
|
+
target,
|
|
291
|
+
total,
|
|
292
|
+
maximum,
|
|
293
|
+
started,
|
|
294
|
+
search,
|
|
295
|
+
mappings,
|
|
296
|
+
distances,
|
|
297
|
+
minimum,
|
|
298
|
+
complete,
|
|
299
|
+
group,
|
|
300
|
+
scope,
|
|
301
|
+
):
|
|
302
|
+
count = search.selected
|
|
303
|
+
cost = minimum if target == "minimal" else float(target) if count else None
|
|
304
|
+
return DistanceEnumerationResult(
|
|
305
|
+
target=target,
|
|
306
|
+
cost=cost,
|
|
307
|
+
minimum_cost=minimum,
|
|
308
|
+
mappings=mappings,
|
|
309
|
+
distances=distances,
|
|
310
|
+
total_bijections=total,
|
|
311
|
+
maximum_cost_upper_bound=maximum,
|
|
312
|
+
visited_leaves=search.statistics["visited_leaves"],
|
|
313
|
+
pruned_branches=sum(
|
|
314
|
+
search.statistics[k]
|
|
315
|
+
for k in ("lower_bound_pruned", "upper_bound_pruned", "hall_pruned")
|
|
316
|
+
),
|
|
317
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
318
|
+
status="timeout" if not complete else "complete" if count else "no_solutions",
|
|
319
|
+
complete=complete,
|
|
320
|
+
truncation_reason=search.stop_reason,
|
|
321
|
+
scope=scope,
|
|
322
|
+
visited_nodes=search.statistics["visited_nodes"],
|
|
323
|
+
symmetry_pruned_branches=search.statistics["symmetry_pruned"],
|
|
324
|
+
lower_bound_pruned_branches=search.statistics["lower_bound_pruned"],
|
|
325
|
+
upper_bound_pruned_branches=search.statistics["upper_bound_pruned"],
|
|
326
|
+
selected_mapping_count=count,
|
|
327
|
+
symmetry_group_order=len(group),
|
|
328
|
+
symmetry_automorphism_count=len(group),
|
|
329
|
+
selected_labeled_mapping_count=(
|
|
330
|
+
count
|
|
331
|
+
if search.expand
|
|
332
|
+
else None if search.reactant_symmetry else count * len(group)
|
|
333
|
+
),
|
|
334
|
+
backend="synister_cp",
|
|
335
|
+
backend_statistics={"search": dict(search.statistics)},
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _initialize_search(
|
|
340
|
+
a,
|
|
341
|
+
b,
|
|
342
|
+
labels,
|
|
343
|
+
product_labels,
|
|
344
|
+
lgp,
|
|
345
|
+
seed,
|
|
346
|
+
fixed,
|
|
347
|
+
config,
|
|
348
|
+
deadline,
|
|
349
|
+
*,
|
|
350
|
+
binary,
|
|
351
|
+
symmetry_pruning,
|
|
352
|
+
reactant_symmetry_pruning,
|
|
353
|
+
expand_symmetry,
|
|
354
|
+
symmetry_node_properties,
|
|
355
|
+
max_symmetry_automorphisms,
|
|
356
|
+
symmetry_timeout_seconds,
|
|
357
|
+
symmetry_max_search_nodes,
|
|
358
|
+
):
|
|
359
|
+
"""Budget symmetry discovery, subgroup closure and certified root setup."""
|
|
360
|
+
check_deadline(deadline)
|
|
361
|
+
group = (tuple(range(len(a))),)
|
|
362
|
+
reactant_group = (tuple(range(len(a))),)
|
|
363
|
+
discovered = True
|
|
364
|
+
if symmetry_pruning:
|
|
365
|
+
remaining = None if deadline is None else max(0, deadline - time.perf_counter())
|
|
366
|
+
seconds = (
|
|
367
|
+
math.inf if symmetry_timeout_seconds is None else symmetry_timeout_seconds
|
|
368
|
+
)
|
|
369
|
+
if remaining is not None:
|
|
370
|
+
seconds = min(seconds, remaining)
|
|
371
|
+
symmetry_deadline = deadline
|
|
372
|
+
automorphism_seconds = seconds
|
|
373
|
+
if math.isfinite(seconds):
|
|
374
|
+
local_deadline = time.perf_counter() + seconds
|
|
375
|
+
if symmetry_deadline is None or local_deadline < symmetry_deadline:
|
|
376
|
+
symmetry_deadline = local_deadline
|
|
377
|
+
automorphism_seconds = (
|
|
378
|
+
0.4 * seconds if reactant_symmetry_pruning else 0.8 * seconds
|
|
379
|
+
)
|
|
380
|
+
permutations, discovered = bounded_automorphism_permutations(
|
|
381
|
+
lgp[1],
|
|
382
|
+
binary,
|
|
383
|
+
limit=max_symmetry_automorphisms,
|
|
384
|
+
timeout_seconds=automorphism_seconds,
|
|
385
|
+
max_search_nodes=symmetry_max_search_nodes,
|
|
386
|
+
node_properties=symmetry_node_properties,
|
|
387
|
+
)
|
|
388
|
+
group = bounded_generated_subgroup(
|
|
389
|
+
permutations,
|
|
390
|
+
max_order=max_symmetry_automorphisms,
|
|
391
|
+
deadline=symmetry_deadline,
|
|
392
|
+
)
|
|
393
|
+
group = tuple(g for g in group if all(g[j] == j for j in fixed.values()))
|
|
394
|
+
if reactant_symmetry_pruning:
|
|
395
|
+
if not symmetry_pruning:
|
|
396
|
+
raise ValueError("reactant symmetry pruning requires symmetry_pruning=True")
|
|
397
|
+
remaining = None if deadline is None else max(0, deadline - time.perf_counter())
|
|
398
|
+
seconds = (
|
|
399
|
+
math.inf if symmetry_timeout_seconds is None else symmetry_timeout_seconds
|
|
400
|
+
)
|
|
401
|
+
if remaining is not None:
|
|
402
|
+
seconds = min(seconds, remaining)
|
|
403
|
+
automorphism_seconds = seconds
|
|
404
|
+
if math.isfinite(seconds):
|
|
405
|
+
automorphism_seconds = 0.4 * seconds
|
|
406
|
+
permutations, source_discovered = bounded_automorphism_permutations(
|
|
407
|
+
lgp[0],
|
|
408
|
+
binary,
|
|
409
|
+
limit=max_symmetry_automorphisms,
|
|
410
|
+
timeout_seconds=automorphism_seconds,
|
|
411
|
+
max_search_nodes=symmetry_max_search_nodes,
|
|
412
|
+
node_properties=symmetry_node_properties,
|
|
413
|
+
)
|
|
414
|
+
reactant_group = bounded_generated_subgroup(
|
|
415
|
+
permutations,
|
|
416
|
+
max_order=max_symmetry_automorphisms,
|
|
417
|
+
deadline=symmetry_deadline if symmetry_pruning else deadline,
|
|
418
|
+
)
|
|
419
|
+
reactant_group = tuple(
|
|
420
|
+
g for g in reactant_group if all(g[i] == i for i in fixed)
|
|
421
|
+
)
|
|
422
|
+
discovered = discovered and source_discovered
|
|
423
|
+
check_deadline(deadline)
|
|
424
|
+
search = PropagatedSearch(
|
|
425
|
+
np.rint(a * 4).astype(np.int64),
|
|
426
|
+
np.rint(b * 4).astype(np.int64),
|
|
427
|
+
labels,
|
|
428
|
+
product_labels,
|
|
429
|
+
seed,
|
|
430
|
+
fixed,
|
|
431
|
+
group,
|
|
432
|
+
reactant_group,
|
|
433
|
+
expand_symmetry,
|
|
434
|
+
config,
|
|
435
|
+
deadline,
|
|
436
|
+
)
|
|
437
|
+
check_deadline(deadline)
|
|
438
|
+
return search, group, reactant_group, discovered
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def _setup_timeout(target, total, maximum, started, scope):
|
|
442
|
+
"""Report an interrupted preprocessing phase without claiming infeasibility."""
|
|
443
|
+
return DistanceEnumerationResult(
|
|
444
|
+
target=target,
|
|
445
|
+
cost=None,
|
|
446
|
+
minimum_cost=None,
|
|
447
|
+
mappings=[],
|
|
448
|
+
distances=[],
|
|
449
|
+
total_bijections=total,
|
|
450
|
+
maximum_cost_upper_bound=maximum,
|
|
451
|
+
visited_leaves=0,
|
|
452
|
+
pruned_branches=0,
|
|
453
|
+
elapsed_seconds=time.perf_counter() - started,
|
|
454
|
+
status="timeout",
|
|
455
|
+
complete=False,
|
|
456
|
+
truncation_reason="time_limit",
|
|
457
|
+
scope=scope,
|
|
458
|
+
backend="synister_cp",
|
|
459
|
+
symmetry_search_complete=False,
|
|
460
|
+
backend_statistics={
|
|
461
|
+
"search": {"interrupted_phase": "preprocessing", "visited_nodes": 0}
|
|
462
|
+
},
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def enumerate_synister_cp_mappings( # noqa: C901
|
|
467
|
+
lgp,
|
|
468
|
+
*,
|
|
469
|
+
CD="minimal",
|
|
470
|
+
binary=True,
|
|
471
|
+
initial_mapping=None,
|
|
472
|
+
fixed_mapping=None,
|
|
473
|
+
max_bijections=1_000_000,
|
|
474
|
+
max_mappings=None,
|
|
475
|
+
tolerance=1e-9,
|
|
476
|
+
time_limit_seconds=None,
|
|
477
|
+
symmetry_pruning=False,
|
|
478
|
+
reactant_symmetry_pruning=False,
|
|
479
|
+
expand_symmetry=False,
|
|
480
|
+
symmetry_node_properties=(),
|
|
481
|
+
max_symmetry_automorphisms=256,
|
|
482
|
+
symmetry_timeout_seconds=0.25,
|
|
483
|
+
symmetry_max_search_nodes=10_000,
|
|
484
|
+
collect_mappings=True,
|
|
485
|
+
mapping_callback=None,
|
|
486
|
+
compute_minimum_cost=True,
|
|
487
|
+
certify=False,
|
|
488
|
+
config=None,
|
|
489
|
+
):
|
|
490
|
+
"""Enumerate exact weighted shells using Python graph-assignment propagation.
|
|
491
|
+
|
|
492
|
+
This is the Python implementation behind ``enumerate_pabs_mappings``.
|
|
493
|
+
Propagation maintains compatible one-to-one assignments; LAP lower bounds
|
|
494
|
+
prune partial mappings that cannot reach the requested cost. A supplied
|
|
495
|
+
``initial_mapping`` is a feasible seed, while ``fixed_mapping`` restricts
|
|
496
|
+
the search. No SLAP uncertainty kernel is extracted.
|
|
497
|
+
|
|
498
|
+
The new path supports loop-free undirected half-integer matrices of order
|
|
499
|
+
at most 256 in a bounded integer range. Generic graphs and legacy tree-cover
|
|
500
|
+
certificates explicitly fall back to the unchanged legacy solver. Verified
|
|
501
|
+
cyclic product subgroups provide unique expansion, including fixed subspaces.
|
|
502
|
+
|
|
503
|
+
:param lgp: Reactant/product labeled graphs.
|
|
504
|
+
:param CD: ``'minimal'`` or a nonnegative selected distance.
|
|
505
|
+
:param config: Optional propagation and adaptive-bound controls.
|
|
506
|
+
:return: Standard distance-enumeration result with explicit backend metadata.
|
|
507
|
+
"""
|
|
508
|
+
started = time.perf_counter()
|
|
509
|
+
target = normalize_distance_target(CD)
|
|
510
|
+
config = PropagationConfig() if config is None else config
|
|
511
|
+
flags = dict(
|
|
512
|
+
binary=binary,
|
|
513
|
+
symmetry_pruning=symmetry_pruning,
|
|
514
|
+
expand_symmetry=expand_symmetry,
|
|
515
|
+
collect_mappings=collect_mappings,
|
|
516
|
+
compute_minimum_cost=compute_minimum_cost,
|
|
517
|
+
certify=certify,
|
|
518
|
+
)
|
|
519
|
+
if not isinstance(reactant_symmetry_pruning, bool):
|
|
520
|
+
raise TypeError("reactant_symmetry_pruning must be Boolean")
|
|
521
|
+
if reactant_symmetry_pruning and not symmetry_pruning:
|
|
522
|
+
raise ValueError("reactant_symmetry_pruning requires symmetry_pruning=True")
|
|
523
|
+
caps = dict(
|
|
524
|
+
max_bijections=max_bijections,
|
|
525
|
+
max_mappings=max_mappings,
|
|
526
|
+
max_symmetry_automorphisms=max_symmetry_automorphisms,
|
|
527
|
+
symmetry_max_search_nodes=symmetry_max_search_nodes,
|
|
528
|
+
)
|
|
529
|
+
_validate_options(
|
|
530
|
+
tolerance, time_limit_seconds, caps, flags, mapping_callback, config
|
|
531
|
+
)
|
|
532
|
+
if max_symmetry_automorphisms is None or symmetry_max_search_nodes is None:
|
|
533
|
+
raise ValueError("Symmetry discovery caps must be positive integers")
|
|
534
|
+
_validate_options(tolerance, symmetry_timeout_seconds, {}, {}, None, config)
|
|
535
|
+
if expand_symmetry and not symmetry_pruning:
|
|
536
|
+
raise ValueError("expand_symmetry requires symmetry_pruning")
|
|
537
|
+
if isinstance(symmetry_node_properties, str):
|
|
538
|
+
raise TypeError("symmetry_node_properties must be a sequence")
|
|
539
|
+
a, labels = _adjacency_and_elements(lgp[0], binary)
|
|
540
|
+
b, product_labels = _adjacency_and_elements(lgp[1], binary)
|
|
541
|
+
if a.shape != b.shape or Counter(labels) != Counter(product_labels):
|
|
542
|
+
raise ValueError("Endpoints must have equal atom-type inventories")
|
|
543
|
+
fixed, seed = _fixed_and_seed(
|
|
544
|
+
labels, product_labels, fixed_mapping, initial_mapping
|
|
545
|
+
)
|
|
546
|
+
reason = _eligible(a, b, certify)
|
|
547
|
+
if reason is not None:
|
|
548
|
+
result = enumerate_distance_mappings(
|
|
549
|
+
lgp,
|
|
550
|
+
CD=CD,
|
|
551
|
+
initial_mapping=initial_mapping,
|
|
552
|
+
fixed_mapping=fixed_mapping,
|
|
553
|
+
tolerance=tolerance,
|
|
554
|
+
time_limit_seconds=time_limit_seconds,
|
|
555
|
+
mapping_callback=mapping_callback,
|
|
556
|
+
symmetry_node_properties=symmetry_node_properties,
|
|
557
|
+
symmetry_timeout_seconds=symmetry_timeout_seconds,
|
|
558
|
+
**flags,
|
|
559
|
+
**caps,
|
|
560
|
+
)
|
|
561
|
+
statistics = dict(result.backend_statistics or {})
|
|
562
|
+
statistics["synister_cp_fallback"] = reason
|
|
563
|
+
return replace(
|
|
564
|
+
result, backend="synister_cp_legacy_fallback", backend_statistics=statistics
|
|
565
|
+
)
|
|
566
|
+
counts = Counter(labels[i] for i in range(len(labels)) if i not in fixed)
|
|
567
|
+
total = math.prod(math.factorial(count) for count in counts.values())
|
|
568
|
+
if max_bijections is not None and total > max_bijections:
|
|
569
|
+
raise ExactEnumerationLimitError(
|
|
570
|
+
f"{total:,} atom-compatible bijections exceed max_bijections={max_bijections:,}"
|
|
571
|
+
)
|
|
572
|
+
maximum = 0.5 * float(np.abs(a).sum() + np.abs(b).sum())
|
|
573
|
+
deadline = None if time_limit_seconds is None else started + time_limit_seconds
|
|
574
|
+
scope = (
|
|
575
|
+
"fixed_assignment_subspace"
|
|
576
|
+
if fixed
|
|
577
|
+
else "complete_atom_compatible_assignment_space"
|
|
578
|
+
)
|
|
579
|
+
if symmetry_pruning and not expand_symmetry:
|
|
580
|
+
scope = (
|
|
581
|
+
"verified_reactant_product_orbit_representatives"
|
|
582
|
+
if reactant_symmetry_pruning
|
|
583
|
+
else "verified_cyclic_product_orbit_representatives"
|
|
584
|
+
) + ("_within_fixed_subspace" if fixed else "")
|
|
585
|
+
try:
|
|
586
|
+
search, group, reactant_group, discovered = _initialize_search(
|
|
587
|
+
a,
|
|
588
|
+
b,
|
|
589
|
+
labels,
|
|
590
|
+
product_labels,
|
|
591
|
+
lgp,
|
|
592
|
+
seed,
|
|
593
|
+
fixed,
|
|
594
|
+
config,
|
|
595
|
+
deadline,
|
|
596
|
+
binary=binary,
|
|
597
|
+
symmetry_pruning=symmetry_pruning,
|
|
598
|
+
reactant_symmetry_pruning=reactant_symmetry_pruning,
|
|
599
|
+
expand_symmetry=expand_symmetry,
|
|
600
|
+
symmetry_node_properties=symmetry_node_properties,
|
|
601
|
+
max_symmetry_automorphisms=max_symmetry_automorphisms,
|
|
602
|
+
symmetry_timeout_seconds=symmetry_timeout_seconds,
|
|
603
|
+
symmetry_max_search_nodes=symmetry_max_search_nodes,
|
|
604
|
+
)
|
|
605
|
+
except PropagationDeadline:
|
|
606
|
+
return _setup_timeout(target, total, maximum, started, scope)
|
|
607
|
+
search.statistics["preprocessing_seconds"] = time.perf_counter() - started
|
|
608
|
+
search.selected, search.stop_reason = 0, None
|
|
609
|
+
minimum, complete = None, True
|
|
610
|
+
if target == "minimal" or compute_minimum_cost:
|
|
611
|
+
before = time.perf_counter()
|
|
612
|
+
complete = search.prove()
|
|
613
|
+
search.statistics["minimum_proof_seconds"] = time.perf_counter() - before
|
|
614
|
+
search.statistics["minimum_proof_nodes"] = search.statistics["visited_nodes"]
|
|
615
|
+
search.statistics["minimum_proof_status"] = (
|
|
616
|
+
"proved" if complete else "time_limit"
|
|
617
|
+
)
|
|
618
|
+
if complete:
|
|
619
|
+
minimum = search.incumbent / 4
|
|
620
|
+
else:
|
|
621
|
+
search.statistics["minimum_proof_seconds"] = None
|
|
622
|
+
search.statistics["minimum_proof_nodes"] = None
|
|
623
|
+
search.statistics["minimum_proof_status"] = "not_requested"
|
|
624
|
+
search.statistics["incumbent_quarters"] = int(search.incumbent)
|
|
625
|
+
search.statistics["root_lower_bound_quarters"] = int(search.root_lower)
|
|
626
|
+
search.statistics["root_gap_quarters"] = int(search.incumbent - search.root_lower)
|
|
627
|
+
mappings, distances = [], []
|
|
628
|
+
|
|
629
|
+
def emit(mapping, cost):
|
|
630
|
+
if collect_mappings:
|
|
631
|
+
mappings.append(mapping)
|
|
632
|
+
distances.append(cost)
|
|
633
|
+
if mapping_callback is not None:
|
|
634
|
+
mapping_callback(mapping, cost)
|
|
635
|
+
|
|
636
|
+
enumeration_seconds = 0.0
|
|
637
|
+
enumeration_nodes = 0
|
|
638
|
+
if target != "minimal" or complete:
|
|
639
|
+
selected = minimum if target == "minimal" else target
|
|
640
|
+
lower, upper = math.ceil((selected - tolerance) * 4), math.floor(
|
|
641
|
+
(selected + tolerance) * 4
|
|
642
|
+
)
|
|
643
|
+
before_nodes = search.statistics["visited_nodes"]
|
|
644
|
+
enumeration_started = time.perf_counter()
|
|
645
|
+
complete = search.enumerate(lower, upper, emit, max_mappings)
|
|
646
|
+
enumeration_seconds = time.perf_counter() - enumeration_started
|
|
647
|
+
enumeration_nodes = search.statistics["visited_nodes"] - before_nodes
|
|
648
|
+
search.statistics["enumeration_seconds"] = enumeration_seconds
|
|
649
|
+
search.statistics["enumeration_nodes"] = enumeration_nodes
|
|
650
|
+
search.statistics["enumeration_status"] = (
|
|
651
|
+
"complete"
|
|
652
|
+
if enumeration_seconds and complete
|
|
653
|
+
else "incomplete" if enumeration_seconds else "not_started"
|
|
654
|
+
)
|
|
655
|
+
scope = (
|
|
656
|
+
"fixed_assignment_subspace"
|
|
657
|
+
if fixed
|
|
658
|
+
else "complete_atom_compatible_assignment_space"
|
|
659
|
+
)
|
|
660
|
+
if symmetry_pruning and not expand_symmetry:
|
|
661
|
+
scope = (
|
|
662
|
+
"verified_reactant_product_orbit_representatives"
|
|
663
|
+
if reactant_symmetry_pruning
|
|
664
|
+
else "verified_cyclic_product_orbit_representatives"
|
|
665
|
+
) + ("_within_fixed_subspace" if fixed else "")
|
|
666
|
+
result = _result(
|
|
667
|
+
target,
|
|
668
|
+
total,
|
|
669
|
+
maximum,
|
|
670
|
+
started,
|
|
671
|
+
search,
|
|
672
|
+
mappings,
|
|
673
|
+
distances,
|
|
674
|
+
minimum,
|
|
675
|
+
complete,
|
|
676
|
+
group,
|
|
677
|
+
scope,
|
|
678
|
+
)
|
|
679
|
+
return replace(result, symmetry_search_complete=discovered)
|