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,186 @@
|
|
|
1
|
+
import networkx as nx
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from typing import Any, Dict, List, Set, Tuple, Union
|
|
4
|
+
from synkit.Graph.Matcher.turbo_iso import TurboISO
|
|
5
|
+
|
|
6
|
+
######################################################################
|
|
7
|
+
# MultiTurboISO – one global index for **N host graphs × M patterns**
|
|
8
|
+
######################################################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MultiTurboISO:
|
|
12
|
+
"""Accelerated sub-graph search across a batch of host graphs.
|
|
13
|
+
|
|
14
|
+
Builds a single global signature bucket over all hosts and reuses a
|
|
15
|
+
lightweight TurboISO matcher per host. For each query graph, hosts
|
|
16
|
+
are first pruned by a signature + degree filter, and then TurboISO’s
|
|
17
|
+
backtracking is run only on the surviving hosts.
|
|
18
|
+
|
|
19
|
+
:param hosts: List of host graphs to index.
|
|
20
|
+
:type hosts: List[nx.Graph]
|
|
21
|
+
:param node_label: Node attribute(s) used for signature matching.
|
|
22
|
+
:type node_label: str or list[str]
|
|
23
|
+
:param edge_label: Edge attribute(s) to match; pass None to ignore
|
|
24
|
+
edges.
|
|
25
|
+
:type edge_label: str or list[str] or None
|
|
26
|
+
:param distance_threshold: Skip distance filtering if candidate pool
|
|
27
|
+
is smaller.
|
|
28
|
+
:type distance_threshold: int
|
|
29
|
+
:return: An instance of MultiTurboISO with global index built.
|
|
30
|
+
:rtype: MultiTurboISO
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# --------------------------------------------------------------- init
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
hosts: List[nx.Graph],
|
|
37
|
+
node_label: Union[str, List[str]] = "label",
|
|
38
|
+
edge_label: Union[str, List[str], None] = None,
|
|
39
|
+
distance_threshold: int = 5000,
|
|
40
|
+
) -> None:
|
|
41
|
+
# normalise selectors ------------------------------------------------
|
|
42
|
+
self._node_attr = (
|
|
43
|
+
[node_label] if isinstance(node_label, str) else list(node_label)
|
|
44
|
+
)
|
|
45
|
+
self._edge_attr = (
|
|
46
|
+
[]
|
|
47
|
+
if edge_label is None
|
|
48
|
+
else [edge_label] if isinstance(edge_label, str) else list(edge_label)
|
|
49
|
+
)
|
|
50
|
+
self._dthr = distance_threshold
|
|
51
|
+
|
|
52
|
+
# store hosts & create one TurboISO per host ------------------------
|
|
53
|
+
|
|
54
|
+
self._hosts: List[nx.Graph] = hosts
|
|
55
|
+
self._matchers: List[TurboISO] = [
|
|
56
|
+
TurboISO(
|
|
57
|
+
h,
|
|
58
|
+
node_label=self._node_attr,
|
|
59
|
+
edge_label=self._edge_attr,
|
|
60
|
+
distance_threshold=distance_threshold,
|
|
61
|
+
)
|
|
62
|
+
for h in hosts
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
# global bucket: signature → {(host_idx, node)} ---------------------
|
|
66
|
+
self._bucket: Dict[Tuple[Any, ...], Set[Tuple[int, Any]]] = defaultdict(set)
|
|
67
|
+
for idx, m in enumerate(self._matchers):
|
|
68
|
+
for node, sig in m._sig.items():
|
|
69
|
+
self._bucket[sig].add((idx, node))
|
|
70
|
+
|
|
71
|
+
# degree maps for quick filtering -----------------------------------
|
|
72
|
+
self._deg: List[Dict[Any, int]] = [dict(H.degree()) for H in hosts]
|
|
73
|
+
|
|
74
|
+
# --------------------------------------------------------- repr / help
|
|
75
|
+
def __repr__(self) -> str:
|
|
76
|
+
return (
|
|
77
|
+
f"<MultiTurboISO hosts={len(self._hosts)} "
|
|
78
|
+
f"node_label={self._node_attr} edge_label={self._edge_attr} "
|
|
79
|
+
f"dthr={self._dthr}>"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def __help__(self) -> str: # for interactive use
|
|
83
|
+
return self.__doc__
|
|
84
|
+
|
|
85
|
+
# ----------------------------------------------------------- properties
|
|
86
|
+
@property
|
|
87
|
+
def hosts(self) -> List[nx.Graph]:
|
|
88
|
+
"""Return the list of host graphs."""
|
|
89
|
+
return self._hosts
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def num_hosts(self) -> int:
|
|
93
|
+
"""Number of host graphs indexed."""
|
|
94
|
+
return len(self._hosts)
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def node_label(self) -> List[str]:
|
|
98
|
+
"""Node‑attribute selector(s)."""
|
|
99
|
+
return list(self._node_attr)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def edge_label(self) -> List[str]:
|
|
103
|
+
"""Edge‑attribute selector(s).
|
|
104
|
+
|
|
105
|
+
Empty list means ‘ignore’.
|
|
106
|
+
"""
|
|
107
|
+
return list(self._edge_attr)
|
|
108
|
+
|
|
109
|
+
# -------------------------------------------------------------- helpers
|
|
110
|
+
def _node_sig(self, v: Any, G: nx.Graph) -> Tuple[Any, ...]:
|
|
111
|
+
if self._matchers:
|
|
112
|
+
return self._matchers[0]._node_signature(v, G)
|
|
113
|
+
return TurboISO(G, node_label=self._node_attr)._node_signature(v, G)
|
|
114
|
+
|
|
115
|
+
def _init_candidates(self, Q: nx.Graph) -> Dict[int, Dict[Any, Set[Any]]]:
|
|
116
|
+
"""Return per‑host candidate sets after signature + degree filter."""
|
|
117
|
+
cand: Dict[int, Dict[Any, Set[Any]]] = defaultdict(dict)
|
|
118
|
+
# (1) signature filter ------------------------------------------------
|
|
119
|
+
for q in Q.nodes:
|
|
120
|
+
sig = self._node_sig(q, Q)
|
|
121
|
+
for hidx, v in self._bucket.get(sig, ()): # O(1) bucket lookup
|
|
122
|
+
cand[hidx].setdefault(q, set()).add(v)
|
|
123
|
+
# (2) degree filter + host pruning -----------------------------------
|
|
124
|
+
qdeg = {q: Q.degree(q) for q in Q.nodes}
|
|
125
|
+
for hidx in list(cand.keys()):
|
|
126
|
+
cmap = cand[hidx]
|
|
127
|
+
if len(cmap) < len(Q): # missing some query nodes entirely
|
|
128
|
+
del cand[hidx]
|
|
129
|
+
continue
|
|
130
|
+
dmap = self._deg[hidx]
|
|
131
|
+
for q in Q.nodes:
|
|
132
|
+
vs = {v for v in cmap[q] if dmap[v] >= qdeg[q]}
|
|
133
|
+
if not vs: # prune host if any q has no candidates
|
|
134
|
+
del cand[hidx]
|
|
135
|
+
break
|
|
136
|
+
cmap[q] = vs
|
|
137
|
+
return cand
|
|
138
|
+
|
|
139
|
+
# -------------------------------------------------------------- search
|
|
140
|
+
def search_one(
|
|
141
|
+
self,
|
|
142
|
+
Q: nx.Graph,
|
|
143
|
+
*,
|
|
144
|
+
prune: bool = False,
|
|
145
|
+
) -> Dict[int, Union[bool, List[Dict[Any, Any]]]]:
|
|
146
|
+
"""Match a single pattern graph *Q* against every host.
|
|
147
|
+
|
|
148
|
+
:param Q: Query / pattern graph.
|
|
149
|
+
:type Q: nx.Graph
|
|
150
|
+
:param prune: Forwarded to TurboISO. If *True*, return just a boolean per
|
|
151
|
+
host (‘found?’), otherwise return the full list of mappings.
|
|
152
|
+
:type prune: bool, default False
|
|
153
|
+
|
|
154
|
+
:return: ``{host_idx: result}`` where *result* is *bool* if *prune* is
|
|
155
|
+
*True* else a list of node‑mapping dicts.
|
|
156
|
+
:rtype: dict
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
if not Q:
|
|
160
|
+
empty_result: Union[bool, List[Dict[Any, Any]]] = True if prune else [{}]
|
|
161
|
+
return {index: empty_result for index in range(len(self._hosts))}
|
|
162
|
+
|
|
163
|
+
host_cands = self._init_candidates(Q)
|
|
164
|
+
out: Dict[int, Union[bool, List[Dict[Any, Any]]]] = {}
|
|
165
|
+
for hidx, C in host_cands.items():
|
|
166
|
+
m: TurboISO = self._matchers[hidx]
|
|
167
|
+
original = m._init_candidates
|
|
168
|
+
m._init_candidates = lambda _Q: C # type: ignore
|
|
169
|
+
try:
|
|
170
|
+
out[hidx] = m.search(Q, prune=prune)
|
|
171
|
+
finally:
|
|
172
|
+
m._init_candidates = original
|
|
173
|
+
return out
|
|
174
|
+
|
|
175
|
+
def search_many(
|
|
176
|
+
self,
|
|
177
|
+
patterns: List[nx.Graph],
|
|
178
|
+
*,
|
|
179
|
+
prune: bool = False,
|
|
180
|
+
) -> List[Dict[int, Union[bool, List[Dict[Any, Any]]]]]:
|
|
181
|
+
"""Match a list of pattern graphs.
|
|
182
|
+
|
|
183
|
+
Returns a list of per‑pattern dictionaries in the same order as
|
|
184
|
+
the input list.
|
|
185
|
+
"""
|
|
186
|
+
return [self.search_one(p, prune=prune) for p in patterns]
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Dict, FrozenSet, Hashable, Iterable, List, Set
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OrbitAccuracy:
|
|
7
|
+
"""Compare two orbit partitions (approximate vs exact) and compute accuracy metrics.
|
|
8
|
+
|
|
9
|
+
The class is intentionally small and OOP-styled: most methods are chainable
|
|
10
|
+
(return ``self``) and computed results are exposed via properties.
|
|
11
|
+
|
|
12
|
+
:param approx_orbits: Iterable of frozenset-like objects (each containing node identifiers).
|
|
13
|
+
Each element represents one orbit (set of node ids) from the *approximate*
|
|
14
|
+
partition. The iterable is consumed and a *copy* (list of frozensets) is
|
|
15
|
+
stored internally.
|
|
16
|
+
:param exact_orbits: Iterable of frozenset-like objects (each containing node identifiers).
|
|
17
|
+
Each element represents one orbit from the *exact* partition.
|
|
18
|
+
|
|
19
|
+
:raises ValueError: If the union of nodes covered by the two partitions differs (i.e. they do
|
|
20
|
+
not refer to the same node set), a :class:`ValueError` is raised with a
|
|
21
|
+
short diagnostic listing nodes missing in either partition.
|
|
22
|
+
|
|
23
|
+
:ivar nodes: The set of all node identifiers (union of both partitions). Available
|
|
24
|
+
after initialization.
|
|
25
|
+
:vartype nodes: set
|
|
26
|
+
:ivar metrics: Computed metrics (see :meth:`compute`) exposed as a dictionary via the
|
|
27
|
+
:attr:`metrics` property.
|
|
28
|
+
:vartype metrics: dict
|
|
29
|
+
:ivar confusion_map: A mapping ``approx_orbit_index -> { exact_orbit_index: overlap_count }``
|
|
30
|
+
exposed via the :attr:`confusion_map` property.
|
|
31
|
+
|
|
32
|
+
:vartype confusion_map: dict
|
|
33
|
+
|
|
34
|
+
.. rubric:: Notes
|
|
35
|
+
|
|
36
|
+
- Node identifiers must be hashable (ints, str, ...).
|
|
37
|
+
- The input iterables are not modified; the class stores its own frozenset
|
|
38
|
+
copies.
|
|
39
|
+
- :meth:`compute` is chainable and returns ``self``; read metrics via the
|
|
40
|
+
:attr:`metrics` property.
|
|
41
|
+
|
|
42
|
+
.. rubric:: Examples
|
|
43
|
+
|
|
44
|
+
.. code-block:: python
|
|
45
|
+
|
|
46
|
+
approx = [frozenset({1}), frozenset({2, 3})]
|
|
47
|
+
exact = [frozenset({1}), frozenset({2, 3})]
|
|
48
|
+
|
|
49
|
+
oa = OrbitAccuracy(approx, exact).compute()
|
|
50
|
+
print(oa) # -> <OrbitAccuracy nodes=3 approx_orbits=2 exact_orbits=2>
|
|
51
|
+
print(oa.metrics) # -> {'node_exact_match_fraction': 1.0, ...}
|
|
52
|
+
print(oa.confusion_map) # -> {0: {0: 1}, 1: {1: 2}}
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
approx_orbits: Iterable[FrozenSet[Hashable]],
|
|
58
|
+
exact_orbits: Iterable[FrozenSet[Hashable]],
|
|
59
|
+
) -> None:
|
|
60
|
+
# store copies as frozensets to guarantee immutability semantics
|
|
61
|
+
self._approx_raw: List[FrozenSet[Hashable]] = [
|
|
62
|
+
frozenset(s) for s in approx_orbits
|
|
63
|
+
]
|
|
64
|
+
self._exact_raw: List[FrozenSet[Hashable]] = [
|
|
65
|
+
frozenset(s) for s in exact_orbits
|
|
66
|
+
]
|
|
67
|
+
self._validate()
|
|
68
|
+
self._build_mappings()
|
|
69
|
+
self._metrics: Dict[str, float] = {}
|
|
70
|
+
self._confusion: Dict[int, Dict[int, int]] = {}
|
|
71
|
+
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
return (
|
|
74
|
+
f"<OrbitAccuracy nodes={len(self.nodes)} "
|
|
75
|
+
f"approx_orbits={len(self._approx_raw)} exact_orbits={len(self._exact_raw)}>"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# ---- Convenience / help ----
|
|
79
|
+
def help(self) -> str:
|
|
80
|
+
"""Return a short usage/help string.
|
|
81
|
+
|
|
82
|
+
:return: Brief one-line instructions on how to use the class.
|
|
83
|
+
:rtype: str
|
|
84
|
+
"""
|
|
85
|
+
return (
|
|
86
|
+
"Instantiate with approx and exact orbit iterables of frozensets. "
|
|
87
|
+
"Call .compute() then read .metrics or .confusion_map."
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# ---- Internal validation / mapping builders ----
|
|
91
|
+
def _validate(self) -> None:
|
|
92
|
+
"""Ensure both partitions cover the same node set.
|
|
93
|
+
|
|
94
|
+
:raises ValueError: If the union of nodes in ``approx_orbits`` differs from that in
|
|
95
|
+
``exact_orbits``. The raised message includes nodes missing in
|
|
96
|
+
either partition for quick diagnostics.
|
|
97
|
+
"""
|
|
98
|
+
approx_nodes: Set[Hashable] = (
|
|
99
|
+
set().union(*self._approx_raw) if self._approx_raw else set()
|
|
100
|
+
)
|
|
101
|
+
exact_nodes: Set[Hashable] = (
|
|
102
|
+
set().union(*self._exact_raw) if self._exact_raw else set()
|
|
103
|
+
)
|
|
104
|
+
if approx_nodes != exact_nodes:
|
|
105
|
+
missing_in_approx = exact_nodes - approx_nodes
|
|
106
|
+
missing_in_exact = approx_nodes - exact_nodes
|
|
107
|
+
msg_parts = []
|
|
108
|
+
if missing_in_approx:
|
|
109
|
+
msg_parts.append(
|
|
110
|
+
"nodes missing in approx: " f"{sorted(missing_in_approx, key=repr)}"
|
|
111
|
+
)
|
|
112
|
+
if missing_in_exact:
|
|
113
|
+
msg_parts.append(
|
|
114
|
+
f"nodes missing in exact: {sorted(missing_in_exact, key=repr)}"
|
|
115
|
+
)
|
|
116
|
+
raise ValueError(
|
|
117
|
+
"Orbit partitions do not cover the same node set. "
|
|
118
|
+
+ " ".join(msg_parts)
|
|
119
|
+
)
|
|
120
|
+
self.nodes: Set[Hashable] = approx_nodes
|
|
121
|
+
|
|
122
|
+
def _build_mappings(self) -> None:
|
|
123
|
+
"""Build node -> orbit index mappings for both partitions (internal use)."""
|
|
124
|
+
self._node_to_approx: Dict[Hashable, int] = {}
|
|
125
|
+
self._node_to_exact: Dict[Hashable, int] = {}
|
|
126
|
+
for i, orb in enumerate(self._approx_raw):
|
|
127
|
+
for n in orb:
|
|
128
|
+
self._node_to_approx[n] = i
|
|
129
|
+
for j, orb in enumerate(self._exact_raw):
|
|
130
|
+
for n in orb:
|
|
131
|
+
self._node_to_exact[n] = j
|
|
132
|
+
|
|
133
|
+
# ---- Core API ----
|
|
134
|
+
def compute(self, brute_force_pairs: bool = True) -> "OrbitAccuracy":
|
|
135
|
+
"""Compute all metrics and build the confusion map.
|
|
136
|
+
|
|
137
|
+
This method is chainable and returns ``self``; call :attr:`metrics` or
|
|
138
|
+
:attr:`confusion_map` afterwards to access results.
|
|
139
|
+
|
|
140
|
+
:param brute_force_pairs: If True (default) compute pairwise accuracy by checking all unordered
|
|
141
|
+
node pairs (O(N^2)). For very large node sets a combinatorial
|
|
142
|
+
method (based on orbit sizes) may be preferred; this implementation
|
|
143
|
+
defaults to brute-force because typical orbit counts are moderate.
|
|
144
|
+
:type brute_force_pairs: bool, optional
|
|
145
|
+
|
|
146
|
+
:return: Returns ``self`` to enable chaining.
|
|
147
|
+
:rtype: OrbitAccuracy
|
|
148
|
+
"""
|
|
149
|
+
self._compute_node_exact_match_fraction()
|
|
150
|
+
self._compute_confusion()
|
|
151
|
+
self._compute_purity()
|
|
152
|
+
if brute_force_pairs:
|
|
153
|
+
self._compute_pairwise_accuracy_bruteforce()
|
|
154
|
+
else:
|
|
155
|
+
self._compute_pairwise_accuracy_combinatorial_fallback()
|
|
156
|
+
return self
|
|
157
|
+
|
|
158
|
+
def _compute_node_exact_match_fraction(self) -> None:
|
|
159
|
+
"""Compute fraction of nodes whose approx orbit exactly equals the exact orbit."""
|
|
160
|
+
correct = 0
|
|
161
|
+
for n in self.nodes:
|
|
162
|
+
approx_idx = self._node_to_approx[n]
|
|
163
|
+
exact_idx = self._node_to_exact[n]
|
|
164
|
+
if self._approx_raw[approx_idx] == self._exact_raw[exact_idx]:
|
|
165
|
+
correct += 1
|
|
166
|
+
total = len(self.nodes) or 1
|
|
167
|
+
self._metrics["node_exact_match_fraction"] = correct / total
|
|
168
|
+
|
|
169
|
+
def _compute_confusion(self) -> None:
|
|
170
|
+
"""Build confusion matrix as a dict: approx_idx -> { exact_idx: overlap_count }."""
|
|
171
|
+
conf: Dict[int, Dict[int, int]] = {}
|
|
172
|
+
for ai, aorb in enumerate(self._approx_raw):
|
|
173
|
+
row: Dict[int, int] = {}
|
|
174
|
+
for ej, eorb in enumerate(self._exact_raw):
|
|
175
|
+
inter = len(aorb & eorb)
|
|
176
|
+
if inter:
|
|
177
|
+
row[ej] = inter
|
|
178
|
+
conf[ai] = row
|
|
179
|
+
self._confusion = conf
|
|
180
|
+
|
|
181
|
+
def _compute_purity(self) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Compute purity: weighted average (by approx-orbit size) of the largest
|
|
184
|
+
overlap between each approx-orbit and any exact-orbit.
|
|
185
|
+
"""
|
|
186
|
+
total_nodes = len(self.nodes) or 1
|
|
187
|
+
weight_sum = 0
|
|
188
|
+
for ai, aorb in enumerate(self._approx_raw):
|
|
189
|
+
if not aorb:
|
|
190
|
+
continue
|
|
191
|
+
overlaps = self._confusion.get(ai, {})
|
|
192
|
+
best_overlap = max(overlaps.values()) if overlaps else 0
|
|
193
|
+
weight_sum += best_overlap
|
|
194
|
+
self._metrics["purity"] = weight_sum / total_nodes
|
|
195
|
+
|
|
196
|
+
def _compute_pairwise_accuracy_bruteforce(self) -> None:
|
|
197
|
+
"""Brute-force O(N^2) pairwise agreement calculation (same-orbit vs different-orbit)."""
|
|
198
|
+
nodes = list(self.nodes)
|
|
199
|
+
n = len(nodes)
|
|
200
|
+
if n < 2:
|
|
201
|
+
self._metrics["pairwise_accuracy"] = 1.0
|
|
202
|
+
return
|
|
203
|
+
matches = 0
|
|
204
|
+
total = 0
|
|
205
|
+
for i in range(n):
|
|
206
|
+
ni = nodes[i]
|
|
207
|
+
for j in range(i + 1, n):
|
|
208
|
+
nj = nodes[j]
|
|
209
|
+
approx_same = self._node_to_approx[ni] == self._node_to_approx[nj]
|
|
210
|
+
exact_same = self._node_to_exact[ni] == self._node_to_exact[nj]
|
|
211
|
+
if approx_same == exact_same:
|
|
212
|
+
matches += 1
|
|
213
|
+
total += 1
|
|
214
|
+
self._metrics["pairwise_accuracy"] = matches / total if total else 1.0
|
|
215
|
+
|
|
216
|
+
def _compute_pairwise_accuracy_combinatorial_fallback(self) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Placeholder for a combinatorial pairwise method (not implemented).
|
|
219
|
+
Currently delegates to the brute-force implementation.
|
|
220
|
+
"""
|
|
221
|
+
self._compute_pairwise_accuracy_bruteforce()
|
|
222
|
+
|
|
223
|
+
# ---- Properties / accessors ----
|
|
224
|
+
@property
|
|
225
|
+
def metrics(self) -> Dict[str, float]:
|
|
226
|
+
"""Return computed metrics.
|
|
227
|
+
|
|
228
|
+
:return: Copy of the metrics dictionary. Call :meth:`compute` first to populate.
|
|
229
|
+
:rtype: dict
|
|
230
|
+
"""
|
|
231
|
+
return dict(self._metrics)
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def confusion_map(self) -> Dict[int, Dict[int, int]]:
|
|
235
|
+
"""Return the confusion map: approx_orbit_index -> { exact_orbit_index: count }.
|
|
236
|
+
|
|
237
|
+
:return: Copy of the internal confusion mapping. Call :meth:`compute` first.
|
|
238
|
+
:rtype: dict
|
|
239
|
+
"""
|
|
240
|
+
# return a shallow copy to avoid accidental external mutation
|
|
241
|
+
return {k: dict(v) for k, v in self._confusion.items()}
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def approx_orbits(self) -> List[FrozenSet[Hashable]]:
|
|
245
|
+
"""Return the stored approx-orbits as a list of frozensets.
|
|
246
|
+
|
|
247
|
+
:return: Internal copy of the approximate orbit list.
|
|
248
|
+
:rtype: list
|
|
249
|
+
"""
|
|
250
|
+
return list(self._approx_raw)
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
def exact_orbits(self) -> List[FrozenSet[Hashable]]:
|
|
254
|
+
"""Return the stored exact-orbits as a list of frozensets.
|
|
255
|
+
|
|
256
|
+
:return: Internal copy of the exact orbit list.
|
|
257
|
+
:rtype: list
|
|
258
|
+
"""
|
|
259
|
+
return list(self._exact_raw)
|
|
260
|
+
|
|
261
|
+
# ---- Human-readable report ----
|
|
262
|
+
def report(self, max_rows: int = 10) -> str:
|
|
263
|
+
"""Produce a short human-readable report summarising computed metrics and the
|
|
264
|
+
top confusion rows.
|
|
265
|
+
|
|
266
|
+
:param max_rows: Maximum number of confusion rows to include in the textual report.
|
|
267
|
+
Default is 10.
|
|
268
|
+
:type max_rows: int, optional
|
|
269
|
+
|
|
270
|
+
:return: A multi-line string summarising the results. Call :meth:`compute`
|
|
271
|
+
before calling this method.
|
|
272
|
+
:rtype: str
|
|
273
|
+
"""
|
|
274
|
+
lines: List[str] = []
|
|
275
|
+
m = self.metrics
|
|
276
|
+
lines.append(repr(self))
|
|
277
|
+
lines.append("Metrics:")
|
|
278
|
+
for k in ("node_exact_match_fraction", "pairwise_accuracy", "purity"):
|
|
279
|
+
if k in m:
|
|
280
|
+
lines.append(f" {k}: {m[k]:.6f}")
|
|
281
|
+
lines.append("Top confusion rows (approx_orbit_idx -> {exact_idx:count}):")
|
|
282
|
+
for ai in sorted(self._confusion)[:max_rows]:
|
|
283
|
+
lines.append(f" {ai} -> {self._confusion[ai]}")
|
|
284
|
+
return "\n".join(lines)
|