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,694 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from itertools import combinations
|
|
4
|
+
from typing import Dict, Iterator, List, Optional, Sequence, Set, Union
|
|
5
|
+
|
|
6
|
+
import networkx as nx
|
|
7
|
+
|
|
8
|
+
from synkit.Graph.Matcher.subgraph_matcher import (
|
|
9
|
+
SubgraphSearchEngine,
|
|
10
|
+
electron_aware_node_match,
|
|
11
|
+
)
|
|
12
|
+
from synkit.Synthesis.Reactor import Strategy
|
|
13
|
+
from synkit.Graph.Matcher.auto_est import AutoEst # WL-1 orbit estimator
|
|
14
|
+
from synkit.Graph.Matcher.dedup_matches import deduplicate_matches_with_anchor
|
|
15
|
+
|
|
16
|
+
MappingDict = Dict[int, int]
|
|
17
|
+
|
|
18
|
+
__all__ = ["PartialMatcher"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PartialMatcher:
|
|
22
|
+
"""Component-subset helper for pattern→host subgraph matching.
|
|
23
|
+
|
|
24
|
+
This matcher treats each connected component of the pattern as an
|
|
25
|
+
independent "micro-pattern" and searches for consistent embeddings
|
|
26
|
+
of subsets of these components into one or more host graphs. It can
|
|
27
|
+
behave like a classic "partial matcher" (searching all component
|
|
28
|
+
counts) or like a strict full-pattern matcher, depending on the
|
|
29
|
+
``partial`` flag.
|
|
30
|
+
|
|
31
|
+
Internally, all embeddings for each pair (host, pattern component)
|
|
32
|
+
are pre-computed once and then re-used for all combinations. This
|
|
33
|
+
significantly reduces redundant calls to
|
|
34
|
+
:class:`SubgraphSearchEngine` when exploring many subsets.
|
|
35
|
+
|
|
36
|
+
Optionally, approximate WL-1 automorphism orbits can be used to
|
|
37
|
+
prune embeddings that are equivalent under host symmetries via
|
|
38
|
+
``prune_auto``.
|
|
39
|
+
|
|
40
|
+
:param host: Single host graph or sequence of host graphs.
|
|
41
|
+
:type host: nx.Graph | Sequence[nx.Graph]
|
|
42
|
+
:param pattern: Pattern graph whose connected components act as building blocks.
|
|
43
|
+
:type pattern: nx.Graph
|
|
44
|
+
:param node_attrs: Node attribute keys enforced equal during matching.
|
|
45
|
+
:type node_attrs: list[str]
|
|
46
|
+
:param edge_attrs: Edge attribute keys enforced equal during matching.
|
|
47
|
+
:type edge_attrs: list[str]
|
|
48
|
+
:param strategy: Matching strategy forwarded to :class:`SubgraphSearchEngine`.
|
|
49
|
+
:type strategy: Strategy, optional
|
|
50
|
+
:param max_results: Global cap on number of embeddings to store. If ``None``, no
|
|
51
|
+
explicit cap is applied.
|
|
52
|
+
:type max_results: int | None, optional
|
|
53
|
+
:param partial: If ``True``, auto-mode (``k=None``) searches all component counts
|
|
54
|
+
from full pattern down to 1. If ``False``, auto-mode only tries
|
|
55
|
+
``k = n_components`` (i.e. full-pattern matching only).
|
|
56
|
+
:type partial: bool, optional
|
|
57
|
+
:param threshold: Optional cap on embeddings *per (host, component)* pairing. If
|
|
58
|
+
exceeded, that pairing is treated as "no valid embeddings" and
|
|
59
|
+
skipped. Defaults to :data:`SubgraphSearchEngine.DEFAULT_THRESHOLD`.
|
|
60
|
+
:type threshold: int | None, optional
|
|
61
|
+
:param pre_filter: If ``True``, enable the cheap Cartesian-product pre-filter in
|
|
62
|
+
:class:`SubgraphSearchEngine` for each (host, component) pair.
|
|
63
|
+
:type pre_filter: bool, optional
|
|
64
|
+
:param prune_auto: If ``True``, apply approximate automorphism-based pruning on the
|
|
65
|
+
final list of embeddings using WL-1 orbits computed by
|
|
66
|
+
:class:`AutoEst`. For safety, pruning is only applied when there
|
|
67
|
+
is a single host graph. Defaults to ``False``.
|
|
68
|
+
:type prune_auto: bool, optional
|
|
69
|
+
:param wl_max_iter: Maximum number of WL refinement iterations in :class:`AutoEst`
|
|
70
|
+
when ``prune_auto`` is enabled. Defaults to 10.
|
|
71
|
+
:type wl_max_iter: int, optional
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
host: Union[nx.Graph, Sequence[nx.Graph]],
|
|
77
|
+
pattern: nx.Graph,
|
|
78
|
+
node_attrs: List[str],
|
|
79
|
+
edge_attrs: List[str],
|
|
80
|
+
*,
|
|
81
|
+
strategy: Strategy = Strategy.COMPONENT,
|
|
82
|
+
max_results: Optional[int] = None,
|
|
83
|
+
partial: bool = True,
|
|
84
|
+
threshold: Optional[int] = None,
|
|
85
|
+
pre_filter: bool = False,
|
|
86
|
+
prune_auto: bool = False,
|
|
87
|
+
wl_max_iter: int = 10,
|
|
88
|
+
) -> None:
|
|
89
|
+
if isinstance(host, nx.Graph):
|
|
90
|
+
self.hosts: List[nx.Graph] = [host]
|
|
91
|
+
elif isinstance(host, Sequence):
|
|
92
|
+
self.hosts = list(host)
|
|
93
|
+
else:
|
|
94
|
+
raise TypeError(
|
|
95
|
+
"host must be a networkx.Graph or a sequence of such graphs"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
self.pattern: nx.Graph = pattern
|
|
99
|
+
self.node_attrs: List[str] = node_attrs
|
|
100
|
+
self.edge_attrs: List[str] = edge_attrs
|
|
101
|
+
self.strategy: Strategy = strategy
|
|
102
|
+
if max_results is not None and max_results < 0:
|
|
103
|
+
raise ValueError("max_results must be non-negative or None")
|
|
104
|
+
if threshold is not None and threshold < 0:
|
|
105
|
+
raise ValueError("threshold must be non-negative or None")
|
|
106
|
+
self.max_results: Optional[int] = max_results
|
|
107
|
+
self.partial: bool = partial
|
|
108
|
+
self._threshold: int = (
|
|
109
|
+
threshold
|
|
110
|
+
if threshold is not None
|
|
111
|
+
else SubgraphSearchEngine.DEFAULT_THRESHOLD
|
|
112
|
+
)
|
|
113
|
+
self._pre_filter: bool = pre_filter
|
|
114
|
+
|
|
115
|
+
# WL-1 approximate automorphism pruning settings
|
|
116
|
+
self._prune_auto: bool = bool(prune_auto)
|
|
117
|
+
self._wl_max_iter: int = int(wl_max_iter)
|
|
118
|
+
|
|
119
|
+
# Candidate-domain embedding upper bound
|
|
120
|
+
self._approx_embedding_count: Optional[int] = None
|
|
121
|
+
|
|
122
|
+
self._pattern_ccs: List[nx.Graph] = self._split_pattern_components()
|
|
123
|
+
self._host_embeddings: List[List[List[MappingDict]]] = []
|
|
124
|
+
if self.max_results == 0:
|
|
125
|
+
self._mappings = []
|
|
126
|
+
return
|
|
127
|
+
self._precompute_embeddings()
|
|
128
|
+
|
|
129
|
+
mappings = self._match_components(k=None)
|
|
130
|
+
if self._prune_auto:
|
|
131
|
+
mappings = self._prune_automorphic_mappings(mappings)
|
|
132
|
+
self._mappings: List[MappingDict] = mappings
|
|
133
|
+
|
|
134
|
+
# ------------------------------------------------------------------
|
|
135
|
+
# Internal helpers
|
|
136
|
+
# ------------------------------------------------------------------
|
|
137
|
+
def _split_pattern_components(self) -> List[nx.Graph]:
|
|
138
|
+
"""Split the pattern into connected components.
|
|
139
|
+
|
|
140
|
+
:return: List of connected component subgraphs.
|
|
141
|
+
:rtype: list[nx.Graph]
|
|
142
|
+
:raises ValueError: If the pattern has no components.
|
|
143
|
+
"""
|
|
144
|
+
component_nodes = (
|
|
145
|
+
nx.weakly_connected_components(self.pattern)
|
|
146
|
+
if self.pattern.is_directed()
|
|
147
|
+
else nx.connected_components(self.pattern)
|
|
148
|
+
)
|
|
149
|
+
components = [self.pattern.subgraph(nodes).copy() for nodes in component_nodes]
|
|
150
|
+
if not components:
|
|
151
|
+
raise ValueError("Pattern graph has no components.")
|
|
152
|
+
return components
|
|
153
|
+
|
|
154
|
+
def _precompute_embeddings(self) -> None:
|
|
155
|
+
"""
|
|
156
|
+
Pre-compute embeddings for each (host, component) pair.
|
|
157
|
+
|
|
158
|
+
The results are stored in :attr:`_host_embeddings` as a nested
|
|
159
|
+
list indexed as ``[host_index][component_index]``.
|
|
160
|
+
"""
|
|
161
|
+
host_embeddings: List[List[List[MappingDict]]] = []
|
|
162
|
+
for host in self.hosts:
|
|
163
|
+
comp_embeddings: List[List[MappingDict]] = []
|
|
164
|
+
for pat_cc in self._pattern_ccs:
|
|
165
|
+
embeddings = SubgraphSearchEngine.find_subgraph_mappings(
|
|
166
|
+
host,
|
|
167
|
+
pat_cc,
|
|
168
|
+
node_attrs=self.node_attrs,
|
|
169
|
+
edge_attrs=self.edge_attrs,
|
|
170
|
+
strategy=self.strategy,
|
|
171
|
+
# A global result cap cannot safely truncate an individual
|
|
172
|
+
# component domain: the retained local embeddings may all
|
|
173
|
+
# overlap those of another component even though a later
|
|
174
|
+
# local embedding participates in a valid injective join.
|
|
175
|
+
max_results=None,
|
|
176
|
+
strict_cc_count=False,
|
|
177
|
+
threshold=self._threshold,
|
|
178
|
+
pre_filter=self._pre_filter,
|
|
179
|
+
)
|
|
180
|
+
comp_embeddings.append(embeddings)
|
|
181
|
+
host_embeddings.append(comp_embeddings)
|
|
182
|
+
self._host_embeddings = host_embeddings
|
|
183
|
+
|
|
184
|
+
def _prune_automorphic_mappings(
|
|
185
|
+
self,
|
|
186
|
+
mappings: List[MappingDict],
|
|
187
|
+
) -> List[MappingDict]:
|
|
188
|
+
"""Approximate automorphism-based pruning using WL-1 orbits.
|
|
189
|
+
|
|
190
|
+
This uses :class:`AutoEst` on the (single) host graph to collapse
|
|
191
|
+
mappings that hit the same multiset of WL-orbit indices. For
|
|
192
|
+
multiple hosts, the input list is returned unchanged to avoid
|
|
193
|
+
node-id collisions across different hosts.
|
|
194
|
+
|
|
195
|
+
:param mappings: Flat list of pattern→host mappings.
|
|
196
|
+
:type mappings: list[MappingDict]
|
|
197
|
+
:return: Possibly pruned list of mappings.
|
|
198
|
+
:rtype: list[MappingDict]
|
|
199
|
+
"""
|
|
200
|
+
if not mappings:
|
|
201
|
+
return []
|
|
202
|
+
|
|
203
|
+
if len(self.hosts) != 1:
|
|
204
|
+
return mappings
|
|
205
|
+
|
|
206
|
+
host = self.hosts[0]
|
|
207
|
+
est = AutoEst(
|
|
208
|
+
graph=host,
|
|
209
|
+
node_attrs=self.node_attrs,
|
|
210
|
+
edge_attrs=self.edge_attrs,
|
|
211
|
+
max_iter=self._wl_max_iter,
|
|
212
|
+
).fit()
|
|
213
|
+
|
|
214
|
+
# AutoEst.deduplicate expects Mapping[hashable, hashable]
|
|
215
|
+
maps = deduplicate_matches_with_anchor(
|
|
216
|
+
matches=mappings, host_orbits=est.orbits, host_anchor=est.anchor_component
|
|
217
|
+
)
|
|
218
|
+
return maps
|
|
219
|
+
|
|
220
|
+
# ------------------------------------------------------------------
|
|
221
|
+
# Embedding upper-bound helpers
|
|
222
|
+
# ------------------------------------------------------------------
|
|
223
|
+
def _normalise_k_values(self, k: Optional[int]) -> List[int]:
|
|
224
|
+
"""Normalise ``k`` to a list of component counts to consider.
|
|
225
|
+
|
|
226
|
+
:param k: Desired number of components or ``None`` for auto-mode.
|
|
227
|
+
:type k: int | None
|
|
228
|
+
:return: List of component counts to iterate over.
|
|
229
|
+
:rtype: list[int]
|
|
230
|
+
:raises ValueError: If ``k`` is outside ``[1, n_components]``.
|
|
231
|
+
"""
|
|
232
|
+
n_cc = len(self._pattern_ccs)
|
|
233
|
+
if k is not None:
|
|
234
|
+
if k <= 0 or k > n_cc:
|
|
235
|
+
raise ValueError(f"k must be between 1 and {n_cc}")
|
|
236
|
+
return [k]
|
|
237
|
+
if not self.partial:
|
|
238
|
+
return [n_cc]
|
|
239
|
+
return list(range(n_cc, 0, -1))
|
|
240
|
+
|
|
241
|
+
def _pair_count_upper_bound(self, host: nx.Graph, component: nx.Graph) -> int:
|
|
242
|
+
"""Bound embeddings by the product of compatible node-domain sizes.
|
|
243
|
+
|
|
244
|
+
Every subgraph embedding maps a pattern node to a host node satisfying
|
|
245
|
+
the authoritative node predicate and the necessary degree inequality.
|
|
246
|
+
Ignoring adjacency and injectivity can only add assignments, so the
|
|
247
|
+
resulting product is a mathematical upper bound.
|
|
248
|
+
"""
|
|
249
|
+
total = 1
|
|
250
|
+
for pattern_node, pattern_data in component.nodes(data=True):
|
|
251
|
+
pattern_degree = component.degree(pattern_node)
|
|
252
|
+
domain_size = sum(
|
|
253
|
+
1
|
|
254
|
+
for host_node, host_data in host.nodes(data=True)
|
|
255
|
+
if host.degree(host_node) >= pattern_degree
|
|
256
|
+
and electron_aware_node_match(
|
|
257
|
+
host_data,
|
|
258
|
+
pattern_data,
|
|
259
|
+
self.node_attrs,
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
if domain_size == 0:
|
|
263
|
+
return 0
|
|
264
|
+
total *= domain_size
|
|
265
|
+
return total
|
|
266
|
+
|
|
267
|
+
def _compute_pair_counts(
|
|
268
|
+
self,
|
|
269
|
+
) -> List[List[int]]:
|
|
270
|
+
"""Pre-compute upper bounds for all (host, component) pairs.
|
|
271
|
+
|
|
272
|
+
:return: Matrix of upper bounds indexed as [host][component].
|
|
273
|
+
:rtype: list[list[int]]
|
|
274
|
+
"""
|
|
275
|
+
pair_counts: List[List[int]] = []
|
|
276
|
+
for host in self.hosts:
|
|
277
|
+
row: List[int] = []
|
|
278
|
+
for component in self._pattern_ccs:
|
|
279
|
+
count = self._pair_count_upper_bound(host, component)
|
|
280
|
+
row.append(count)
|
|
281
|
+
pair_counts.append(row)
|
|
282
|
+
return pair_counts
|
|
283
|
+
|
|
284
|
+
def _product_for_combo(
|
|
285
|
+
self,
|
|
286
|
+
row: List[int],
|
|
287
|
+
combo: Sequence[int],
|
|
288
|
+
) -> int:
|
|
289
|
+
"""Compute product of pair counts for a single host/combination.
|
|
290
|
+
|
|
291
|
+
:param row: List of pair counts for one host over all components.
|
|
292
|
+
:type row: list[int]
|
|
293
|
+
:param combo: Selected component indices.
|
|
294
|
+
:type combo: Sequence[int]
|
|
295
|
+
:return: Product of counts, or 0 if any factor is 0.
|
|
296
|
+
:rtype: int
|
|
297
|
+
"""
|
|
298
|
+
prod_val = 1
|
|
299
|
+
for cc_idx in combo:
|
|
300
|
+
pair_count = row[cc_idx]
|
|
301
|
+
if pair_count == 0:
|
|
302
|
+
return 0
|
|
303
|
+
prod_val *= pair_count
|
|
304
|
+
return prod_val
|
|
305
|
+
|
|
306
|
+
def _aggregate_pair_counts(
|
|
307
|
+
self,
|
|
308
|
+
pair_counts: List[List[int]],
|
|
309
|
+
k_values: List[int],
|
|
310
|
+
) -> int:
|
|
311
|
+
"""Aggregate per-pair estimates over component subsets and hosts.
|
|
312
|
+
|
|
313
|
+
:param pair_counts: Matrix of approximate counts [host][component].
|
|
314
|
+
:type pair_counts: list[list[int]]
|
|
315
|
+
:param k_values: Component counts to consider.
|
|
316
|
+
:type k_values: list[int]
|
|
317
|
+
:return: Aggregated estimate (may be truncated by ``max_results``).
|
|
318
|
+
:rtype: int
|
|
319
|
+
"""
|
|
320
|
+
total_est = 0
|
|
321
|
+
n_cc = len(self._pattern_ccs)
|
|
322
|
+
cc_indices = range(n_cc)
|
|
323
|
+
|
|
324
|
+
for k_try in k_values:
|
|
325
|
+
for combo in combinations(cc_indices, k_try):
|
|
326
|
+
for host_idx, row in enumerate(pair_counts):
|
|
327
|
+
prod_val = self._product_for_combo(row, combo)
|
|
328
|
+
if prod_val == 0:
|
|
329
|
+
continue
|
|
330
|
+
total_est += prod_val
|
|
331
|
+
if self.max_results is not None and total_est >= self.max_results:
|
|
332
|
+
return int(self.max_results)
|
|
333
|
+
return int(total_est)
|
|
334
|
+
|
|
335
|
+
# ------------------------------------------------------------------
|
|
336
|
+
# Core matching logic
|
|
337
|
+
# ------------------------------------------------------------------
|
|
338
|
+
def _match_components(self, k: Optional[int] = None) -> List[MappingDict]:
|
|
339
|
+
"""Internal search – returns a *flat* list of embeddings.
|
|
340
|
+
|
|
341
|
+
:param k: Number of connected components of the pattern to use.
|
|
342
|
+
|
|
343
|
+
* If an integer, the search is restricted to subsets of
|
|
344
|
+
exactly ``k`` pattern components.
|
|
345
|
+
* If ``None``, behaviour depends on :attr:`partial`:
|
|
346
|
+
|
|
347
|
+
- ``partial=False`` → only ``k = n_components`` is used.
|
|
348
|
+
- ``partial=True`` → searches all feasible ``k`` from
|
|
349
|
+
``n_components`` down to 1.
|
|
350
|
+
|
|
351
|
+
:type k: int | None
|
|
352
|
+
:return: Flat list of pattern→host node mappings.
|
|
353
|
+
:rtype: list[MappingDict]
|
|
354
|
+
"""
|
|
355
|
+
if k is not None:
|
|
356
|
+
return self._match_fixed_k(k)
|
|
357
|
+
|
|
358
|
+
if not self.partial:
|
|
359
|
+
return self._match_fixed_k(len(self._pattern_ccs))
|
|
360
|
+
|
|
361
|
+
return self._match_all_k()
|
|
362
|
+
|
|
363
|
+
def _match_all_k(self) -> List[MappingDict]:
|
|
364
|
+
"""Aggregate embeddings over all feasible component counts.
|
|
365
|
+
|
|
366
|
+
This tries ``k = n_cc, n_cc-1, ..., 1`` and stops once
|
|
367
|
+
:attr:`max_results` is reached (if set).
|
|
368
|
+
|
|
369
|
+
:return: Flat list of pattern→host node mappings.
|
|
370
|
+
:rtype: list[MappingDict]
|
|
371
|
+
"""
|
|
372
|
+
all_mappings: List[MappingDict] = []
|
|
373
|
+
n_cc = len(self._pattern_ccs)
|
|
374
|
+
|
|
375
|
+
for k_try in range(n_cc, 0, -1):
|
|
376
|
+
mappings = self._match_fixed_k(k_try)
|
|
377
|
+
if not mappings:
|
|
378
|
+
continue
|
|
379
|
+
|
|
380
|
+
for emb in mappings:
|
|
381
|
+
all_mappings.append(emb)
|
|
382
|
+
if (
|
|
383
|
+
self.max_results is not None
|
|
384
|
+
and len(all_mappings) >= self.max_results
|
|
385
|
+
):
|
|
386
|
+
return all_mappings
|
|
387
|
+
|
|
388
|
+
return all_mappings
|
|
389
|
+
|
|
390
|
+
def _match_fixed_k(self, k: int) -> List[MappingDict]:
|
|
391
|
+
"""Match using exactly ``k`` connected components of the pattern.
|
|
392
|
+
|
|
393
|
+
:param k: Number of connected components to select.
|
|
394
|
+
:type k: int
|
|
395
|
+
:return: Flat list of pattern→host node mappings.
|
|
396
|
+
:rtype: list[MappingDict]
|
|
397
|
+
:raises ValueError: If ``k`` is outside ``[1, n_components]``.
|
|
398
|
+
"""
|
|
399
|
+
n_cc = len(self._pattern_ccs)
|
|
400
|
+
if k <= 0 or k > n_cc:
|
|
401
|
+
raise ValueError(f"k must be between 1 and {n_cc}")
|
|
402
|
+
|
|
403
|
+
all_mappings: List[MappingDict] = []
|
|
404
|
+
cc_indices = range(n_cc)
|
|
405
|
+
|
|
406
|
+
for combo in combinations(cc_indices, k):
|
|
407
|
+
for host_index, _host in enumerate(self.hosts):
|
|
408
|
+
self._backtrack_components(
|
|
409
|
+
combo=combo,
|
|
410
|
+
host_index=host_index,
|
|
411
|
+
level=0,
|
|
412
|
+
used_nodes=set(),
|
|
413
|
+
accum={},
|
|
414
|
+
out=all_mappings,
|
|
415
|
+
)
|
|
416
|
+
if (
|
|
417
|
+
self.max_results is not None
|
|
418
|
+
and len(all_mappings) >= self.max_results
|
|
419
|
+
):
|
|
420
|
+
return all_mappings
|
|
421
|
+
|
|
422
|
+
return all_mappings
|
|
423
|
+
|
|
424
|
+
def _backtrack_components(
|
|
425
|
+
self,
|
|
426
|
+
combo: Sequence[int],
|
|
427
|
+
host_index: int,
|
|
428
|
+
level: int,
|
|
429
|
+
used_nodes: Set[int],
|
|
430
|
+
accum: MappingDict,
|
|
431
|
+
out: List[MappingDict],
|
|
432
|
+
) -> None:
|
|
433
|
+
"""
|
|
434
|
+
Backtracking across selected components within a single host.
|
|
435
|
+
|
|
436
|
+
:param combo: Sequence of component indices to match in order.
|
|
437
|
+
:type combo: Sequence[int]
|
|
438
|
+
:param host_index: Index of the current host in :attr:`hosts`.
|
|
439
|
+
:type host_index: int
|
|
440
|
+
:param level: Current recursion depth (index in ``combo``).
|
|
441
|
+
:type level: int
|
|
442
|
+
:param used_nodes: Set of host node ids already used.
|
|
443
|
+
:type used_nodes: set[int]
|
|
444
|
+
:param accum: Accumulated pattern→host mapping.
|
|
445
|
+
:type accum: MappingDict
|
|
446
|
+
:param out: List where completed mappings are appended.
|
|
447
|
+
:type out: list[MappingDict]
|
|
448
|
+
"""
|
|
449
|
+
if self.max_results is not None and len(out) >= self.max_results:
|
|
450
|
+
return
|
|
451
|
+
|
|
452
|
+
if level == len(combo):
|
|
453
|
+
out.append(accum.copy())
|
|
454
|
+
return
|
|
455
|
+
|
|
456
|
+
cc_idx = combo[level]
|
|
457
|
+
embeddings = self._host_embeddings[host_index][cc_idx]
|
|
458
|
+
|
|
459
|
+
if not embeddings:
|
|
460
|
+
return
|
|
461
|
+
|
|
462
|
+
for emb in embeddings:
|
|
463
|
+
mapped = set(emb.values())
|
|
464
|
+
if mapped & used_nodes:
|
|
465
|
+
continue
|
|
466
|
+
|
|
467
|
+
new_used = used_nodes | mapped
|
|
468
|
+
new_accum = {**accum, **emb}
|
|
469
|
+
self._backtrack_components(
|
|
470
|
+
combo=combo,
|
|
471
|
+
host_index=host_index,
|
|
472
|
+
level=level + 1,
|
|
473
|
+
used_nodes=new_used,
|
|
474
|
+
accum=new_accum,
|
|
475
|
+
out=out,
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
# ------------------------------------------------------------------
|
|
479
|
+
# Candidate-domain embedding upper bound
|
|
480
|
+
# ------------------------------------------------------------------
|
|
481
|
+
def estimate_embeddings_wl(self, k: Optional[int] = None) -> "PartialMatcher":
|
|
482
|
+
"""Compute a cheap upper bound on the number of stored embeddings.
|
|
483
|
+
|
|
484
|
+
This is a mathematical upper bound that:
|
|
485
|
+
|
|
486
|
+
* Builds the authoritative compatible host-node domain for each
|
|
487
|
+
pattern node, including degree and directional electron constraints.
|
|
488
|
+
* Multiplies domain sizes while deliberately ignoring adjacency and
|
|
489
|
+
injectivity, both of which can only reduce the exact population.
|
|
490
|
+
* Aggregates these per-pair estimates over subsets of pattern
|
|
491
|
+
components using the same semantics as :meth:`_match_components`.
|
|
492
|
+
|
|
493
|
+
No calls to :class:`SubgraphSearchEngine` or backtracking are
|
|
494
|
+
performed. The result is stored in
|
|
495
|
+
:attr:`approx_embedding_count`.
|
|
496
|
+
|
|
497
|
+
:param k: Number of pattern components to use. If ``None``,
|
|
498
|
+
behaviour mirrors :meth:`_match_components`:
|
|
499
|
+
|
|
500
|
+
* ``partial=False`` → use only full pattern (``k=n_cc``).
|
|
501
|
+
* ``partial=True`` → aggregate over all k from ``n_cc`` down to 1.
|
|
502
|
+
|
|
503
|
+
:type k: int | None
|
|
504
|
+
:return: The estimator itself (for chained use).
|
|
505
|
+
:rtype: PartialMatcher
|
|
506
|
+
"""
|
|
507
|
+
k_values = self._normalise_k_values(k)
|
|
508
|
+
pair_counts = self._compute_pair_counts()
|
|
509
|
+
total_est = self._aggregate_pair_counts(pair_counts, k_values)
|
|
510
|
+
|
|
511
|
+
if self.max_results is not None and total_est >= self.max_results:
|
|
512
|
+
self._approx_embedding_count = int(self.max_results)
|
|
513
|
+
else:
|
|
514
|
+
self._approx_embedding_count = int(total_est)
|
|
515
|
+
|
|
516
|
+
return self
|
|
517
|
+
|
|
518
|
+
@property
|
|
519
|
+
def approx_embedding_count(self) -> int:
|
|
520
|
+
"""Candidate-domain upper bound on the stored embedding count.
|
|
521
|
+
|
|
522
|
+
:return: Last estimated embedding count.
|
|
523
|
+
:rtype: int
|
|
524
|
+
:raises RuntimeError: If :meth:`estimate_embeddings_wl` has not
|
|
525
|
+
been called.
|
|
526
|
+
"""
|
|
527
|
+
if self._approx_embedding_count is None:
|
|
528
|
+
raise RuntimeError(
|
|
529
|
+
"Call 'estimate_embeddings_wl()' before accessing "
|
|
530
|
+
"'approx_embedding_count'."
|
|
531
|
+
)
|
|
532
|
+
return self._approx_embedding_count
|
|
533
|
+
|
|
534
|
+
# ------------------------------------------------------------------
|
|
535
|
+
# Public instance helpers
|
|
536
|
+
# ------------------------------------------------------------------
|
|
537
|
+
def get_mappings(self) -> List[MappingDict]:
|
|
538
|
+
"""Return the list of discovered embeddings (auto-computed).
|
|
539
|
+
|
|
540
|
+
:return: List of pattern→host node mappings.
|
|
541
|
+
:rtype: list[MappingDict]
|
|
542
|
+
"""
|
|
543
|
+
return self._mappings
|
|
544
|
+
|
|
545
|
+
@property
|
|
546
|
+
def num_mappings(self) -> int:
|
|
547
|
+
"""Number of embeddings found.
|
|
548
|
+
|
|
549
|
+
:return: Count of discovered embeddings.
|
|
550
|
+
:rtype: int
|
|
551
|
+
"""
|
|
552
|
+
return len(self._mappings)
|
|
553
|
+
|
|
554
|
+
@property
|
|
555
|
+
def num_pattern_components(self) -> int:
|
|
556
|
+
"""Number of connected components in the pattern graph.
|
|
557
|
+
|
|
558
|
+
:return: Number of pattern connected components.
|
|
559
|
+
:rtype: int
|
|
560
|
+
"""
|
|
561
|
+
return len(self._pattern_ccs)
|
|
562
|
+
|
|
563
|
+
@property
|
|
564
|
+
def threshold(self) -> int:
|
|
565
|
+
"""Per-(host, component) embedding threshold.
|
|
566
|
+
|
|
567
|
+
:return: Threshold passed to :class:`SubgraphSearchEngine`.
|
|
568
|
+
:rtype: int
|
|
569
|
+
"""
|
|
570
|
+
return self._threshold
|
|
571
|
+
|
|
572
|
+
@property
|
|
573
|
+
def pre_filter(self) -> bool:
|
|
574
|
+
"""Whether the cheap pre-filter is enabled.
|
|
575
|
+
|
|
576
|
+
:return: Current value of the pre-filter flag.
|
|
577
|
+
:rtype: bool
|
|
578
|
+
"""
|
|
579
|
+
return self._pre_filter
|
|
580
|
+
|
|
581
|
+
# Iteration support -------------------------------------------------
|
|
582
|
+
def __iter__(self) -> Iterator[MappingDict]:
|
|
583
|
+
"""Iterate over discovered embeddings.
|
|
584
|
+
|
|
585
|
+
:return: Iterator over mapping dictionaries.
|
|
586
|
+
:rtype: Iterator[MappingDict]
|
|
587
|
+
"""
|
|
588
|
+
return iter(self._mappings)
|
|
589
|
+
|
|
590
|
+
# Niceties ----------------------------------------------------------
|
|
591
|
+
def __repr__(self) -> str:
|
|
592
|
+
"""Representation string for debugging.
|
|
593
|
+
|
|
594
|
+
:return: Short summary of matcher state.
|
|
595
|
+
:rtype: str
|
|
596
|
+
"""
|
|
597
|
+
return (
|
|
598
|
+
f"<PartialMatcher pattern_ccs={self.num_pattern_components} "
|
|
599
|
+
f"hosts={len(self.hosts)} mappings={self.num_mappings} "
|
|
600
|
+
f"partial={self.partial} threshold={self._threshold} "
|
|
601
|
+
f"pre_filter={self._pre_filter} prune_auto={self._prune_auto}>"
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
__str__ = __repr__
|
|
605
|
+
|
|
606
|
+
@property
|
|
607
|
+
def help(self) -> str:
|
|
608
|
+
"""Return the full module docstring.
|
|
609
|
+
|
|
610
|
+
:return: Module-level documentation string.
|
|
611
|
+
:rtype: str
|
|
612
|
+
"""
|
|
613
|
+
return __doc__ or ""
|
|
614
|
+
|
|
615
|
+
# ------------------------------------------------------------------
|
|
616
|
+
# Functional/staticmethod wrapper
|
|
617
|
+
# ------------------------------------------------------------------
|
|
618
|
+
@staticmethod
|
|
619
|
+
def find_partial_mappings(
|
|
620
|
+
host: Union[nx.Graph, Sequence[nx.Graph]],
|
|
621
|
+
pattern: nx.Graph,
|
|
622
|
+
*,
|
|
623
|
+
node_attrs: List[str],
|
|
624
|
+
edge_attrs: List[str],
|
|
625
|
+
k: Optional[int] = None,
|
|
626
|
+
strategy: Strategy = Strategy.COMPONENT,
|
|
627
|
+
max_results: Optional[int] = None,
|
|
628
|
+
partial: bool = True,
|
|
629
|
+
threshold: Optional[int] = None,
|
|
630
|
+
pre_filter: bool = False,
|
|
631
|
+
prune_auto: bool = False,
|
|
632
|
+
wl_max_iter: int = 10,
|
|
633
|
+
) -> List[MappingDict]:
|
|
634
|
+
"""Stateless convenience wrapper – one-liner for users in a hurry.
|
|
635
|
+
|
|
636
|
+
This mirrors the OO API but avoids explicitly instantiating the
|
|
637
|
+
matcher in user code.
|
|
638
|
+
|
|
639
|
+
:param host: A single host graph or a sequence of host graphs.
|
|
640
|
+
:type host: nx.Graph | Sequence[nx.Graph]
|
|
641
|
+
:param pattern: Pattern graph whose connected components are used
|
|
642
|
+
as building blocks.
|
|
643
|
+
:type pattern: nx.Graph
|
|
644
|
+
:param node_attrs: Node attribute keys to enforce equality on
|
|
645
|
+
during matching.
|
|
646
|
+
:type node_attrs: list[str]
|
|
647
|
+
:param edge_attrs: Edge attribute keys to enforce equality on
|
|
648
|
+
during matching.
|
|
649
|
+
:type edge_attrs: list[str]
|
|
650
|
+
:param k: If an integer, restricts the search to subsets of
|
|
651
|
+
exactly ``k`` pattern connected components. If ``None``,
|
|
652
|
+
behaviour follows the ``partial`` flag.
|
|
653
|
+
:type k: int | None
|
|
654
|
+
:param strategy: Matching strategy forwarded to
|
|
655
|
+
:class:`SubgraphSearchEngine`.
|
|
656
|
+
:type strategy: Strategy
|
|
657
|
+
:param max_results: Optional global cap on the number of
|
|
658
|
+
embeddings to return.
|
|
659
|
+
:type max_results: int | None
|
|
660
|
+
:param partial: If ``True``, all component counts are tried in
|
|
661
|
+
auto-mode. If ``False``, only the full pattern is used.
|
|
662
|
+
:type partial: bool
|
|
663
|
+
:param threshold: Optional per-(host, component) embedding cap
|
|
664
|
+
forwarded to :class:`SubgraphSearchEngine`.
|
|
665
|
+
:type threshold: int | None
|
|
666
|
+
:param pre_filter: Whether to enable the cheap pre-filter in
|
|
667
|
+
:class:`SubgraphSearchEngine`.
|
|
668
|
+
:type pre_filter: bool
|
|
669
|
+
:param prune_auto: If ``True``, apply WL-1-based approximate
|
|
670
|
+
automorphism pruning on the final mappings.
|
|
671
|
+
:type prune_auto: bool
|
|
672
|
+
:param wl_max_iter: Maximum number of WL iterations for the
|
|
673
|
+
internal :class:`AutoEst` if ``prune_auto`` is
|
|
674
|
+
enabled.
|
|
675
|
+
:type wl_max_iter: int
|
|
676
|
+
:return: Flat list of pattern→host node mappings.
|
|
677
|
+
:rtype: list[MappingDict]
|
|
678
|
+
"""
|
|
679
|
+
matcher = PartialMatcher(
|
|
680
|
+
host=host,
|
|
681
|
+
pattern=pattern,
|
|
682
|
+
node_attrs=node_attrs,
|
|
683
|
+
edge_attrs=edge_attrs,
|
|
684
|
+
strategy=strategy,
|
|
685
|
+
max_results=max_results,
|
|
686
|
+
partial=partial,
|
|
687
|
+
threshold=threshold,
|
|
688
|
+
pre_filter=pre_filter,
|
|
689
|
+
prune_auto=prune_auto,
|
|
690
|
+
wl_max_iter=wl_max_iter,
|
|
691
|
+
)
|
|
692
|
+
if k is not None:
|
|
693
|
+
return matcher._match_components(k)
|
|
694
|
+
return matcher.get_mappings()
|