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,967 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
6
|
+
|
|
7
|
+
import networkx as nx
|
|
8
|
+
|
|
9
|
+
from ._common import (
|
|
10
|
+
SymmetryConfig,
|
|
11
|
+
approx_automorphism_count_from_cells,
|
|
12
|
+
build_fast_signature,
|
|
13
|
+
edge_token,
|
|
14
|
+
graph_key_from_order,
|
|
15
|
+
hash_text,
|
|
16
|
+
node_token,
|
|
17
|
+
prepare_graph,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class _WLState:
|
|
23
|
+
"""
|
|
24
|
+
Internal cached WL state.
|
|
25
|
+
|
|
26
|
+
:param colors:
|
|
27
|
+
Final node colors after WL refinement.
|
|
28
|
+
:type colors: Dict[Any, str]
|
|
29
|
+
|
|
30
|
+
:param cells:
|
|
31
|
+
Final WL color cells as sorted node lists.
|
|
32
|
+
:type cells: List[List[Any]]
|
|
33
|
+
|
|
34
|
+
:param orbits:
|
|
35
|
+
Approximate node orbits induced by final WL colors.
|
|
36
|
+
:type orbits: List[Set[Any]]
|
|
37
|
+
|
|
38
|
+
:param color_hist:
|
|
39
|
+
Histogram of final colors.
|
|
40
|
+
:type color_hist: Dict[str, int]
|
|
41
|
+
|
|
42
|
+
:param iters_run:
|
|
43
|
+
Number of WL iterations actually performed.
|
|
44
|
+
:type iters_run: int
|
|
45
|
+
|
|
46
|
+
:param stabilized:
|
|
47
|
+
Whether refinement stabilized before the iteration limit.
|
|
48
|
+
:type stabilized: bool
|
|
49
|
+
|
|
50
|
+
:param canonical_order:
|
|
51
|
+
Deterministic node order induced by final WL colors.
|
|
52
|
+
:type canonical_order: List[Any]
|
|
53
|
+
|
|
54
|
+
:param approx_automorphism_count:
|
|
55
|
+
Approximate automorphism count derived from WL cells.
|
|
56
|
+
:type approx_automorphism_count: Optional[int]
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
colors: Dict[Any, str]
|
|
60
|
+
cells: List[List[Any]]
|
|
61
|
+
orbits: List[Set[Any]]
|
|
62
|
+
color_hist: Dict[str, int]
|
|
63
|
+
iters_run: int
|
|
64
|
+
stabilized: bool
|
|
65
|
+
canonical_order: List[Any]
|
|
66
|
+
approx_automorphism_count: Optional[int]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(frozen=True)
|
|
70
|
+
class WLCanonicalResult:
|
|
71
|
+
"""
|
|
72
|
+
Approximate canonicalization result from WL refinement.
|
|
73
|
+
|
|
74
|
+
This mirrors the exact canonicalizer style, but remains approximate.
|
|
75
|
+
|
|
76
|
+
:param canon_graph:
|
|
77
|
+
Graph canonically relabeled according to the WL order.
|
|
78
|
+
:type canon_graph: nx.DiGraph
|
|
79
|
+
|
|
80
|
+
:param graph_type:
|
|
81
|
+
Graph representation type, e.g. ``"bipartite"`` or ``"species"``.
|
|
82
|
+
:type graph_type: str
|
|
83
|
+
|
|
84
|
+
:param canonical_order:
|
|
85
|
+
Deterministic node order induced by the final WL partition.
|
|
86
|
+
:type canonical_order: List[Any]
|
|
87
|
+
|
|
88
|
+
:param canonical_key:
|
|
89
|
+
Canonical graph key derived from the WL order.
|
|
90
|
+
:type canonical_key: Any
|
|
91
|
+
|
|
92
|
+
:param automorphism_count:
|
|
93
|
+
Approximate automorphism count from WL cells.
|
|
94
|
+
:type automorphism_count: Optional[int]
|
|
95
|
+
|
|
96
|
+
:param orbits:
|
|
97
|
+
Approximate node orbits from the final WL cells.
|
|
98
|
+
:type orbits: List[Set[Any]]
|
|
99
|
+
|
|
100
|
+
:param colors:
|
|
101
|
+
Final WL color mapping.
|
|
102
|
+
:type colors: Dict[Any, str]
|
|
103
|
+
|
|
104
|
+
:param color_hist:
|
|
105
|
+
Histogram of final WL colors.
|
|
106
|
+
:type color_hist: Dict[str, int]
|
|
107
|
+
|
|
108
|
+
:param iters_run:
|
|
109
|
+
Number of WL iterations actually performed.
|
|
110
|
+
:type iters_run: int
|
|
111
|
+
|
|
112
|
+
:param stabilized:
|
|
113
|
+
Whether WL refinement stabilized before the maximum iteration count.
|
|
114
|
+
:type stabilized: bool
|
|
115
|
+
|
|
116
|
+
:param exact:
|
|
117
|
+
Always ``False`` for WL refinement.
|
|
118
|
+
:type exact: bool
|
|
119
|
+
|
|
120
|
+
:param elapsed_seconds:
|
|
121
|
+
Runtime in seconds for building the result object.
|
|
122
|
+
:type elapsed_seconds: float
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
canon_graph: nx.DiGraph
|
|
126
|
+
graph_type: str
|
|
127
|
+
canonical_order: List[Any]
|
|
128
|
+
canonical_key: Any
|
|
129
|
+
automorphism_count: Optional[int]
|
|
130
|
+
orbits: List[Set[Any]]
|
|
131
|
+
colors: Dict[Any, str]
|
|
132
|
+
color_hist: Dict[str, int]
|
|
133
|
+
iters_run: int
|
|
134
|
+
stabilized: bool
|
|
135
|
+
exact: bool
|
|
136
|
+
elapsed_seconds: float
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class WLCanonicalizer:
|
|
140
|
+
"""Fast approximate canonicalizer for SynKit CRN graphs using direction-aware
|
|
141
|
+
1-WL refinement.
|
|
142
|
+
|
|
143
|
+
This class is designed as a lightweight companion to the exact CRN
|
|
144
|
+
canonicalizer. It gives:
|
|
145
|
+
|
|
146
|
+
- deterministic WL-based canonical relabeling
|
|
147
|
+
- approximate orbit partitions
|
|
148
|
+
- approximate automorphism counts from WL cells
|
|
149
|
+
- fast signatures for cheap prefiltering
|
|
150
|
+
|
|
151
|
+
Compared with the exact canonicalizer, this class is much faster but not
|
|
152
|
+
guaranteed to distinguish all non-isomorphic graphs or recover exact
|
|
153
|
+
automorphism groups.
|
|
154
|
+
|
|
155
|
+
:param source:
|
|
156
|
+
Input CRN representation. This may be a prepared
|
|
157
|
+
:class:`networkx.DiGraph`, an object exposing ``to_digraph()``, or any
|
|
158
|
+
object accepted by :func:`prepare_graph`.
|
|
159
|
+
:type source: Any
|
|
160
|
+
|
|
161
|
+
:param include_rule:
|
|
162
|
+
Whether rule nodes should be included in the prepared graph.
|
|
163
|
+
:type include_rule: bool
|
|
164
|
+
|
|
165
|
+
:param include_stoich:
|
|
166
|
+
Whether stoichiometric edge attributes should be preserved during graph
|
|
167
|
+
preparation.
|
|
168
|
+
:type include_stoich: bool
|
|
169
|
+
|
|
170
|
+
:param n_iter:
|
|
171
|
+
Maximum number of WL refinement iterations.
|
|
172
|
+
:type n_iter: int
|
|
173
|
+
|
|
174
|
+
:param digest_size:
|
|
175
|
+
Digest size used when hashing node and edge signatures.
|
|
176
|
+
:type digest_size: int
|
|
177
|
+
|
|
178
|
+
:param include_in_neighbors:
|
|
179
|
+
Whether incoming neighbors should contribute to refinement.
|
|
180
|
+
:type include_in_neighbors: bool
|
|
181
|
+
|
|
182
|
+
:param include_out_neighbors:
|
|
183
|
+
Whether outgoing neighbors should contribute to refinement.
|
|
184
|
+
:type include_out_neighbors: bool
|
|
185
|
+
|
|
186
|
+
:param estimate_automorphisms:
|
|
187
|
+
Whether to compute an approximate automorphism count from the final WL
|
|
188
|
+
cells.
|
|
189
|
+
:type estimate_automorphisms: bool
|
|
190
|
+
|
|
191
|
+
:param automorphism_cap:
|
|
192
|
+
Cap applied to approximate automorphism counts.
|
|
193
|
+
:type automorphism_cap: int
|
|
194
|
+
|
|
195
|
+
:param config:
|
|
196
|
+
Symmetry semantics configuration controlling which node and edge
|
|
197
|
+
attributes participate in WL coloring.
|
|
198
|
+
:type config: Optional[SymmetryConfig]
|
|
199
|
+
|
|
200
|
+
.. rubric:: Example
|
|
201
|
+
|
|
202
|
+
.. code-block:: python
|
|
203
|
+
|
|
204
|
+
from synkit.CRN.Sym import WLCanonicalizer, SymmetryConfig
|
|
205
|
+
|
|
206
|
+
wl = WLCanonicalizer(
|
|
207
|
+
syn.to_digraph(),
|
|
208
|
+
include_rule=True,
|
|
209
|
+
config=SymmetryConfig.topological(),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
print(wl.has_nontrivial_automorphism())
|
|
213
|
+
print(wl.orbits())
|
|
214
|
+
print(wl.canonical_order())
|
|
215
|
+
print(wl.summary()["automorphism_count"])
|
|
216
|
+
"""
|
|
217
|
+
|
|
218
|
+
def __init__(
|
|
219
|
+
self,
|
|
220
|
+
source: Any,
|
|
221
|
+
*,
|
|
222
|
+
include_rule: bool = True,
|
|
223
|
+
include_stoich: bool = True,
|
|
224
|
+
n_iter: int = 20,
|
|
225
|
+
digest_size: int = 16,
|
|
226
|
+
include_in_neighbors: bool = True,
|
|
227
|
+
include_out_neighbors: bool = True,
|
|
228
|
+
estimate_automorphisms: bool = True,
|
|
229
|
+
automorphism_cap: int = 10**18,
|
|
230
|
+
config: Optional[SymmetryConfig] = None,
|
|
231
|
+
) -> None:
|
|
232
|
+
"""Initialize the WL canonicalizer.
|
|
233
|
+
|
|
234
|
+
:param source:
|
|
235
|
+
Input CRN representation.
|
|
236
|
+
:type source: Any
|
|
237
|
+
|
|
238
|
+
:param include_rule:
|
|
239
|
+
Whether rule nodes should be included in the prepared graph.
|
|
240
|
+
:type include_rule: bool
|
|
241
|
+
|
|
242
|
+
:param include_stoich:
|
|
243
|
+
Whether stoichiometric edge attributes should be preserved.
|
|
244
|
+
:type include_stoich: bool
|
|
245
|
+
|
|
246
|
+
:param n_iter:
|
|
247
|
+
Maximum number of WL refinement rounds.
|
|
248
|
+
:type n_iter: int
|
|
249
|
+
|
|
250
|
+
:param digest_size:
|
|
251
|
+
Digest size used when hashing WL signatures.
|
|
252
|
+
:type digest_size: int
|
|
253
|
+
|
|
254
|
+
:param include_in_neighbors:
|
|
255
|
+
Whether incoming neighborhoods should be used.
|
|
256
|
+
:type include_in_neighbors: bool
|
|
257
|
+
|
|
258
|
+
:param include_out_neighbors:
|
|
259
|
+
Whether outgoing neighborhoods should be used.
|
|
260
|
+
:type include_out_neighbors: bool
|
|
261
|
+
|
|
262
|
+
:param estimate_automorphisms:
|
|
263
|
+
Whether to estimate automorphism count from final WL cells.
|
|
264
|
+
:type estimate_automorphisms: bool
|
|
265
|
+
|
|
266
|
+
:param automorphism_cap:
|
|
267
|
+
Maximum cap for approximate automorphism counting.
|
|
268
|
+
:type automorphism_cap: int
|
|
269
|
+
|
|
270
|
+
:param config:
|
|
271
|
+
Symmetry semantics configuration.
|
|
272
|
+
:type config: Optional[SymmetryConfig]
|
|
273
|
+
|
|
274
|
+
:return:
|
|
275
|
+
None.
|
|
276
|
+
:rtype: None
|
|
277
|
+
|
|
278
|
+
.. rubric:: Example
|
|
279
|
+
|
|
280
|
+
.. code-block:: python
|
|
281
|
+
|
|
282
|
+
wl = WLCanonicalizer(
|
|
283
|
+
syn.to_digraph(),
|
|
284
|
+
include_rule=True,
|
|
285
|
+
n_iter=20,
|
|
286
|
+
digest_size=16,
|
|
287
|
+
)
|
|
288
|
+
"""
|
|
289
|
+
self.source = source
|
|
290
|
+
self.include_rule = bool(include_rule)
|
|
291
|
+
self.include_stoich = bool(include_stoich)
|
|
292
|
+
self.n_iter = int(n_iter)
|
|
293
|
+
self.digest_size = int(digest_size)
|
|
294
|
+
self.include_in_neighbors = bool(include_in_neighbors)
|
|
295
|
+
self.include_out_neighbors = bool(include_out_neighbors)
|
|
296
|
+
self.estimate_automorphisms = bool(estimate_automorphisms)
|
|
297
|
+
self.automorphism_cap = int(automorphism_cap)
|
|
298
|
+
self.config = config or SymmetryConfig.semantic()
|
|
299
|
+
|
|
300
|
+
self._G, self._graph_type = prepare_graph(
|
|
301
|
+
source,
|
|
302
|
+
include_rule=self.include_rule,
|
|
303
|
+
include_stoich=self.include_stoich,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
self._state_cache: Optional[_WLState] = None
|
|
307
|
+
self._summary_cache: Optional[WLCanonicalResult] = None
|
|
308
|
+
self._fast_signature: Optional[Tuple[Any, ...]] = None
|
|
309
|
+
self._cache_key_last: Optional[Tuple[Any, ...]] = None
|
|
310
|
+
|
|
311
|
+
def __repr__(self) -> str:
|
|
312
|
+
"""Return a concise representation.
|
|
313
|
+
|
|
314
|
+
:return:
|
|
315
|
+
String representation.
|
|
316
|
+
:rtype: str
|
|
317
|
+
|
|
318
|
+
.. rubric:: Example
|
|
319
|
+
|
|
320
|
+
.. code-block:: python
|
|
321
|
+
|
|
322
|
+
wl = WLCanonicalizer(syn)
|
|
323
|
+
print(wl)
|
|
324
|
+
"""
|
|
325
|
+
return (
|
|
326
|
+
f"WLCanonicalizer(include_rule={self.include_rule}, "
|
|
327
|
+
f"graph_type={self.graph_type}, n_iter={self.n_iter}, "
|
|
328
|
+
f"digest_size={self.digest_size})"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
@property
|
|
332
|
+
def G(self) -> nx.DiGraph:
|
|
333
|
+
"""Return the prepared graph.
|
|
334
|
+
|
|
335
|
+
:return:
|
|
336
|
+
Prepared directed graph.
|
|
337
|
+
:rtype: nx.DiGraph
|
|
338
|
+
|
|
339
|
+
.. rubric:: Example
|
|
340
|
+
|
|
341
|
+
.. code-block:: python
|
|
342
|
+
|
|
343
|
+
wl = WLCanonicalizer(syn)
|
|
344
|
+
print(wl.G.number_of_nodes(), wl.G.number_of_edges())
|
|
345
|
+
"""
|
|
346
|
+
return self._G
|
|
347
|
+
|
|
348
|
+
@property
|
|
349
|
+
def graph_type(self) -> str:
|
|
350
|
+
"""Return the graph representation type.
|
|
351
|
+
|
|
352
|
+
:return:
|
|
353
|
+
Graph representation type.
|
|
354
|
+
:rtype: str
|
|
355
|
+
|
|
356
|
+
.. rubric:: Example
|
|
357
|
+
|
|
358
|
+
.. code-block:: python
|
|
359
|
+
|
|
360
|
+
wl = WLCanonicalizer(syn, include_rule=True)
|
|
361
|
+
print(wl.graph_type)
|
|
362
|
+
"""
|
|
363
|
+
return self._graph_type
|
|
364
|
+
|
|
365
|
+
def _cache_key(self) -> Tuple[Any, ...]:
|
|
366
|
+
"""Build a conservative cache key for the current graph and parameters.
|
|
367
|
+
|
|
368
|
+
:return:
|
|
369
|
+
Cache key tuple.
|
|
370
|
+
:rtype: Tuple[Any, ...]
|
|
371
|
+
|
|
372
|
+
.. rubric:: Example
|
|
373
|
+
|
|
374
|
+
.. code-block:: python
|
|
375
|
+
|
|
376
|
+
wl = WLCanonicalizer(syn)
|
|
377
|
+
print(wl._cache_key())
|
|
378
|
+
"""
|
|
379
|
+
return (
|
|
380
|
+
id(self.G),
|
|
381
|
+
self.G.number_of_nodes(),
|
|
382
|
+
self.G.number_of_edges(),
|
|
383
|
+
self.include_rule,
|
|
384
|
+
self.include_stoich,
|
|
385
|
+
self.n_iter,
|
|
386
|
+
self.digest_size,
|
|
387
|
+
self.include_in_neighbors,
|
|
388
|
+
self.include_out_neighbors,
|
|
389
|
+
self.estimate_automorphisms,
|
|
390
|
+
self.automorphism_cap,
|
|
391
|
+
self.config,
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
def _node_seed(self, v: Any) -> str:
|
|
395
|
+
"""Compute the initial WL color for one node.
|
|
396
|
+
|
|
397
|
+
The seed combines the semantic node token and the directed degree.
|
|
398
|
+
|
|
399
|
+
:param v:
|
|
400
|
+
Node identifier.
|
|
401
|
+
:type v: Any
|
|
402
|
+
|
|
403
|
+
:return:
|
|
404
|
+
Initial hashed node color.
|
|
405
|
+
:rtype: str
|
|
406
|
+
"""
|
|
407
|
+
tok = node_token(self.G.nodes[v], self.config)
|
|
408
|
+
deg = (self.G.in_degree(v), self.G.out_degree(v))
|
|
409
|
+
return hash_text(f"N|{tok}|{deg}", digest_size=self.digest_size)
|
|
410
|
+
|
|
411
|
+
def _edge_sig(self, attrs: Dict[str, Any]) -> str:
|
|
412
|
+
"""Compute a hashed signature for one edge attribute dictionary.
|
|
413
|
+
|
|
414
|
+
:param attrs:
|
|
415
|
+
Edge attributes.
|
|
416
|
+
:type attrs: Dict[str, Any]
|
|
417
|
+
|
|
418
|
+
:return:
|
|
419
|
+
Hashed edge signature.
|
|
420
|
+
:rtype: str
|
|
421
|
+
"""
|
|
422
|
+
return hash_text(
|
|
423
|
+
f"E|{edge_token(attrs, self.config)}",
|
|
424
|
+
digest_size=self.digest_size,
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
def _edge_sig_between(self, u: Any, v: Any) -> str:
|
|
428
|
+
"""Return a stable signature for the edge between two nodes.
|
|
429
|
+
|
|
430
|
+
For multigraphs, the minimum signature over parallel edges is used to
|
|
431
|
+
keep the behavior deterministic.
|
|
432
|
+
|
|
433
|
+
:param u:
|
|
434
|
+
Source node.
|
|
435
|
+
:type u: Any
|
|
436
|
+
|
|
437
|
+
:param v:
|
|
438
|
+
Target node.
|
|
439
|
+
:type v: Any
|
|
440
|
+
|
|
441
|
+
:return:
|
|
442
|
+
Stable edge signature.
|
|
443
|
+
:rtype: str
|
|
444
|
+
"""
|
|
445
|
+
data = self.G.get_edge_data(u, v, default=None)
|
|
446
|
+
if data is None:
|
|
447
|
+
return self._edge_sig({})
|
|
448
|
+
|
|
449
|
+
if self.G.is_multigraph():
|
|
450
|
+
sigs: List[str] = []
|
|
451
|
+
if isinstance(data, dict):
|
|
452
|
+
for _, attrs in data.items():
|
|
453
|
+
if isinstance(attrs, dict):
|
|
454
|
+
sigs.append(self._edge_sig(attrs))
|
|
455
|
+
return min(sigs) if sigs else self._edge_sig({})
|
|
456
|
+
|
|
457
|
+
if isinstance(data, dict):
|
|
458
|
+
return self._edge_sig(data)
|
|
459
|
+
|
|
460
|
+
return self._edge_sig({})
|
|
461
|
+
|
|
462
|
+
def _neighbors_items(
|
|
463
|
+
self,
|
|
464
|
+
colors: Dict[Any, str],
|
|
465
|
+
v: Any,
|
|
466
|
+
*,
|
|
467
|
+
direction: str,
|
|
468
|
+
) -> List[str]:
|
|
469
|
+
"""Collect colored neighbor-edge descriptors for one node.
|
|
470
|
+
|
|
471
|
+
:param colors:
|
|
472
|
+
Current node colors.
|
|
473
|
+
:type colors: Dict[Any, str]
|
|
474
|
+
|
|
475
|
+
:param v:
|
|
476
|
+
Node identifier.
|
|
477
|
+
:type v: Any
|
|
478
|
+
|
|
479
|
+
:param direction:
|
|
480
|
+
Neighborhood direction, one of ``"in"``, ``"out"``, or ``"undir"``.
|
|
481
|
+
:type direction: str
|
|
482
|
+
|
|
483
|
+
:return:
|
|
484
|
+
Sorted color-edge descriptors.
|
|
485
|
+
:rtype: List[str]
|
|
486
|
+
"""
|
|
487
|
+
items: List[str] = []
|
|
488
|
+
|
|
489
|
+
if direction == "in":
|
|
490
|
+
if not self.G.is_directed():
|
|
491
|
+
direction = "undir"
|
|
492
|
+
else:
|
|
493
|
+
for u in self.G.predecessors(v):
|
|
494
|
+
items.append(f"{colors[u]}#{self._edge_sig_between(u, v)}")
|
|
495
|
+
|
|
496
|
+
if direction == "out":
|
|
497
|
+
if not self.G.is_directed():
|
|
498
|
+
direction = "undir"
|
|
499
|
+
else:
|
|
500
|
+
for u in self.G.successors(v):
|
|
501
|
+
items.append(f"{colors[u]}#{self._edge_sig_between(v, u)}")
|
|
502
|
+
|
|
503
|
+
if direction == "undir":
|
|
504
|
+
for u in self.G.neighbors(v):
|
|
505
|
+
es = self._edge_sig_between(v, u) if self.G.has_edge(v, u) else ""
|
|
506
|
+
if not es and self.G.has_edge(u, v):
|
|
507
|
+
es = self._edge_sig_between(u, v)
|
|
508
|
+
items.append(f"{colors[u]}#{es}")
|
|
509
|
+
|
|
510
|
+
items.sort()
|
|
511
|
+
return items
|
|
512
|
+
|
|
513
|
+
def _refine_once(self, colors: Dict[Any, str]) -> Dict[Any, str]:
|
|
514
|
+
"""Perform one WL refinement round.
|
|
515
|
+
|
|
516
|
+
:param colors:
|
|
517
|
+
Current node colors.
|
|
518
|
+
:type colors: Dict[Any, str]
|
|
519
|
+
|
|
520
|
+
:return:
|
|
521
|
+
Refined node colors.
|
|
522
|
+
:rtype: Dict[Any, str]
|
|
523
|
+
"""
|
|
524
|
+
new_colors: Dict[Any, str] = {}
|
|
525
|
+
|
|
526
|
+
for v in self.G.nodes():
|
|
527
|
+
parts: List[str] = [colors[v]]
|
|
528
|
+
|
|
529
|
+
if self.include_in_neighbors:
|
|
530
|
+
parts.append(
|
|
531
|
+
"IN["
|
|
532
|
+
+ "|".join(self._neighbors_items(colors, v, direction="in"))
|
|
533
|
+
+ "]"
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
if self.include_out_neighbors:
|
|
537
|
+
parts.append(
|
|
538
|
+
"OUT["
|
|
539
|
+
+ "|".join(self._neighbors_items(colors, v, direction="out"))
|
|
540
|
+
+ "]"
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
new_colors[v] = hash_text("||".join(parts), digest_size=self.digest_size)
|
|
544
|
+
|
|
545
|
+
return new_colors
|
|
546
|
+
|
|
547
|
+
@staticmethod
|
|
548
|
+
def _colors_equal(a: Dict[Any, str], b: Dict[Any, str]) -> bool:
|
|
549
|
+
"""Compare two color mappings exactly.
|
|
550
|
+
|
|
551
|
+
:param a:
|
|
552
|
+
First color mapping.
|
|
553
|
+
:type a: Dict[Any, str]
|
|
554
|
+
|
|
555
|
+
:param b:
|
|
556
|
+
Second color mapping.
|
|
557
|
+
:type b: Dict[Any, str]
|
|
558
|
+
|
|
559
|
+
:return:
|
|
560
|
+
``True`` if both mappings are identical.
|
|
561
|
+
:rtype: bool
|
|
562
|
+
"""
|
|
563
|
+
if a.keys() != b.keys():
|
|
564
|
+
return False
|
|
565
|
+
return all(a[k] == b[k] for k in a)
|
|
566
|
+
|
|
567
|
+
@staticmethod
|
|
568
|
+
def _buckets_from_colors(colors: Dict[Any, str]) -> Dict[str, List[Any]]:
|
|
569
|
+
"""Group nodes by final color.
|
|
570
|
+
|
|
571
|
+
:param colors:
|
|
572
|
+
Node-to-color mapping.
|
|
573
|
+
:type colors: Dict[Any, str]
|
|
574
|
+
|
|
575
|
+
:return:
|
|
576
|
+
Color buckets.
|
|
577
|
+
:rtype: Dict[str, List[Any]]
|
|
578
|
+
"""
|
|
579
|
+
buckets: Dict[str, List[Any]] = {}
|
|
580
|
+
for v, c in colors.items():
|
|
581
|
+
buckets.setdefault(c, []).append(v)
|
|
582
|
+
return buckets
|
|
583
|
+
|
|
584
|
+
@staticmethod
|
|
585
|
+
def _orbits_from_buckets(buckets: Dict[str, List[Any]]) -> List[Set[Any]]:
|
|
586
|
+
"""Build approximate orbit sets from color buckets.
|
|
587
|
+
|
|
588
|
+
:param buckets:
|
|
589
|
+
Color buckets.
|
|
590
|
+
:type buckets: Dict[str, List[Any]]
|
|
591
|
+
|
|
592
|
+
:return:
|
|
593
|
+
Approximate orbit sets.
|
|
594
|
+
:rtype: List[Set[Any]]
|
|
595
|
+
"""
|
|
596
|
+
items = sorted(buckets.items(), key=lambda kv: (kv[0], len(kv[1])))
|
|
597
|
+
out: List[Set[Any]] = []
|
|
598
|
+
for _, nodes in items:
|
|
599
|
+
out.append(set(sorted(nodes, key=str)))
|
|
600
|
+
return out
|
|
601
|
+
|
|
602
|
+
@staticmethod
|
|
603
|
+
def _canonical_order_from_colors(
|
|
604
|
+
G: nx.DiGraph,
|
|
605
|
+
colors: Dict[Any, str],
|
|
606
|
+
) -> List[Any]:
|
|
607
|
+
"""Build a deterministic node order from final colors.
|
|
608
|
+
|
|
609
|
+
:param G:
|
|
610
|
+
Input graph.
|
|
611
|
+
:type G: nx.DiGraph
|
|
612
|
+
|
|
613
|
+
:param colors:
|
|
614
|
+
Final color mapping.
|
|
615
|
+
:type colors: Dict[Any, str]
|
|
616
|
+
|
|
617
|
+
:return:
|
|
618
|
+
Deterministic canonical order.
|
|
619
|
+
:rtype: List[Any]
|
|
620
|
+
"""
|
|
621
|
+
return sorted(G.nodes(), key=lambda v: (colors[v], str(v)))
|
|
622
|
+
|
|
623
|
+
def _run(self) -> _WLState:
|
|
624
|
+
"""Run WL refinement once and cache the result.
|
|
625
|
+
|
|
626
|
+
:return:
|
|
627
|
+
Internal cached WL state.
|
|
628
|
+
:rtype: _WLState
|
|
629
|
+
|
|
630
|
+
.. rubric:: Example
|
|
631
|
+
|
|
632
|
+
.. code-block:: python
|
|
633
|
+
|
|
634
|
+
wl = WLCanonicalizer(syn)
|
|
635
|
+
state = wl._run()
|
|
636
|
+
print(state.iters_run, state.stabilized)
|
|
637
|
+
"""
|
|
638
|
+
key = self._cache_key()
|
|
639
|
+
if self._state_cache is not None and self._cache_key_last == key:
|
|
640
|
+
return self._state_cache
|
|
641
|
+
|
|
642
|
+
colors: Dict[Any, str] = {v: self._node_seed(v) for v in self.G.nodes()}
|
|
643
|
+
stabilized = False
|
|
644
|
+
iters_run = 0
|
|
645
|
+
|
|
646
|
+
for it in range(self.n_iter):
|
|
647
|
+
iters_run = it + 1
|
|
648
|
+
new_colors = self._refine_once(colors)
|
|
649
|
+
if self._colors_equal(new_colors, colors):
|
|
650
|
+
stabilized = True
|
|
651
|
+
colors = new_colors
|
|
652
|
+
break
|
|
653
|
+
colors = new_colors
|
|
654
|
+
|
|
655
|
+
buckets = self._buckets_from_colors(colors)
|
|
656
|
+
cells = [
|
|
657
|
+
sorted(nodes, key=str)
|
|
658
|
+
for _, nodes in sorted(
|
|
659
|
+
buckets.items(),
|
|
660
|
+
key=lambda kv: (kv[0], tuple(map(str, kv[1]))),
|
|
661
|
+
)
|
|
662
|
+
]
|
|
663
|
+
orbits = self._orbits_from_buckets(buckets)
|
|
664
|
+
color_hist = {c: len(nodes) for c, nodes in buckets.items()}
|
|
665
|
+
canonical_order = self._canonical_order_from_colors(self.G, colors)
|
|
666
|
+
|
|
667
|
+
approx_count: Optional[int] = None
|
|
668
|
+
if self.estimate_automorphisms:
|
|
669
|
+
approx_count = approx_automorphism_count_from_cells(
|
|
670
|
+
cells,
|
|
671
|
+
cap=self.automorphism_cap,
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
self._state_cache = _WLState(
|
|
675
|
+
colors=colors,
|
|
676
|
+
cells=cells,
|
|
677
|
+
orbits=orbits,
|
|
678
|
+
color_hist=color_hist,
|
|
679
|
+
iters_run=iters_run,
|
|
680
|
+
stabilized=stabilized,
|
|
681
|
+
canonical_order=canonical_order,
|
|
682
|
+
approx_automorphism_count=approx_count,
|
|
683
|
+
)
|
|
684
|
+
self._summary_cache = None
|
|
685
|
+
self._fast_signature = None
|
|
686
|
+
self._cache_key_last = key
|
|
687
|
+
return self._state_cache
|
|
688
|
+
|
|
689
|
+
def colors(self) -> Dict[Any, str]:
|
|
690
|
+
"""Return final WL colors.
|
|
691
|
+
|
|
692
|
+
:return:
|
|
693
|
+
Mapping from node to final color.
|
|
694
|
+
:rtype: Dict[Any, str]
|
|
695
|
+
|
|
696
|
+
.. rubric:: Example
|
|
697
|
+
|
|
698
|
+
.. code-block:: python
|
|
699
|
+
|
|
700
|
+
wl = WLCanonicalizer(syn)
|
|
701
|
+
print(wl.colors())
|
|
702
|
+
"""
|
|
703
|
+
return dict(self._run().colors)
|
|
704
|
+
|
|
705
|
+
def color_of(self, v: Any) -> str:
|
|
706
|
+
"""Return the final WL color of one node.
|
|
707
|
+
|
|
708
|
+
:param v:
|
|
709
|
+
Node identifier.
|
|
710
|
+
:type v: Any
|
|
711
|
+
|
|
712
|
+
:return:
|
|
713
|
+
Final WL color.
|
|
714
|
+
:rtype: str
|
|
715
|
+
|
|
716
|
+
.. rubric:: Example
|
|
717
|
+
|
|
718
|
+
.. code-block:: python
|
|
719
|
+
|
|
720
|
+
wl = WLCanonicalizer(syn)
|
|
721
|
+
print(wl.color_of(1))
|
|
722
|
+
"""
|
|
723
|
+
return self._run().colors[v]
|
|
724
|
+
|
|
725
|
+
def orbits(self) -> List[Set[Any]]:
|
|
726
|
+
"""Return approximate WL orbit sets.
|
|
727
|
+
|
|
728
|
+
:return:
|
|
729
|
+
Approximate orbits induced by final WL colors.
|
|
730
|
+
:rtype: List[Set[Any]]
|
|
731
|
+
|
|
732
|
+
.. rubric:: Example
|
|
733
|
+
|
|
734
|
+
.. code-block:: python
|
|
735
|
+
|
|
736
|
+
wl = WLCanonicalizer(syn)
|
|
737
|
+
print(wl.orbits())
|
|
738
|
+
"""
|
|
739
|
+
return [set(x) for x in self._run().orbits]
|
|
740
|
+
|
|
741
|
+
def wl_orbits(self) -> List[Set[Any]]:
|
|
742
|
+
"""Alias for :meth:`orbits`.
|
|
743
|
+
|
|
744
|
+
:return:
|
|
745
|
+
Approximate WL orbit sets.
|
|
746
|
+
:rtype: List[Set[Any]]
|
|
747
|
+
"""
|
|
748
|
+
return self.orbits()
|
|
749
|
+
|
|
750
|
+
def has_nontrivial_automorphism(self) -> bool:
|
|
751
|
+
"""Heuristically detect whether symmetry may be present.
|
|
752
|
+
|
|
753
|
+
This is approximate and simply checks whether any WL color cell has size
|
|
754
|
+
greater than one.
|
|
755
|
+
|
|
756
|
+
:return:
|
|
757
|
+
``True`` if WL detects a non-singleton cell, else ``False``.
|
|
758
|
+
:rtype: bool
|
|
759
|
+
|
|
760
|
+
.. rubric:: Example
|
|
761
|
+
|
|
762
|
+
.. code-block:: python
|
|
763
|
+
|
|
764
|
+
wl = WLCanonicalizer(syn)
|
|
765
|
+
print(wl.has_nontrivial_automorphism())
|
|
766
|
+
"""
|
|
767
|
+
return any(len(cell) > 1 for cell in self._run().cells)
|
|
768
|
+
|
|
769
|
+
def canonical_order(self) -> List[Any]:
|
|
770
|
+
"""Return the deterministic WL node order.
|
|
771
|
+
|
|
772
|
+
:return:
|
|
773
|
+
WL-based canonical node order.
|
|
774
|
+
:rtype: List[Any]
|
|
775
|
+
|
|
776
|
+
.. rubric:: Example
|
|
777
|
+
|
|
778
|
+
.. code-block:: python
|
|
779
|
+
|
|
780
|
+
wl = WLCanonicalizer(syn)
|
|
781
|
+
print(wl.canonical_order())
|
|
782
|
+
"""
|
|
783
|
+
return list(self._run().canonical_order)
|
|
784
|
+
|
|
785
|
+
def canonical_key(self) -> Any:
|
|
786
|
+
"""Return the canonical key induced by the WL order.
|
|
787
|
+
|
|
788
|
+
:return:
|
|
789
|
+
WL canonical key.
|
|
790
|
+
:rtype: Any
|
|
791
|
+
|
|
792
|
+
.. rubric:: Example
|
|
793
|
+
|
|
794
|
+
.. code-block:: python
|
|
795
|
+
|
|
796
|
+
wl = WLCanonicalizer(syn)
|
|
797
|
+
print(wl.canonical_key())
|
|
798
|
+
"""
|
|
799
|
+
return graph_key_from_order(self.G, self.canonical_order(), self.config)
|
|
800
|
+
|
|
801
|
+
def canonical_graph(self) -> nx.DiGraph:
|
|
802
|
+
"""Return the canonically relabeled graph using the WL order.
|
|
803
|
+
|
|
804
|
+
:return:
|
|
805
|
+
WL-canonically relabeled graph.
|
|
806
|
+
:rtype: nx.DiGraph
|
|
807
|
+
|
|
808
|
+
.. rubric:: Example
|
|
809
|
+
|
|
810
|
+
.. code-block:: python
|
|
811
|
+
|
|
812
|
+
wl = WLCanonicalizer(syn)
|
|
813
|
+
G_can = wl.canonical_graph()
|
|
814
|
+
print(sorted(G_can.nodes()))
|
|
815
|
+
"""
|
|
816
|
+
order = self.canonical_order()
|
|
817
|
+
mapping = {v: i + 1 for i, v in enumerate(order)}
|
|
818
|
+
return nx.relabel_nodes(self.G, mapping, copy=True)
|
|
819
|
+
|
|
820
|
+
def graph(self) -> nx.DiGraph:
|
|
821
|
+
"""Alias for :meth:`canonical_graph`, matching the older canon style.
|
|
822
|
+
|
|
823
|
+
:return:
|
|
824
|
+
WL-canonically relabeled graph.
|
|
825
|
+
:rtype: nx.DiGraph
|
|
826
|
+
|
|
827
|
+
.. rubric:: Example
|
|
828
|
+
|
|
829
|
+
.. code-block:: python
|
|
830
|
+
|
|
831
|
+
wl = WLCanonicalizer(syn)
|
|
832
|
+
G_can = wl.graph()
|
|
833
|
+
"""
|
|
834
|
+
return self.canonical_graph()
|
|
835
|
+
|
|
836
|
+
def canonical_result(self) -> WLCanonicalResult:
|
|
837
|
+
"""Build an approximate canonicalization result in a CRN-canon-like format.
|
|
838
|
+
|
|
839
|
+
:return:
|
|
840
|
+
Approximate canonicalization result.
|
|
841
|
+
:rtype: WLCanonicalResult
|
|
842
|
+
|
|
843
|
+
.. rubric:: Example
|
|
844
|
+
|
|
845
|
+
.. code-block:: python
|
|
846
|
+
|
|
847
|
+
wl = WLCanonicalizer(syn)
|
|
848
|
+
result = wl.canonical_result()
|
|
849
|
+
print(result.canonical_order)
|
|
850
|
+
print(result.automorphism_count)
|
|
851
|
+
"""
|
|
852
|
+
if self._summary_cache is not None:
|
|
853
|
+
return self._summary_cache
|
|
854
|
+
|
|
855
|
+
start = perf_counter()
|
|
856
|
+
state = self._run()
|
|
857
|
+
can_graph = self.canonical_graph()
|
|
858
|
+
can_key = graph_key_from_order(self.G, state.canonical_order, self.config)
|
|
859
|
+
|
|
860
|
+
self._summary_cache = WLCanonicalResult(
|
|
861
|
+
canon_graph=can_graph,
|
|
862
|
+
graph_type=self.graph_type,
|
|
863
|
+
canonical_order=list(state.canonical_order),
|
|
864
|
+
canonical_key=can_key,
|
|
865
|
+
automorphism_count=state.approx_automorphism_count,
|
|
866
|
+
orbits=[set(x) for x in state.orbits],
|
|
867
|
+
colors=dict(state.colors),
|
|
868
|
+
color_hist=dict(state.color_hist),
|
|
869
|
+
iters_run=state.iters_run,
|
|
870
|
+
stabilized=state.stabilized,
|
|
871
|
+
exact=False,
|
|
872
|
+
elapsed_seconds=perf_counter() - start,
|
|
873
|
+
)
|
|
874
|
+
return self._summary_cache
|
|
875
|
+
|
|
876
|
+
def summary(self) -> Dict[str, Any]:
|
|
877
|
+
"""Return a dictionary summary in a format close to the exact canonicalizer.
|
|
878
|
+
|
|
879
|
+
The reported automorphism count and orbit sets are WL-based
|
|
880
|
+
approximations.
|
|
881
|
+
|
|
882
|
+
:return:
|
|
883
|
+
Summary dictionary.
|
|
884
|
+
:rtype: Dict[str, Any]
|
|
885
|
+
|
|
886
|
+
.. rubric:: Example
|
|
887
|
+
|
|
888
|
+
.. code-block:: python
|
|
889
|
+
|
|
890
|
+
wl = WLCanonicalizer(syn)
|
|
891
|
+
info = wl.summary()
|
|
892
|
+
print(info["automorphism_count"])
|
|
893
|
+
print(info["orbits"])
|
|
894
|
+
"""
|
|
895
|
+
res = self.canonical_result()
|
|
896
|
+
return {
|
|
897
|
+
"canon_graph": res.canon_graph,
|
|
898
|
+
"graph_type": res.graph_type,
|
|
899
|
+
"automorphism_count": res.automorphism_count,
|
|
900
|
+
"orbits": res.orbits,
|
|
901
|
+
"canonical_perm": res.canonical_order,
|
|
902
|
+
"canonical_key": res.canonical_key,
|
|
903
|
+
"colors": res.colors,
|
|
904
|
+
"color_hist": res.color_hist,
|
|
905
|
+
"iters_run": res.iters_run,
|
|
906
|
+
"stabilized": res.stabilized,
|
|
907
|
+
"exact": res.exact,
|
|
908
|
+
"elapsed_seconds": res.elapsed_seconds,
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
def fast_signature(self) -> Tuple[Any, ...]:
|
|
912
|
+
"""Return a fast graph signature using graph statistics and WL color
|
|
913
|
+
histogram.
|
|
914
|
+
|
|
915
|
+
This is useful as a cheap prefilter before exact graph isomorphism or
|
|
916
|
+
exact canonicalization.
|
|
917
|
+
|
|
918
|
+
:return:
|
|
919
|
+
Fast graph signature.
|
|
920
|
+
:rtype: Tuple[Any, ...]
|
|
921
|
+
|
|
922
|
+
.. rubric:: Example
|
|
923
|
+
|
|
924
|
+
.. code-block:: python
|
|
925
|
+
|
|
926
|
+
wl = WLCanonicalizer(syn)
|
|
927
|
+
print(wl.fast_signature())
|
|
928
|
+
"""
|
|
929
|
+
if self._fast_signature is None:
|
|
930
|
+
state = self._run()
|
|
931
|
+
self._fast_signature = build_fast_signature(
|
|
932
|
+
self.G,
|
|
933
|
+
self.graph_type,
|
|
934
|
+
self.config,
|
|
935
|
+
wl_color_hist=state.color_hist,
|
|
936
|
+
)
|
|
937
|
+
return self._fast_signature
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
def wl_canonical(source: Any, **kwargs: Any) -> nx.DiGraph:
|
|
941
|
+
"""Convenience function returning the WL-canonically relabeled graph.
|
|
942
|
+
|
|
943
|
+
:param source:
|
|
944
|
+
Input CRN representation.
|
|
945
|
+
:type source: Any
|
|
946
|
+
|
|
947
|
+
:param kwargs:
|
|
948
|
+
Additional keyword arguments forwarded to :class:`WLCanonicalizer`.
|
|
949
|
+
:type kwargs: Any
|
|
950
|
+
|
|
951
|
+
:return:
|
|
952
|
+
WL-canonically relabeled graph.
|
|
953
|
+
:rtype: nx.DiGraph
|
|
954
|
+
|
|
955
|
+
.. rubric:: Example
|
|
956
|
+
|
|
957
|
+
.. code-block:: python
|
|
958
|
+
|
|
959
|
+
from synkit.CRN.Sym import SymmetryConfig, wl_canonical
|
|
960
|
+
|
|
961
|
+
G_can = wl_canonical(
|
|
962
|
+
syn.to_digraph(),
|
|
963
|
+
include_rule=True,
|
|
964
|
+
config=SymmetryConfig.topological(),
|
|
965
|
+
)
|
|
966
|
+
"""
|
|
967
|
+
return WLCanonicalizer(source, **kwargs).canonical_graph()
|