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,95 @@
|
|
|
1
|
+
"""Realize fixed-carrier material-port histories as coordinate histories."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
import networkx as nx
|
|
8
|
+
|
|
9
|
+
from .history import OccurrenceMTG
|
|
10
|
+
from .local import (
|
|
11
|
+
GroundedLocalEvent,
|
|
12
|
+
LocalCoordinateHistory,
|
|
13
|
+
LocalHistoryError,
|
|
14
|
+
build_local_coordinate_history,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _same_raw_world(first, second):
|
|
19
|
+
return (
|
|
20
|
+
first.schema == second.schema
|
|
21
|
+
and first.node_ids == second.node_ids
|
|
22
|
+
and first.edge_keys == second.edge_keys
|
|
23
|
+
and all(
|
|
24
|
+
first.node_labels(node, semantic=True)
|
|
25
|
+
== second.node_labels(node, semantic=True)
|
|
26
|
+
for node in first.node_ids
|
|
27
|
+
)
|
|
28
|
+
and all(
|
|
29
|
+
first.edge_labels(pair, semantic=True)
|
|
30
|
+
== second.edge_labels(pair, semantic=True)
|
|
31
|
+
for pair in first.edge_keys
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class CoordinateRealization:
|
|
38
|
+
"""Original copy bindings and their exact fixed-carrier source realization."""
|
|
39
|
+
|
|
40
|
+
source: OccurrenceMTG
|
|
41
|
+
history: LocalCoordinateHistory
|
|
42
|
+
|
|
43
|
+
def replay(self) -> bool:
|
|
44
|
+
"""Revalidate bindings, transported matches, order and realized prefix worlds."""
|
|
45
|
+
try:
|
|
46
|
+
return realize_coordinate_history(self.source) == self
|
|
47
|
+
except (ValueError, TypeError, KeyError):
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def realize_coordinate_history(source: OccurrenceMTG) -> CoordinateRealization:
|
|
52
|
+
"""Transport a supported material-port history into its persistent atom universe.
|
|
53
|
+
|
|
54
|
+
Every primitive rule must meet the unguarded fixed-carrier locality profile.
|
|
55
|
+
Declared port precedence is retained, and every extracted access dependency
|
|
56
|
+
must already be implied by that order. No copy binding, physical independence
|
|
57
|
+
or alternative mechanism is inferred. All canonical prefix worlds are checked
|
|
58
|
+
against the original occurrence construction.
|
|
59
|
+
|
|
60
|
+
:param source: A replayable material-port occurrence history.
|
|
61
|
+
:return: Original history and its anchored coordinate-poset realization.
|
|
62
|
+
:raises LocalHistoryError: If profile, order or prefix-world agreement fails.
|
|
63
|
+
"""
|
|
64
|
+
if not source.replay().valid:
|
|
65
|
+
raise LocalHistoryError("The material-port source history is not replayable.")
|
|
66
|
+
graph = source.to_process().causal_graph
|
|
67
|
+
order = tuple(nx.lexicographical_topological_sort(graph))
|
|
68
|
+
initial = source.configuration_cut(()).world
|
|
69
|
+
events = []
|
|
70
|
+
for event_id in order:
|
|
71
|
+
event = source.event_by_id[event_id]
|
|
72
|
+
match = {
|
|
73
|
+
rule_node: source.node_lineage_by_carrier[
|
|
74
|
+
binding.material_id, material_node
|
|
75
|
+
]
|
|
76
|
+
for binding in event.inputs
|
|
77
|
+
for rule_node, material_node in binding.mapping
|
|
78
|
+
}
|
|
79
|
+
events.append(GroundedLocalEvent(event_id, event.rule, match))
|
|
80
|
+
local = build_local_coordinate_history(initial, events, precedence=graph.edges)
|
|
81
|
+
if any(not nx.has_path(graph, a, b) for a, b in local.causal_pairs):
|
|
82
|
+
raise LocalHistoryError(
|
|
83
|
+
"The port order does not cover every grounded coordinate dependency."
|
|
84
|
+
)
|
|
85
|
+
completed = set()
|
|
86
|
+
if not _same_raw_world(initial, local.initial):
|
|
87
|
+
raise LocalHistoryError("The initial anchored worlds disagree.")
|
|
88
|
+
for record in local.records:
|
|
89
|
+
completed.add(record.event.event_id)
|
|
90
|
+
original = source.configuration_cut(completed).world
|
|
91
|
+
if not _same_raw_world(record.application.result, original):
|
|
92
|
+
raise LocalHistoryError(
|
|
93
|
+
"A realized source prefix has a different raw world."
|
|
94
|
+
)
|
|
95
|
+
return CoordinateRealization(source, local)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Optional exact series/parallel decomposition of an occurrence poset."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import itertools
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
import networkx as nx
|
|
9
|
+
|
|
10
|
+
from .process import OccurrenceProcess, ProcessError, ProcessIssue, ProcessIssueCode
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class SeriesParallelDecomposition:
|
|
15
|
+
"""A detected decomposition; absence never changes process semantics."""
|
|
16
|
+
|
|
17
|
+
kind: str
|
|
18
|
+
events: frozenset[str]
|
|
19
|
+
children: tuple["SeriesParallelDecomposition", ...] = ()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def detect_series_parallel(
|
|
23
|
+
process: OccurrenceProcess,
|
|
24
|
+
*,
|
|
25
|
+
max_partition_states: int = 100_000,
|
|
26
|
+
) -> SeriesParallelDecomposition | None:
|
|
27
|
+
"""Return an exact recursive decomposition or ``None`` for a general poset."""
|
|
28
|
+
if max_partition_states <= 0:
|
|
29
|
+
raise ValueError("max_partition_states must be positive.")
|
|
30
|
+
events = frozenset(process.event_by_id)
|
|
31
|
+
relation = set(process.causal_pairs)
|
|
32
|
+
explored = 0
|
|
33
|
+
|
|
34
|
+
def comparable(left: str, right: str) -> bool:
|
|
35
|
+
return (left, right) in relation or (right, left) in relation
|
|
36
|
+
|
|
37
|
+
def visit(current: frozenset[str]) -> SeriesParallelDecomposition | None:
|
|
38
|
+
nonlocal explored
|
|
39
|
+
explored += 1
|
|
40
|
+
if explored > max_partition_states:
|
|
41
|
+
raise ProcessError(
|
|
42
|
+
ProcessIssue(
|
|
43
|
+
ProcessIssueCode.SERIES_PARALLEL_LIMIT,
|
|
44
|
+
"Series/parallel detection exceeded its explicit partition bound.",
|
|
45
|
+
{"limit": max_partition_states},
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
if len(current) <= 1:
|
|
49
|
+
return SeriesParallelDecomposition("event", current)
|
|
50
|
+
|
|
51
|
+
comparability = nx.Graph()
|
|
52
|
+
comparability.add_nodes_from(current)
|
|
53
|
+
comparability.add_edges_from(
|
|
54
|
+
(left, right)
|
|
55
|
+
for left in current
|
|
56
|
+
for right in current
|
|
57
|
+
if repr(left) < repr(right) and comparable(left, right)
|
|
58
|
+
)
|
|
59
|
+
components = tuple(
|
|
60
|
+
frozenset(component) for component in nx.connected_components(comparability)
|
|
61
|
+
)
|
|
62
|
+
if len(components) > 1:
|
|
63
|
+
children = tuple(visit(component) for component in components)
|
|
64
|
+
if all(child is not None for child in children):
|
|
65
|
+
return SeriesParallelDecomposition(
|
|
66
|
+
"parallel",
|
|
67
|
+
current,
|
|
68
|
+
tuple(child for child in children if child is not None),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
ordered = tuple(sorted(current, key=repr))
|
|
72
|
+
anchor = ordered[0]
|
|
73
|
+
for size in range(1, len(ordered)):
|
|
74
|
+
for selected in itertools.combinations(ordered[1:], size - 1):
|
|
75
|
+
explored += 1
|
|
76
|
+
if explored > max_partition_states:
|
|
77
|
+
raise ProcessError(
|
|
78
|
+
ProcessIssue(
|
|
79
|
+
ProcessIssueCode.SERIES_PARALLEL_LIMIT,
|
|
80
|
+
"Series/parallel detection exceeded its partition bound.",
|
|
81
|
+
{"limit": max_partition_states},
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
first = frozenset((anchor, *selected))
|
|
85
|
+
second = current - first
|
|
86
|
+
orientations = (
|
|
87
|
+
all(
|
|
88
|
+
(left, right) in relation for left in first for right in second
|
|
89
|
+
),
|
|
90
|
+
all(
|
|
91
|
+
(right, left) in relation for left in first for right in second
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
if not any(orientations):
|
|
95
|
+
continue
|
|
96
|
+
lower, upper = (first, second) if orientations[0] else (second, first)
|
|
97
|
+
lower_tree, upper_tree = visit(lower), visit(upper)
|
|
98
|
+
if lower_tree is not None and upper_tree is not None:
|
|
99
|
+
return SeriesParallelDecomposition(
|
|
100
|
+
"series", current, (lower_tree, upper_tree)
|
|
101
|
+
)
|
|
102
|
+
return None
|
|
103
|
+
|
|
104
|
+
return visit(events)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
__all__ = ["SeriesParallelDecomposition", "detect_series_parallel"]
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import networkx as nx
|
|
2
|
+
import copy
|
|
3
|
+
from typing import Tuple, Any, Optional, Sequence, Set, Union
|
|
4
|
+
|
|
5
|
+
OrderPair = Tuple[float, float]
|
|
6
|
+
MissingOrder = Tuple[Set[float], Set[float]]
|
|
7
|
+
|
|
8
|
+
GraphType = Union[nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
|
9
|
+
TypesGHTuple = Tuple[Any, ...] # e.g., ('H', 0, 0, 0, ['C'])
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _extract_leaf_candidates(orig_th: Tuple[Any, ...]) -> Tuple[TypesGHTuple, ...]:
|
|
13
|
+
"""
|
|
14
|
+
Flatten one level: if an element is a sequence whose elements are themselves sequences,
|
|
15
|
+
treat those inner sequences as candidates; otherwise the element itself is a candidate.
|
|
16
|
+
"""
|
|
17
|
+
candidates: list[TypesGHTuple] = []
|
|
18
|
+
for item in orig_th:
|
|
19
|
+
if (
|
|
20
|
+
isinstance(item, (list, tuple))
|
|
21
|
+
and item
|
|
22
|
+
and all(isinstance(inner, (list, tuple)) for inner in item)
|
|
23
|
+
):
|
|
24
|
+
# e.g., (('H',...), ('H',...)) -> take inner tuples
|
|
25
|
+
for inner in item:
|
|
26
|
+
if isinstance(inner, (list, tuple)):
|
|
27
|
+
candidates.append(tuple(inner))
|
|
28
|
+
else:
|
|
29
|
+
if isinstance(item, (list, tuple)):
|
|
30
|
+
candidates.append(tuple(item))
|
|
31
|
+
else:
|
|
32
|
+
# non-sequence fallback, wrap to tuple for uniformity
|
|
33
|
+
candidates.append((item,))
|
|
34
|
+
return tuple(candidates)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def normalize_hcount_and_typesGH(G: GraphType) -> GraphType:
|
|
38
|
+
"""Return a fresh copy of G where:
|
|
39
|
+
* each node's `hcount` attribute is set to 0
|
|
40
|
+
* each node's `typesGH` is processed as follows:
|
|
41
|
+
1. Flatten one level so that nested tuples-of-tuples are expanded.
|
|
42
|
+
2. Drop any tuple that contains a `set` anywhere.
|
|
43
|
+
3. From the remaining tuples, keep only the first and last (if more than two).
|
|
44
|
+
4. Zero indices 1 and 2 in each kept tuple (if they exist).
|
|
45
|
+
5. If nothing remains after dropping, result is an empty tuple.
|
|
46
|
+
|
|
47
|
+
:param G: input NetworkX graph
|
|
48
|
+
:type G: nx.Graph or nx.DiGraph or nx.MultiGraph or nx.MultiDiGraph
|
|
49
|
+
:return: a new graph with normalized hcount and typesGH
|
|
50
|
+
:rtype: same type as G
|
|
51
|
+
:raises TypeError: If G is not a supported NetworkX graph or if typesGH is malformed.
|
|
52
|
+
"""
|
|
53
|
+
if not isinstance(G, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)):
|
|
54
|
+
raise TypeError(f"Expected a NetworkX graph, got {type(G)!r}")
|
|
55
|
+
|
|
56
|
+
H = G.__class__()
|
|
57
|
+
H.graph.update(copy.deepcopy(G.graph))
|
|
58
|
+
|
|
59
|
+
for node, data in G.nodes(data=True):
|
|
60
|
+
new_data = data.copy()
|
|
61
|
+
new_data["hcount"] = 0
|
|
62
|
+
|
|
63
|
+
orig_th = data.get("typesGH", ())
|
|
64
|
+
if not isinstance(orig_th, (list, tuple)):
|
|
65
|
+
raise TypeError(
|
|
66
|
+
f"Node {node} has typesGH of unexpected type {type(orig_th)}; expected sequence"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Step 1: flatten one level of nested tuples-of-tuples
|
|
70
|
+
candidates = _extract_leaf_candidates(tuple(orig_th))
|
|
71
|
+
|
|
72
|
+
# Step 2: drop any tuple containing a set
|
|
73
|
+
filtered = [
|
|
74
|
+
t for t in candidates if not any(isinstance(elem, set) for elem in t)
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
# Step 3: select first and last (or whatever remains)
|
|
78
|
+
if not filtered:
|
|
79
|
+
selected: Tuple[TypesGHTuple, ...] = ()
|
|
80
|
+
elif len(filtered) > 2:
|
|
81
|
+
selected = (filtered[0], filtered[-1])
|
|
82
|
+
else:
|
|
83
|
+
selected = tuple(filtered) # 1 or 2 elements
|
|
84
|
+
|
|
85
|
+
# Step 4: zero indices 1 and 2
|
|
86
|
+
normalized: list[TypesGHTuple] = []
|
|
87
|
+
for inner in selected:
|
|
88
|
+
if not isinstance(inner, (list, tuple)):
|
|
89
|
+
raise TypeError(
|
|
90
|
+
f"Inner element of typesGH for node {node} is not tuple-like: {inner!r}"
|
|
91
|
+
)
|
|
92
|
+
inner_list = list(inner)
|
|
93
|
+
if len(inner_list) > 1:
|
|
94
|
+
inner_list[1] = 0
|
|
95
|
+
if len(inner_list) > 2:
|
|
96
|
+
inner_list[2] = 0
|
|
97
|
+
normalized.append(tuple(inner_list))
|
|
98
|
+
|
|
99
|
+
new_data["typesGH"] = tuple(normalized)
|
|
100
|
+
H.add_node(node, **new_data)
|
|
101
|
+
|
|
102
|
+
# Copy edges appropriately
|
|
103
|
+
if G.is_multigraph():
|
|
104
|
+
for u, v, key, edata in G.edges(keys=True, data=True):
|
|
105
|
+
H.add_edge(u, v, key=key, **copy.deepcopy(edata))
|
|
106
|
+
else:
|
|
107
|
+
for u, v, edata in G.edges(data=True):
|
|
108
|
+
H.add_edge(u, v, **copy.deepcopy(edata))
|
|
109
|
+
|
|
110
|
+
return H
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def extract_order_norm(
|
|
114
|
+
order_sequence: Sequence[Union[OrderPair, MissingOrder]],
|
|
115
|
+
) -> Optional[OrderPair]:
|
|
116
|
+
"""Extract a normalized bond-order pair from orders and placeholders.
|
|
117
|
+
|
|
118
|
+
The left value is taken from the first non-placeholder pair. The right value
|
|
119
|
+
is taken from the last non-placeholder pair.
|
|
120
|
+
|
|
121
|
+
The input sequence must have length >= 2.
|
|
122
|
+
|
|
123
|
+
:param order_sequence: Sequence of order tuples or placeholders.
|
|
124
|
+
:type order_sequence: Sequence[tuple[float, float]] or Sequence[MissingOrder]
|
|
125
|
+
:return: Pair ``(left, right)`` if found; otherwise ``None``.
|
|
126
|
+
:rtype: tuple[float, float] or None
|
|
127
|
+
:raises ValueError: If the sequence contains fewer than two items.
|
|
128
|
+
|
|
129
|
+
.. rubric:: Examples
|
|
130
|
+
|
|
131
|
+
>>> seq = [({1}, {2}), (3.0, 4.0), ({5}, {6}), (7.0, 8.0)]
|
|
132
|
+
>>> extract_order_norm(seq)
|
|
133
|
+
(3.0, 8.0)
|
|
134
|
+
"""
|
|
135
|
+
if not isinstance(order_sequence, Sequence) or len(order_sequence) < 2:
|
|
136
|
+
raise ValueError("order_sequence must be a sequence of length >= 2")
|
|
137
|
+
|
|
138
|
+
left: Any = None
|
|
139
|
+
right: Any = None
|
|
140
|
+
# Find first non-placeholder for left
|
|
141
|
+
for entry in order_sequence:
|
|
142
|
+
a, b = entry
|
|
143
|
+
if not (isinstance(a, set) and isinstance(b, set)):
|
|
144
|
+
left = a
|
|
145
|
+
break
|
|
146
|
+
# Find last non-placeholder for right
|
|
147
|
+
for entry in reversed(order_sequence):
|
|
148
|
+
a, b = entry
|
|
149
|
+
if not (isinstance(a, set) and isinstance(b, set)):
|
|
150
|
+
right = b
|
|
151
|
+
break
|
|
152
|
+
if left is not None and right is not None:
|
|
153
|
+
return (left, right)
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def normalize_order(G: nx.Graph) -> nx.Graph:
|
|
158
|
+
"""Return a copy of the graph with each edge's 'order' attribute normalized.
|
|
159
|
+
If an edge has an 'order' attribute that is a sequence of length >= 2,
|
|
160
|
+
it is replaced by the 2-tuple returned by :func:`extract_order_norm`,
|
|
161
|
+
if that function returns a non-None result.
|
|
162
|
+
|
|
163
|
+
:param G: Input NetworkX graph
|
|
164
|
+
:type G: nx.Graph, nx.DiGraph, nx.MultiGraph, or nx.MultiDiGraph
|
|
165
|
+
:return: A new graph of the same type with normalized edge 'order'
|
|
166
|
+
:rtype: same as G
|
|
167
|
+
:raises TypeError: If G is not a NetworkX graph
|
|
168
|
+
|
|
169
|
+
.. rubric:: Examples
|
|
170
|
+
|
|
171
|
+
>>> import networkx as nx
|
|
172
|
+
>>> G = nx.Graph()
|
|
173
|
+
>>> G.add_edge(1, 2, order=[(1,2), ({3},{4}), (5,6)])
|
|
174
|
+
>>> H = normalize_order(G)
|
|
175
|
+
>>> H.edges[1,2]['order']
|
|
176
|
+
(1, 6)
|
|
177
|
+
"""
|
|
178
|
+
from copy import deepcopy
|
|
179
|
+
|
|
180
|
+
if not isinstance(G, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)):
|
|
181
|
+
raise TypeError(f"Expected a NetworkX graph, got {type(G)}")
|
|
182
|
+
|
|
183
|
+
H = deepcopy(G)
|
|
184
|
+
# Iterate edges appropriately
|
|
185
|
+
if H.is_multigraph():
|
|
186
|
+
edge_iter = H.edges(keys=True, data=True)
|
|
187
|
+
for _, _, _, attr in edge_iter:
|
|
188
|
+
order = attr.get("order")
|
|
189
|
+
if isinstance(order, (list, tuple)) and len(order) >= 2:
|
|
190
|
+
norm = extract_order_norm(order)
|
|
191
|
+
if norm is not None:
|
|
192
|
+
attr["order"] = norm
|
|
193
|
+
else:
|
|
194
|
+
for _, _, attr in H.edges(data=True):
|
|
195
|
+
order = attr.get("order")
|
|
196
|
+
if isinstance(order, (list, tuple)) and len(order) >= 2:
|
|
197
|
+
norm = extract_order_norm(order)
|
|
198
|
+
if norm is not None:
|
|
199
|
+
attr["order"] = norm
|
|
200
|
+
return H
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# def normalize_hcount_and_typesGH(G):
|
|
204
|
+
# """
|
|
205
|
+
# Return a fresh copy of G where:
|
|
206
|
+
# - each node's `hcount` attribute is set to 0
|
|
207
|
+
# - in each tuple of `typesGH`, indices 1 and 2 are set to 0
|
|
208
|
+
|
|
209
|
+
# :param G: input NetworkX graph
|
|
210
|
+
# :type G: nx.Graph or nx.DiGraph or nx.MultiGraph or nx.MultiDiGraph
|
|
211
|
+
# :returns: a new graph with normalized hcount and typesGH
|
|
212
|
+
# :rtype: same type as G
|
|
213
|
+
# :raises: TypeError if G is not a NetworkX graph
|
|
214
|
+
|
|
215
|
+
# :example:
|
|
216
|
+
# >>> G = nx.Graph()
|
|
217
|
+
# >>> G.add_node(1, hcount=2, typesGH=(("C", 1, 2), ("O", 0, 1)))
|
|
218
|
+
# >>> H = normalize_hcount_and_typesGH(G)
|
|
219
|
+
# >>> H.nodes[1]['hcount']
|
|
220
|
+
# 0
|
|
221
|
+
# >>> H.nodes[1]['typesGH']
|
|
222
|
+
# (('C', 0, 0), ('O', 0, 0))
|
|
223
|
+
# """
|
|
224
|
+
# if not isinstance(G, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)):
|
|
225
|
+
# raise TypeError(f"Expected NetworkX graph, got {type(G)}")
|
|
226
|
+
|
|
227
|
+
# # Create empty graph of same class and copy graph-level attributes
|
|
228
|
+
# H = G.__class__()
|
|
229
|
+
# H.graph.update(copy.deepcopy(G.graph))
|
|
230
|
+
|
|
231
|
+
# # Copy and normalize node data
|
|
232
|
+
# for node, data in G.nodes(data=True):
|
|
233
|
+
# new_data = data.copy()
|
|
234
|
+
# new_data["hcount"] = 0
|
|
235
|
+
# orig_th = data.get("typesGH", ())
|
|
236
|
+
# new_th = []
|
|
237
|
+
# for inner in orig_th:
|
|
238
|
+
# inner_list = list(inner)
|
|
239
|
+
# # Zero the aromatic slot (index 1) and the hcountGH slot (index 2)
|
|
240
|
+
# if len(inner_list) > 1:
|
|
241
|
+
# inner_list[1] = 0
|
|
242
|
+
# if len(inner_list) > 2:
|
|
243
|
+
# inner_list[2] = 0
|
|
244
|
+
# new_th.append(tuple(inner_list))
|
|
245
|
+
# new_data["typesGH"] = tuple(new_th)
|
|
246
|
+
# H.add_node(node, **new_data)
|
|
247
|
+
|
|
248
|
+
# # Copy edges (with keys for multigraphs)
|
|
249
|
+
# if G.is_multigraph():
|
|
250
|
+
# for u, v, key, edata in G.edges(keys=True, data=True):
|
|
251
|
+
# H.add_edge(u, v, key=key, **copy.deepcopy(edata))
|
|
252
|
+
# else:
|
|
253
|
+
# for u, v, edata in G.edges(data=True):
|
|
254
|
+
# H.add_edge(u, v, **copy.deepcopy(edata))
|
|
255
|
+
|
|
256
|
+
# return H
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def label_mtg_edges(G: nx.Graph, inplace: bool = False) -> nx.Graph:
|
|
260
|
+
"""Label each edge in the MTG graph with a boolean 'is_mtg' attribute based on two criteria:
|
|
261
|
+
1. There are at least two steps where the standard order (order[0] - order[1]) is non-zero.
|
|
262
|
+
2. The sum of all non-None standard orders is zero.
|
|
263
|
+
|
|
264
|
+
:param G: Input MTG graph with 'order' history per edge
|
|
265
|
+
:type G: nx.Graph or nx.DiGraph
|
|
266
|
+
:param inplace: If True, modify G in place; otherwise work on a copy
|
|
267
|
+
:type inplace: bool
|
|
268
|
+
:return: Graph with 'is_mtg' boolean attribute on each edge
|
|
269
|
+
:rtype: same type as G
|
|
270
|
+
:raises TypeError: If G is not a NetworkX Graph
|
|
271
|
+
|
|
272
|
+
.. rubric:: Examples
|
|
273
|
+
|
|
274
|
+
>>> import networkx as nx
|
|
275
|
+
>>> G = nx.Graph()
|
|
276
|
+
>>> # Single change only -> less than 2 non-zero steps => False
|
|
277
|
+
>>> G.add_edge(7,3, order=((1.0,1.0),(1.0,0)))
|
|
278
|
+
>>> H = label_mtg_edges(G)
|
|
279
|
+
>>> H.edges[7,3]['is_mtg']
|
|
280
|
+
False
|
|
281
|
+
>>> # Two-step equal but opposite changes -> sum zero and count>=2 => True
|
|
282
|
+
>>> G = nx.Graph()
|
|
283
|
+
>>> G.add_edge(2,1, order=((1.0,2.0),(2.0,1.0)))
|
|
284
|
+
>>> H = label_mtg_edges(G)
|
|
285
|
+
>>> H.edges[2,1]['is_mtg']
|
|
286
|
+
True
|
|
287
|
+
"""
|
|
288
|
+
if not isinstance(G, (nx.Graph, nx.DiGraph)):
|
|
289
|
+
raise TypeError(f"Expected a NetworkX Graph, got {type(G)}")
|
|
290
|
+
graph = G if inplace else G.copy()
|
|
291
|
+
for u, v, attr in graph.edges(data=True):
|
|
292
|
+
history = attr.get("order")
|
|
293
|
+
# Extract numeric standard orders
|
|
294
|
+
std_vals: list[float] = []
|
|
295
|
+
if isinstance(history, (list, tuple)) and len(history) >= 2:
|
|
296
|
+
for entry in history:
|
|
297
|
+
if (
|
|
298
|
+
isinstance(entry, tuple)
|
|
299
|
+
and len(entry) == 2
|
|
300
|
+
and all(isinstance(x, (int, float)) for x in entry)
|
|
301
|
+
):
|
|
302
|
+
std_vals.append(entry[0] - entry[1])
|
|
303
|
+
# Apply criteria
|
|
304
|
+
non_zero_count = sum(1 for v in std_vals if v != 0)
|
|
305
|
+
total = sum(std_vals)
|
|
306
|
+
attr["is_mtg"] = non_zero_count >= 2 and total == 0
|
|
307
|
+
return graph
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def compute_standard_order(G: nx.Graph, inplace: bool = False) -> nx.Graph:
|
|
311
|
+
"""Compute and assign the 'standard_order' attribute for each edge in the graph.
|
|
312
|
+
'standard_order' is defined as the difference order[0] - order[1]
|
|
313
|
+
for edges whose 'order' attribute is a 2-tuple of numeric values.
|
|
314
|
+
|
|
315
|
+
:param G: Input NetworkX graph
|
|
316
|
+
:type G: nx.Graph, nx.DiGraph, nx.MultiGraph, or nx.MultiDiGraph
|
|
317
|
+
:param inplace: If True, modify G in-place; otherwise operate on a copy
|
|
318
|
+
:type inplace: bool
|
|
319
|
+
:return: Graph with 'standard_order' attributes set
|
|
320
|
+
:rtype: same type as G
|
|
321
|
+
:raises TypeError: If G is not a NetworkX graph
|
|
322
|
+
|
|
323
|
+
.. rubric:: Examples
|
|
324
|
+
|
|
325
|
+
>>> import networkx as nx
|
|
326
|
+
>>> G = nx.Graph()
|
|
327
|
+
>>> G.add_edge(7, 3, order=(1.0, 0))
|
|
328
|
+
>>> H = compute_standard_order(G)
|
|
329
|
+
>>> H.edges[7,3]['standard_order']
|
|
330
|
+
1.0
|
|
331
|
+
"""
|
|
332
|
+
if not isinstance(G, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)):
|
|
333
|
+
raise TypeError(f"Expected a NetworkX graph, got {type(G)}")
|
|
334
|
+
|
|
335
|
+
graph = G if inplace else G.copy()
|
|
336
|
+
if graph.is_multigraph():
|
|
337
|
+
for u, v, key, attr in graph.edges(keys=True, data=True):
|
|
338
|
+
order = attr.get("order")
|
|
339
|
+
if isinstance(order, tuple) and len(order) == 2:
|
|
340
|
+
a, b = order
|
|
341
|
+
try:
|
|
342
|
+
attr["standard_order"] = a - b
|
|
343
|
+
except Exception:
|
|
344
|
+
attr["standard_order"] = None
|
|
345
|
+
else:
|
|
346
|
+
for u, v, attr in graph.edges(data=True):
|
|
347
|
+
order = attr.get("order")
|
|
348
|
+
if isinstance(order, tuple) and len(order) == 2:
|
|
349
|
+
a, b = order
|
|
350
|
+
try:
|
|
351
|
+
attr["standard_order"] = a - b
|
|
352
|
+
except Exception:
|
|
353
|
+
attr["standard_order"] = None
|
|
354
|
+
return graph
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
# def extract_order_norm(order_tuple):
|
|
358
|
+
# """
|
|
359
|
+
# Given a sequence of four 2-element tuples (order data), return the normalized order:
|
|
360
|
+
# - left: first element of the first tuple that is not both sets
|
|
361
|
+
# - right: second element of the last tuple that is not both sets
|
|
362
|
+
|
|
363
|
+
# :param order_tuple: tuple of four 2-element tuples
|
|
364
|
+
# :type order_tuple: tuple(tuple, tuple, tuple, tuple)
|
|
365
|
+
# :returns: normalized (left, right) or None if not found
|
|
366
|
+
# :rtype: tuple or None
|
|
367
|
+
# :raises: ValueError if order_tuple is not length 4
|
|
368
|
+
|
|
369
|
+
# :example:
|
|
370
|
+
# >>> ot = (({1}, {2}), (3, 4), ({5}, {6}), (7, 8))
|
|
371
|
+
# >>> extract_order_norm(ot)
|
|
372
|
+
# (3, 8)
|
|
373
|
+
# """
|
|
374
|
+
# if not (isinstance(order_tuple, tuple) and len(order_tuple) == 4):
|
|
375
|
+
# raise ValueError("order_tuple must be a tuple of length 4")
|
|
376
|
+
|
|
377
|
+
# left = None
|
|
378
|
+
# right = None
|
|
379
|
+
# # Find first non-all-set tuple for left
|
|
380
|
+
# for a, b in order_tuple:
|
|
381
|
+
# if not (isinstance(a, set) and isinstance(b, set)):
|
|
382
|
+
# left = a
|
|
383
|
+
# break
|
|
384
|
+
# # Find last non-all-set tuple for right
|
|
385
|
+
# for a, b in reversed(order_tuple):
|
|
386
|
+
# if not (isinstance(a, set) and isinstance(b, set)):
|
|
387
|
+
# right = b
|
|
388
|
+
# break
|
|
389
|
+
# return (left, right) if (left is not None and right is not None) else None
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# def normalize_order(G):
|
|
393
|
+
# """
|
|
394
|
+
# Return a copy of G with edge attribute 'order' normalized.
|
|
395
|
+
# For each edge, if the 'order' attribute is a 4-tuple, replace it with the
|
|
396
|
+
# normalized 2-tuple returned by extract_order_norm.
|
|
397
|
+
|
|
398
|
+
# :param G: input NetworkX graph
|
|
399
|
+
# :type G: nx.Graph or nx.DiGraph or nx.MultiGraph or nx.MultiDiGraph
|
|
400
|
+
# :returns: a new graph with normalized edge orders
|
|
401
|
+
# :rtype: same type as G
|
|
402
|
+
# :raises: TypeError if G is not a NetworkX graph
|
|
403
|
+
|
|
404
|
+
# :example:
|
|
405
|
+
# >>> G = nx.Graph()
|
|
406
|
+
# >>> G.add_edge(1, 2, order=((1,2), ({3},{4}), ({5},{6}), (7,8)))
|
|
407
|
+
# >>> H = copy_and_normalize_order(G)
|
|
408
|
+
# >>> H.edges[1,2]['order']
|
|
409
|
+
# (1, 8)
|
|
410
|
+
# """
|
|
411
|
+
# if not isinstance(G, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)):
|
|
412
|
+
# raise TypeError(f"Expected NetworkX graph, got {type(G)}")
|
|
413
|
+
# H = G.copy()
|
|
414
|
+
# for _, _, _, attr in (
|
|
415
|
+
# H.edges(keys=True, data=True)
|
|
416
|
+
# if H.is_multigraph()
|
|
417
|
+
# else [(u, v, None, attr) for u, v, attr in H.edges(data=True)]
|
|
418
|
+
# ):
|
|
419
|
+
# order = attr.get("order")
|
|
420
|
+
# if isinstance(order, tuple) and len(order) == 4:
|
|
421
|
+
# norm = extract_order_norm(order)
|
|
422
|
+
# if norm is not None:
|
|
423
|
+
# attr["order"] = norm
|
|
424
|
+
# return H
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# from .graph_matcher import GraphMatcherEngine
|
|
2
|
+
# from .subgraph_matcher import SubgraphMatch, SubgraphSearchEngine
|
|
3
|
+
# from .graph_cluster import GraphCluster
|
|
4
|
+
|
|
5
|
+
# __all__ = [
|
|
6
|
+
# "GraphMatcherEngine",
|
|
7
|
+
# "SubgraphMatch",
|
|
8
|
+
# "SubgraphSearchEngine",
|
|
9
|
+
# "GraphCluster",
|
|
10
|
+
# ]
|