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,1041 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import Counter
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import (
|
|
6
|
+
Any,
|
|
7
|
+
Dict,
|
|
8
|
+
Hashable,
|
|
9
|
+
Iterable,
|
|
10
|
+
List,
|
|
11
|
+
Mapping,
|
|
12
|
+
MutableMapping,
|
|
13
|
+
Optional,
|
|
14
|
+
Set,
|
|
15
|
+
Tuple,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
import networkx as nx
|
|
19
|
+
|
|
20
|
+
from ..kinds import REACTION_KINDS, SPECIES_KINDS
|
|
21
|
+
|
|
22
|
+
Place = str
|
|
23
|
+
TransitionId = str
|
|
24
|
+
Marking = Mapping[Place, int]
|
|
25
|
+
Multiset = Mapping[str, int]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class SynCRNIncidence:
|
|
30
|
+
"""Canonical species--reaction incidence view extracted from a SynCRN-like object.
|
|
31
|
+
|
|
32
|
+
This dataclass stores a normalized incidence representation that can be
|
|
33
|
+
constructed either from a SynCRN-style object exposing ``species`` and
|
|
34
|
+
``reactions`` mappings, or from a bipartite :class:`networkx.DiGraph`
|
|
35
|
+
returned by ``SynCRN.to_digraph()``.
|
|
36
|
+
|
|
37
|
+
The canonical representation separates:
|
|
38
|
+
|
|
39
|
+
- species order
|
|
40
|
+
- reaction order
|
|
41
|
+
- species and reaction labels
|
|
42
|
+
- pre-incidence stoichiometry
|
|
43
|
+
- post-incidence stoichiometry
|
|
44
|
+
- source-node provenance metadata
|
|
45
|
+
|
|
46
|
+
:param species_order:
|
|
47
|
+
Ordered list of canonical species identifiers.
|
|
48
|
+
:type species_order: List[str]
|
|
49
|
+
:param reaction_order:
|
|
50
|
+
Ordered list of canonical reaction identifiers.
|
|
51
|
+
:type reaction_order: List[str]
|
|
52
|
+
:param species_labels:
|
|
53
|
+
Mapping from species identifier to display label.
|
|
54
|
+
:type species_labels: Dict[str, str]
|
|
55
|
+
:param reaction_labels:
|
|
56
|
+
Mapping from reaction identifier to display label.
|
|
57
|
+
:type reaction_labels: Dict[str, str]
|
|
58
|
+
:param pre:
|
|
59
|
+
Mapping ``reaction_id -> {species_id: stoichiometric_coefficient}``
|
|
60
|
+
for reactants / input arcs.
|
|
61
|
+
:type pre: Dict[str, Dict[str, int]]
|
|
62
|
+
:param post:
|
|
63
|
+
Mapping ``reaction_id -> {species_id: stoichiometric_coefficient}``
|
|
64
|
+
for products / output arcs.
|
|
65
|
+
:type post: Dict[str, Dict[str, int]]
|
|
66
|
+
:param species_source_node_ids:
|
|
67
|
+
Mapping from canonical species identifier to original source node id.
|
|
68
|
+
:type species_source_node_ids: Dict[str, Hashable]
|
|
69
|
+
:param reaction_source_node_ids:
|
|
70
|
+
Mapping from canonical reaction identifier to original source node id.
|
|
71
|
+
:type reaction_source_node_ids: Dict[str, Hashable]
|
|
72
|
+
:param graph_attrs:
|
|
73
|
+
Graph-level metadata copied from the source object or source graph.
|
|
74
|
+
:type graph_attrs: Dict[str, Any]
|
|
75
|
+
:param metadata:
|
|
76
|
+
Additional extraction metadata.
|
|
77
|
+
:type metadata: Dict[str, Any]
|
|
78
|
+
|
|
79
|
+
.. rubric:: Example
|
|
80
|
+
|
|
81
|
+
.. code-block:: python
|
|
82
|
+
|
|
83
|
+
incidence = SynCRNIncidence(
|
|
84
|
+
species_order=["A", "B", "C"],
|
|
85
|
+
reaction_order=["r1"],
|
|
86
|
+
species_labels={"A": "A", "B": "B", "C": "C"},
|
|
87
|
+
reaction_labels={"r1": "A + B -> C"},
|
|
88
|
+
pre={"r1": {"A": 1, "B": 1}},
|
|
89
|
+
post={"r1": {"C": 1}},
|
|
90
|
+
)
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
species_order: List[str]
|
|
94
|
+
reaction_order: List[str]
|
|
95
|
+
species_labels: Dict[str, str]
|
|
96
|
+
reaction_labels: Dict[str, str]
|
|
97
|
+
pre: Dict[str, Dict[str, int]]
|
|
98
|
+
post: Dict[str, Dict[str, int]]
|
|
99
|
+
species_source_node_ids: Dict[str, Hashable] = field(default_factory=dict)
|
|
100
|
+
reaction_source_node_ids: Dict[str, Hashable] = field(default_factory=dict)
|
|
101
|
+
graph_attrs: Dict[str, Any] = field(default_factory=dict)
|
|
102
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class Transition:
|
|
107
|
+
"""Petri-net transition with stoichiometric input/output multisets.
|
|
108
|
+
|
|
109
|
+
A transition corresponds to one reaction node in the source SynCRN-like
|
|
110
|
+
representation.
|
|
111
|
+
|
|
112
|
+
:param tid:
|
|
113
|
+
Canonical transition identifier.
|
|
114
|
+
:type tid: TransitionId
|
|
115
|
+
:param pre:
|
|
116
|
+
Input multiset mapping ``place -> coefficient``.
|
|
117
|
+
:type pre: Dict[Place, int]
|
|
118
|
+
:param post:
|
|
119
|
+
Output multiset mapping ``place -> coefficient``.
|
|
120
|
+
:type post: Dict[Place, int]
|
|
121
|
+
:param label:
|
|
122
|
+
Optional display label.
|
|
123
|
+
:type label: Optional[str]
|
|
124
|
+
:param source_reaction_id:
|
|
125
|
+
Optional source reaction identifier from the original CRN object.
|
|
126
|
+
:type source_reaction_id: Optional[str]
|
|
127
|
+
:param metadata:
|
|
128
|
+
Optional transition metadata dictionary.
|
|
129
|
+
:type metadata: Dict[str, Any]
|
|
130
|
+
|
|
131
|
+
.. rubric:: Example
|
|
132
|
+
|
|
133
|
+
.. code-block:: python
|
|
134
|
+
|
|
135
|
+
t = Transition(
|
|
136
|
+
tid="r1",
|
|
137
|
+
pre={"A": 1, "B": 2},
|
|
138
|
+
post={"C": 1},
|
|
139
|
+
label="A + 2B -> C",
|
|
140
|
+
)
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
tid: TransitionId
|
|
144
|
+
pre: Dict[Place, int]
|
|
145
|
+
post: Dict[Place, int]
|
|
146
|
+
label: Optional[str] = None
|
|
147
|
+
source_reaction_id: Optional[str] = None
|
|
148
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
149
|
+
|
|
150
|
+
def __repr__(self) -> str: # pragma: no cover - simple repr
|
|
151
|
+
"""Return a compact debug representation.
|
|
152
|
+
|
|
153
|
+
:return:
|
|
154
|
+
Readable transition representation.
|
|
155
|
+
:rtype: str
|
|
156
|
+
"""
|
|
157
|
+
extra = f", label={self.label!r}" if self.label is not None else ""
|
|
158
|
+
return f"Transition({self.tid!r}, pre={self.pre}, post={self.post}{extra})"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _safe_int(x: Any, default: int = 0) -> int:
|
|
162
|
+
"""Convert a value to ``int`` with fallback.
|
|
163
|
+
|
|
164
|
+
:param x:
|
|
165
|
+
Value to convert.
|
|
166
|
+
:type x: Any
|
|
167
|
+
:param default:
|
|
168
|
+
Fallback value used if conversion fails.
|
|
169
|
+
:type default: int
|
|
170
|
+
:return:
|
|
171
|
+
Converted integer value.
|
|
172
|
+
:rtype: int
|
|
173
|
+
"""
|
|
174
|
+
try:
|
|
175
|
+
return int(x)
|
|
176
|
+
except Exception:
|
|
177
|
+
return int(default)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _coerce_stoich(x: Any) -> int:
|
|
181
|
+
"""Validate and normalize a stoichiometric coefficient.
|
|
182
|
+
|
|
183
|
+
The value is converted to ``int`` and must be strictly positive.
|
|
184
|
+
|
|
185
|
+
:param x:
|
|
186
|
+
Candidate stoichiometric coefficient.
|
|
187
|
+
:type x: Any
|
|
188
|
+
:return:
|
|
189
|
+
Positive stoichiometric coefficient.
|
|
190
|
+
:rtype: int
|
|
191
|
+
:raises ValueError:
|
|
192
|
+
If the resulting value is not strictly positive.
|
|
193
|
+
|
|
194
|
+
.. rubric:: Example
|
|
195
|
+
|
|
196
|
+
.. code-block:: python
|
|
197
|
+
|
|
198
|
+
_coerce_stoich(2) # 2
|
|
199
|
+
_coerce_stoich("3") # 3
|
|
200
|
+
"""
|
|
201
|
+
val = _safe_int(x, default=1)
|
|
202
|
+
if val <= 0:
|
|
203
|
+
raise ValueError(f"Stoichiometric coefficient must be positive, got {x!r}")
|
|
204
|
+
return val
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _naturalish_key(x: Any) -> Tuple[int, str, str]:
|
|
208
|
+
"""Build a stable sorting key for mixed identifiers.
|
|
209
|
+
|
|
210
|
+
Numeric-looking strings are sorted numerically first, while all other
|
|
211
|
+
objects are sorted by type name and representation.
|
|
212
|
+
|
|
213
|
+
:param x:
|
|
214
|
+
Object used as an identifier.
|
|
215
|
+
:type x: Any
|
|
216
|
+
:return:
|
|
217
|
+
Tuple suitable for deterministic ordering.
|
|
218
|
+
:rtype: Tuple[int, str, str]
|
|
219
|
+
"""
|
|
220
|
+
sx = str(x)
|
|
221
|
+
if sx.isdigit():
|
|
222
|
+
return (0, f"{int(sx):020d}", sx)
|
|
223
|
+
return (1, type(x).__name__, repr(x))
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _graph_node_kind(attrs: Mapping[str, Any]) -> str:
|
|
227
|
+
"""Normalize the ``kind`` attribute of a graph node.
|
|
228
|
+
|
|
229
|
+
:param attrs:
|
|
230
|
+
Node attribute mapping.
|
|
231
|
+
:type attrs: Mapping[str, Any]
|
|
232
|
+
:return:
|
|
233
|
+
Lowercased and stripped node kind.
|
|
234
|
+
:rtype: str
|
|
235
|
+
"""
|
|
236
|
+
return str(attrs.get("kind", "")).strip().lower()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _edge_side_from_graph(
|
|
240
|
+
u: Hashable,
|
|
241
|
+
v: Hashable,
|
|
242
|
+
eattrs: Mapping[str, Any],
|
|
243
|
+
reaction_node: Hashable,
|
|
244
|
+
) -> str:
|
|
245
|
+
"""Infer whether an incidence edge belongs to the left or right side.
|
|
246
|
+
|
|
247
|
+
The function first checks the explicit edge attribute ``role``:
|
|
248
|
+
|
|
249
|
+
- ``"reactant"`` -> ``"lhs"``
|
|
250
|
+
- ``"product"`` -> ``"rhs"``
|
|
251
|
+
|
|
252
|
+
If no explicit role is present, direction relative to the reaction node
|
|
253
|
+
is used as a fallback.
|
|
254
|
+
|
|
255
|
+
:param u:
|
|
256
|
+
Source node of the directed edge.
|
|
257
|
+
:type u: Hashable
|
|
258
|
+
:param v:
|
|
259
|
+
Target node of the directed edge.
|
|
260
|
+
:type v: Hashable
|
|
261
|
+
:param eattrs:
|
|
262
|
+
Edge attribute mapping.
|
|
263
|
+
:type eattrs: Mapping[str, Any]
|
|
264
|
+
:param reaction_node:
|
|
265
|
+
Node corresponding to the reaction / transition.
|
|
266
|
+
:type reaction_node: Hashable
|
|
267
|
+
:return:
|
|
268
|
+
Either ``"lhs"`` or ``"rhs"``.
|
|
269
|
+
:rtype: str
|
|
270
|
+
"""
|
|
271
|
+
role = eattrs.get("role")
|
|
272
|
+
if role == "reactant":
|
|
273
|
+
return "lhs"
|
|
274
|
+
if role == "product":
|
|
275
|
+
return "rhs"
|
|
276
|
+
return "lhs" if v == reaction_node else "rhs"
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _extract_from_syncrn_object(crn: Any) -> SynCRNIncidence:
|
|
280
|
+
"""Extract canonical incidence information from a SynCRN-like object.
|
|
281
|
+
|
|
282
|
+
The input object is expected to expose:
|
|
283
|
+
|
|
284
|
+
- ``species``: mapping of species id -> species-like object
|
|
285
|
+
- ``reactions``: mapping of reaction id -> reaction-like object
|
|
286
|
+
|
|
287
|
+
Species-like objects may expose ``label`` and ``source_node_id``.
|
|
288
|
+
Reaction-like objects may expose ``label``, ``source_node_id``, ``lhs``,
|
|
289
|
+
and ``rhs``.
|
|
290
|
+
|
|
291
|
+
:param crn:
|
|
292
|
+
SynCRN-like object.
|
|
293
|
+
:type crn: Any
|
|
294
|
+
:return:
|
|
295
|
+
Canonical incidence representation.
|
|
296
|
+
:rtype: SynCRNIncidence
|
|
297
|
+
|
|
298
|
+
.. rubric:: Example
|
|
299
|
+
|
|
300
|
+
.. code-block:: python
|
|
301
|
+
|
|
302
|
+
incidence = _extract_from_syncrn_object(crn)
|
|
303
|
+
print(incidence.pre)
|
|
304
|
+
print(incidence.post)
|
|
305
|
+
"""
|
|
306
|
+
species_order = [str(x) for x in getattr(crn, "species", {}).keys()]
|
|
307
|
+
reaction_order = [str(x) for x in getattr(crn, "reactions", {}).keys()]
|
|
308
|
+
|
|
309
|
+
species_labels: Dict[str, str] = {}
|
|
310
|
+
reaction_labels: Dict[str, str] = {}
|
|
311
|
+
species_source_node_ids: Dict[str, Hashable] = {}
|
|
312
|
+
reaction_source_node_ids: Dict[str, Hashable] = {}
|
|
313
|
+
pre: Dict[str, Dict[str, int]] = {}
|
|
314
|
+
post: Dict[str, Dict[str, int]] = {}
|
|
315
|
+
|
|
316
|
+
for sid, sp in getattr(crn, "species", {}).items():
|
|
317
|
+
sid_s = str(sid)
|
|
318
|
+
species_labels[sid_s] = str(getattr(sp, "label", sid_s))
|
|
319
|
+
species_source_node_ids[sid_s] = getattr(sp, "source_node_id", sid)
|
|
320
|
+
|
|
321
|
+
for rid, rxn in getattr(crn, "reactions", {}).items():
|
|
322
|
+
rid_s = str(rid)
|
|
323
|
+
reaction_labels[rid_s] = str(getattr(rxn, "label", rid_s))
|
|
324
|
+
reaction_source_node_ids[rid_s] = getattr(rxn, "source_node_id", rid)
|
|
325
|
+
pre[rid_s] = {
|
|
326
|
+
str(sid): int(coeff) for sid, coeff in getattr(rxn, "lhs", {}).items()
|
|
327
|
+
}
|
|
328
|
+
post[rid_s] = {
|
|
329
|
+
str(sid): int(coeff) for sid, coeff in getattr(rxn, "rhs", {}).items()
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return SynCRNIncidence(
|
|
333
|
+
species_order=species_order,
|
|
334
|
+
reaction_order=reaction_order,
|
|
335
|
+
species_labels=species_labels,
|
|
336
|
+
reaction_labels=reaction_labels,
|
|
337
|
+
pre=pre,
|
|
338
|
+
post=post,
|
|
339
|
+
species_source_node_ids=species_source_node_ids,
|
|
340
|
+
reaction_source_node_ids=reaction_source_node_ids,
|
|
341
|
+
graph_attrs=dict(getattr(crn, "graph_attrs", {}) or {}),
|
|
342
|
+
metadata=dict(getattr(crn, "metadata", {}) or {}),
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _partition_syncrn_nodes(
|
|
347
|
+
crn: nx.DiGraph,
|
|
348
|
+
) -> Tuple[List[Hashable], List[Hashable]]:
|
|
349
|
+
"""Partition graph nodes into species nodes and reaction nodes.
|
|
350
|
+
|
|
351
|
+
Nodes with ``kind == "species"`` are treated as species nodes.
|
|
352
|
+
Nodes with ``kind in {"reaction", "rule"}`` are treated as reaction nodes.
|
|
353
|
+
|
|
354
|
+
:param crn:
|
|
355
|
+
SynCRN bipartite digraph.
|
|
356
|
+
:type crn: nx.DiGraph
|
|
357
|
+
:return:
|
|
358
|
+
Pair ``(species_nodes, reaction_nodes)``.
|
|
359
|
+
:rtype: Tuple[List[Hashable], List[Hashable]]
|
|
360
|
+
"""
|
|
361
|
+
species_nodes: List[Hashable] = []
|
|
362
|
+
reaction_nodes: List[Hashable] = []
|
|
363
|
+
|
|
364
|
+
for node, attrs in crn.nodes(data=True):
|
|
365
|
+
kind = _graph_node_kind(attrs)
|
|
366
|
+
if kind in SPECIES_KINDS:
|
|
367
|
+
species_nodes.append(node)
|
|
368
|
+
elif kind in REACTION_KINDS:
|
|
369
|
+
reaction_nodes.append(node)
|
|
370
|
+
|
|
371
|
+
species_nodes.sort(key=lambda n: _naturalish_key(crn.nodes[n].get("syncrn_id", n)))
|
|
372
|
+
reaction_nodes.sort(key=lambda n: _naturalish_key(crn.nodes[n].get("syncrn_id", n)))
|
|
373
|
+
return species_nodes, reaction_nodes
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _build_species_index(
|
|
377
|
+
crn: nx.DiGraph,
|
|
378
|
+
species_nodes: Iterable[Hashable],
|
|
379
|
+
) -> Tuple[List[str], Dict[str, str], Dict[str, Hashable], Dict[Hashable, str]]:
|
|
380
|
+
"""Build canonical species metadata from graph nodes.
|
|
381
|
+
|
|
382
|
+
:param crn:
|
|
383
|
+
Source graph.
|
|
384
|
+
:type crn: nx.DiGraph
|
|
385
|
+
:param species_nodes:
|
|
386
|
+
Iterable of species node ids.
|
|
387
|
+
:type species_nodes: Iterable[Hashable]
|
|
388
|
+
:return:
|
|
389
|
+
Tuple containing species order, labels, source node ids, and reverse lookup.
|
|
390
|
+
:rtype: Tuple[List[str], Dict[str, str], Dict[str, Hashable], Dict[Hashable, str]]
|
|
391
|
+
"""
|
|
392
|
+
species_order: List[str] = []
|
|
393
|
+
species_labels: Dict[str, str] = {}
|
|
394
|
+
species_source_node_ids: Dict[str, Hashable] = {}
|
|
395
|
+
species_node_to_id: Dict[Hashable, str] = {}
|
|
396
|
+
|
|
397
|
+
for node in species_nodes:
|
|
398
|
+
attrs = dict(crn.nodes[node])
|
|
399
|
+
sid = str(attrs.get("syncrn_id", node))
|
|
400
|
+
species_order.append(sid)
|
|
401
|
+
species_labels[sid] = str(attrs.get("label", sid))
|
|
402
|
+
species_source_node_ids[sid] = attrs.get("source_node_id", node)
|
|
403
|
+
species_node_to_id[node] = sid
|
|
404
|
+
|
|
405
|
+
return (
|
|
406
|
+
species_order,
|
|
407
|
+
species_labels,
|
|
408
|
+
species_source_node_ids,
|
|
409
|
+
species_node_to_id,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _build_reaction_index(
|
|
414
|
+
crn: nx.DiGraph,
|
|
415
|
+
reaction_nodes: Iterable[Hashable],
|
|
416
|
+
) -> Tuple[List[str], Dict[str, str], Dict[str, Hashable], Dict[Hashable, str]]:
|
|
417
|
+
"""Build canonical reaction metadata from graph nodes.
|
|
418
|
+
|
|
419
|
+
:param crn:
|
|
420
|
+
Source graph.
|
|
421
|
+
:type crn: nx.DiGraph
|
|
422
|
+
:param reaction_nodes:
|
|
423
|
+
Iterable of reaction node ids.
|
|
424
|
+
:type reaction_nodes: Iterable[Hashable]
|
|
425
|
+
:return:
|
|
426
|
+
Tuple containing reaction order, labels, source node ids, and reverse lookup.
|
|
427
|
+
:rtype: Tuple[List[str], Dict[str, str], Dict[str, Hashable], Dict[Hashable, str]]
|
|
428
|
+
"""
|
|
429
|
+
reaction_order: List[str] = []
|
|
430
|
+
reaction_labels: Dict[str, str] = {}
|
|
431
|
+
reaction_source_node_ids: Dict[str, Hashable] = {}
|
|
432
|
+
reaction_node_to_id: Dict[Hashable, str] = {}
|
|
433
|
+
|
|
434
|
+
for node in reaction_nodes:
|
|
435
|
+
attrs = dict(crn.nodes[node])
|
|
436
|
+
rid = str(attrs.get("syncrn_id", node))
|
|
437
|
+
reaction_order.append(rid)
|
|
438
|
+
reaction_labels[rid] = str(attrs.get("label", rid))
|
|
439
|
+
reaction_source_node_ids[rid] = attrs.get("source_node_id", node)
|
|
440
|
+
reaction_node_to_id[node] = rid
|
|
441
|
+
|
|
442
|
+
return (
|
|
443
|
+
reaction_order,
|
|
444
|
+
reaction_labels,
|
|
445
|
+
reaction_source_node_ids,
|
|
446
|
+
reaction_node_to_id,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def _accumulate_incidence_from_edges(
|
|
451
|
+
crn: nx.DiGraph,
|
|
452
|
+
reaction_node: Hashable,
|
|
453
|
+
species_node_to_id: Mapping[Hashable, str],
|
|
454
|
+
) -> Tuple[Dict[str, int], Dict[str, int]]:
|
|
455
|
+
"""Accumulate input and output stoichiometry for one reaction node.
|
|
456
|
+
|
|
457
|
+
Both incoming and outgoing graph edges are inspected. The edge role is
|
|
458
|
+
inferred via :func:`_edge_side_from_graph`.
|
|
459
|
+
|
|
460
|
+
:param crn:
|
|
461
|
+
Source graph.
|
|
462
|
+
:type crn: nx.DiGraph
|
|
463
|
+
:param reaction_node:
|
|
464
|
+
Reaction node whose local incidence is extracted.
|
|
465
|
+
:type reaction_node: Hashable
|
|
466
|
+
:param species_node_to_id:
|
|
467
|
+
Mapping from species graph node to canonical species id.
|
|
468
|
+
:type species_node_to_id: Mapping[Hashable, str]
|
|
469
|
+
:return:
|
|
470
|
+
Pair ``(pre, post)`` for the reaction.
|
|
471
|
+
:rtype: Tuple[Dict[str, int], Dict[str, int]]
|
|
472
|
+
"""
|
|
473
|
+
lhs_counter: Counter[str] = Counter()
|
|
474
|
+
rhs_counter: Counter[str] = Counter()
|
|
475
|
+
|
|
476
|
+
for u, v, eattrs in crn.in_edges(reaction_node, data=True):
|
|
477
|
+
if u not in species_node_to_id:
|
|
478
|
+
continue
|
|
479
|
+
sid = species_node_to_id[u]
|
|
480
|
+
side = _edge_side_from_graph(u, v, eattrs, reaction_node)
|
|
481
|
+
stoich = _coerce_stoich(eattrs.get("stoich", 1))
|
|
482
|
+
if side == "lhs":
|
|
483
|
+
lhs_counter[sid] += stoich
|
|
484
|
+
else:
|
|
485
|
+
rhs_counter[sid] += stoich
|
|
486
|
+
|
|
487
|
+
for u, v, eattrs in crn.out_edges(reaction_node, data=True):
|
|
488
|
+
if v not in species_node_to_id:
|
|
489
|
+
continue
|
|
490
|
+
sid = species_node_to_id[v]
|
|
491
|
+
side = _edge_side_from_graph(u, v, eattrs, reaction_node)
|
|
492
|
+
stoich = _coerce_stoich(eattrs.get("stoich", 1))
|
|
493
|
+
if side == "lhs":
|
|
494
|
+
lhs_counter[sid] += stoich
|
|
495
|
+
else:
|
|
496
|
+
rhs_counter[sid] += stoich
|
|
497
|
+
|
|
498
|
+
return dict(lhs_counter), dict(rhs_counter)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def _build_pre_post_from_graph(
|
|
502
|
+
crn: nx.DiGraph,
|
|
503
|
+
reaction_nodes: Iterable[Hashable],
|
|
504
|
+
reaction_node_to_id: Mapping[Hashable, str],
|
|
505
|
+
species_node_to_id: Mapping[Hashable, str],
|
|
506
|
+
) -> Tuple[Dict[str, Dict[str, int]], Dict[str, Dict[str, int]]]:
|
|
507
|
+
"""Build reaction-wise pre and post incidence maps from a graph.
|
|
508
|
+
|
|
509
|
+
:param crn:
|
|
510
|
+
Source graph.
|
|
511
|
+
:type crn: nx.DiGraph
|
|
512
|
+
:param reaction_nodes:
|
|
513
|
+
Iterable of reaction graph nodes.
|
|
514
|
+
:type reaction_nodes: Iterable[Hashable]
|
|
515
|
+
:param reaction_node_to_id:
|
|
516
|
+
Mapping from reaction graph node to canonical reaction id.
|
|
517
|
+
:type reaction_node_to_id: Mapping[Hashable, str]
|
|
518
|
+
:param species_node_to_id:
|
|
519
|
+
Mapping from species graph node to canonical species id.
|
|
520
|
+
:type species_node_to_id: Mapping[Hashable, str]
|
|
521
|
+
:return:
|
|
522
|
+
Pair ``(pre, post)`` keyed by reaction id.
|
|
523
|
+
:rtype: Tuple[Dict[str, Dict[str, int]], Dict[str, Dict[str, int]]]
|
|
524
|
+
"""
|
|
525
|
+
pre: Dict[str, Dict[str, int]] = {}
|
|
526
|
+
post: Dict[str, Dict[str, int]] = {}
|
|
527
|
+
|
|
528
|
+
for rnode in reaction_nodes:
|
|
529
|
+
rid = reaction_node_to_id[rnode]
|
|
530
|
+
pre[rid], post[rid] = _accumulate_incidence_from_edges(
|
|
531
|
+
crn=crn,
|
|
532
|
+
reaction_node=rnode,
|
|
533
|
+
species_node_to_id=species_node_to_id,
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
return pre, post
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def _extract_from_syncrn_digraph(crn: nx.DiGraph) -> SynCRNIncidence:
|
|
540
|
+
"""Extract canonical incidence information from a SynCRN bipartite digraph.
|
|
541
|
+
|
|
542
|
+
The graph is expected to use node attribute ``kind`` with values:
|
|
543
|
+
|
|
544
|
+
- ``"species"`` for species nodes
|
|
545
|
+
- ``"reaction"`` or ``"rule"`` for reaction nodes
|
|
546
|
+
|
|
547
|
+
Optional node attributes include:
|
|
548
|
+
|
|
549
|
+
- ``syncrn_id``
|
|
550
|
+
- ``label``
|
|
551
|
+
- ``source_node_id``
|
|
552
|
+
|
|
553
|
+
Optional edge attributes include:
|
|
554
|
+
|
|
555
|
+
- ``stoich``
|
|
556
|
+
- ``role`` with values ``"reactant"`` or ``"product"``
|
|
557
|
+
|
|
558
|
+
:param crn:
|
|
559
|
+
SynCRN bipartite directed graph.
|
|
560
|
+
:type crn: nx.DiGraph
|
|
561
|
+
:return:
|
|
562
|
+
Canonical incidence representation extracted from the graph.
|
|
563
|
+
:rtype: SynCRNIncidence
|
|
564
|
+
:raises TypeError:
|
|
565
|
+
If ``crn`` is not a :class:`networkx.DiGraph`.
|
|
566
|
+
|
|
567
|
+
.. rubric:: Example
|
|
568
|
+
|
|
569
|
+
.. code-block:: python
|
|
570
|
+
|
|
571
|
+
g = syn.to_digraph()
|
|
572
|
+
incidence = _extract_from_syncrn_digraph(g)
|
|
573
|
+
print(incidence.species_order)
|
|
574
|
+
print(incidence.reaction_order)
|
|
575
|
+
"""
|
|
576
|
+
if not isinstance(crn, nx.DiGraph):
|
|
577
|
+
raise TypeError(f"Expected nx.DiGraph, got {type(crn).__name__}")
|
|
578
|
+
|
|
579
|
+
species_nodes, reaction_nodes = _partition_syncrn_nodes(crn)
|
|
580
|
+
|
|
581
|
+
(
|
|
582
|
+
species_order,
|
|
583
|
+
species_labels,
|
|
584
|
+
species_source_node_ids,
|
|
585
|
+
species_node_to_id,
|
|
586
|
+
) = _build_species_index(crn, species_nodes)
|
|
587
|
+
|
|
588
|
+
(
|
|
589
|
+
reaction_order,
|
|
590
|
+
reaction_labels,
|
|
591
|
+
reaction_source_node_ids,
|
|
592
|
+
reaction_node_to_id,
|
|
593
|
+
) = _build_reaction_index(crn, reaction_nodes)
|
|
594
|
+
|
|
595
|
+
pre, post = _build_pre_post_from_graph(
|
|
596
|
+
crn=crn,
|
|
597
|
+
reaction_nodes=reaction_nodes,
|
|
598
|
+
reaction_node_to_id=reaction_node_to_id,
|
|
599
|
+
species_node_to_id=species_node_to_id,
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
return SynCRNIncidence(
|
|
603
|
+
species_order=species_order,
|
|
604
|
+
reaction_order=reaction_order,
|
|
605
|
+
species_labels=species_labels,
|
|
606
|
+
reaction_labels=reaction_labels,
|
|
607
|
+
pre=pre,
|
|
608
|
+
post=post,
|
|
609
|
+
species_source_node_ids=species_source_node_ids,
|
|
610
|
+
reaction_source_node_ids=reaction_source_node_ids,
|
|
611
|
+
graph_attrs=dict(crn.graph),
|
|
612
|
+
metadata={"source_graph_type": type(crn).__name__},
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def extract_syncrn_incidence(crn: Any) -> SynCRNIncidence:
|
|
617
|
+
"""Extract a canonical incidence view from a SynCRN-like object or digraph.
|
|
618
|
+
|
|
619
|
+
The function accepts three input styles:
|
|
620
|
+
|
|
621
|
+
- a :class:`networkx.DiGraph` in SynCRN bipartite format
|
|
622
|
+
- a SynCRN-like object exposing ``species`` and ``reactions``
|
|
623
|
+
- an object exposing ``to_digraph()`` that returns such a graph
|
|
624
|
+
|
|
625
|
+
:param crn:
|
|
626
|
+
SynCRN-like object or bipartite digraph.
|
|
627
|
+
:type crn: Any
|
|
628
|
+
:return:
|
|
629
|
+
Canonical incidence representation.
|
|
630
|
+
:rtype: SynCRNIncidence
|
|
631
|
+
:raises TypeError:
|
|
632
|
+
If the input cannot be interpreted as a supported SynCRN source.
|
|
633
|
+
|
|
634
|
+
.. rubric:: Example
|
|
635
|
+
|
|
636
|
+
.. code-block:: python
|
|
637
|
+
|
|
638
|
+
incidence = extract_syncrn_incidence(crn)
|
|
639
|
+
print(incidence.pre)
|
|
640
|
+
print(incidence.post)
|
|
641
|
+
"""
|
|
642
|
+
if isinstance(crn, nx.DiGraph):
|
|
643
|
+
return _extract_from_syncrn_digraph(crn)
|
|
644
|
+
|
|
645
|
+
if hasattr(crn, "species") and hasattr(crn, "reactions"):
|
|
646
|
+
return _extract_from_syncrn_object(crn)
|
|
647
|
+
|
|
648
|
+
if hasattr(crn, "to_digraph"):
|
|
649
|
+
g = crn.to_digraph()
|
|
650
|
+
if isinstance(g, nx.DiGraph):
|
|
651
|
+
return _extract_from_syncrn_digraph(g)
|
|
652
|
+
|
|
653
|
+
raise TypeError(
|
|
654
|
+
"crn must be a SynCRN-like object with species/reactions or an nx.DiGraph "
|
|
655
|
+
"in SynCRN bipartite format"
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
class PetriNet:
|
|
660
|
+
"""Minimal Petri net container with marking semantics and SynCRN metadata.
|
|
661
|
+
|
|
662
|
+
Places correspond to species and transitions correspond to reactions.
|
|
663
|
+
The class stores a lightweight Petri-net representation with utilities
|
|
664
|
+
for adding places and transitions, checking enabledness, firing
|
|
665
|
+
transitions, and converting between mapping-based and tuple-based
|
|
666
|
+
markings.
|
|
667
|
+
|
|
668
|
+
:ivar places: Set of place identifiers.
|
|
669
|
+
:ivar transitions: Mapping from transition id to :class:`Transition`.
|
|
670
|
+
:ivar place_labels: Optional human-readable labels for places.
|
|
671
|
+
:ivar transition_labels: Optional human-readable labels for transitions.
|
|
672
|
+
:ivar place_source_node_ids: Provenance mapping for places.
|
|
673
|
+
:ivar transition_source_node_ids: Provenance mapping for transitions.
|
|
674
|
+
:ivar graph_attrs: Graph-level metadata copied from the source.
|
|
675
|
+
:ivar metadata: Additional metadata.
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
.. rubric:: Example
|
|
679
|
+
|
|
680
|
+
.. code-block:: python
|
|
681
|
+
|
|
682
|
+
net = PetriNet()
|
|
683
|
+
net.add_place("A")
|
|
684
|
+
net.add_place("B")
|
|
685
|
+
net.add_transition("r1", pre={"A": 1}, post={"B": 1})
|
|
686
|
+
|
|
687
|
+
m0 = {"A": 1}
|
|
688
|
+
assert net.enabled(m0, "r1")
|
|
689
|
+
m1 = net.fire(m0, "r1")
|
|
690
|
+
print(m1) # {'A': 0, 'B': 1}
|
|
691
|
+
"""
|
|
692
|
+
|
|
693
|
+
def __init__(self) -> None:
|
|
694
|
+
"""Initialize an empty Petri net.
|
|
695
|
+
|
|
696
|
+
:return:
|
|
697
|
+
None
|
|
698
|
+
:rtype: None
|
|
699
|
+
"""
|
|
700
|
+
self.places: Set[Place] = set()
|
|
701
|
+
self.transitions: Dict[TransitionId, Transition] = {}
|
|
702
|
+
self._place_index: Dict[Place, int] = {}
|
|
703
|
+
self._transition_index: Dict[TransitionId, int] = {}
|
|
704
|
+
self.place_labels: Dict[Place, str] = {}
|
|
705
|
+
self.transition_labels: Dict[TransitionId, str] = {}
|
|
706
|
+
self.place_source_node_ids: Dict[Place, Hashable] = {}
|
|
707
|
+
self.transition_source_node_ids: Dict[TransitionId, Hashable] = {}
|
|
708
|
+
self.graph_attrs: Dict[str, Any] = {}
|
|
709
|
+
self.metadata: Dict[str, Any] = {}
|
|
710
|
+
|
|
711
|
+
@classmethod
|
|
712
|
+
def from_syncrn(cls, crn: Any) -> "PetriNet":
|
|
713
|
+
"""Build a Petri-net view directly from SynCRN incidence data.
|
|
714
|
+
|
|
715
|
+
:param crn:
|
|
716
|
+
SynCRN-like object or SynCRN bipartite digraph.
|
|
717
|
+
:type crn: Any
|
|
718
|
+
:return:
|
|
719
|
+
Petri net constructed from the canonical incidence view.
|
|
720
|
+
:rtype: PetriNet
|
|
721
|
+
|
|
722
|
+
.. rubric:: Example
|
|
723
|
+
|
|
724
|
+
.. code-block:: python
|
|
725
|
+
|
|
726
|
+
net = PetriNet.from_syncrn(crn)
|
|
727
|
+
print(net.place_order)
|
|
728
|
+
print(net.transition_order)
|
|
729
|
+
"""
|
|
730
|
+
incidence = extract_syncrn_incidence(crn)
|
|
731
|
+
net = cls()
|
|
732
|
+
net.graph_attrs.update(incidence.graph_attrs)
|
|
733
|
+
net.metadata.update(incidence.metadata)
|
|
734
|
+
net.metadata["source"] = "syncrn"
|
|
735
|
+
|
|
736
|
+
for sid in incidence.species_order:
|
|
737
|
+
net.add_place(
|
|
738
|
+
sid,
|
|
739
|
+
label=incidence.species_labels.get(sid, sid),
|
|
740
|
+
source_node_id=incidence.species_source_node_ids.get(sid),
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
for rid in incidence.reaction_order:
|
|
744
|
+
net.add_transition(
|
|
745
|
+
rid,
|
|
746
|
+
pre=incidence.pre.get(rid, {}),
|
|
747
|
+
post=incidence.post.get(rid, {}),
|
|
748
|
+
label=incidence.reaction_labels.get(rid, rid),
|
|
749
|
+
source_reaction_id=rid,
|
|
750
|
+
)
|
|
751
|
+
if rid in incidence.reaction_source_node_ids:
|
|
752
|
+
net.transition_source_node_ids[rid] = (
|
|
753
|
+
incidence.reaction_source_node_ids[rid]
|
|
754
|
+
)
|
|
755
|
+
|
|
756
|
+
return net
|
|
757
|
+
|
|
758
|
+
@property
|
|
759
|
+
def place_order(self) -> List[Place]:
|
|
760
|
+
"""Return places in insertion order.
|
|
761
|
+
|
|
762
|
+
:return:
|
|
763
|
+
Ordered place identifiers.
|
|
764
|
+
:rtype: List[Place]
|
|
765
|
+
"""
|
|
766
|
+
return list(self._place_index.keys())
|
|
767
|
+
|
|
768
|
+
@property
|
|
769
|
+
def transition_order(self) -> List[TransitionId]:
|
|
770
|
+
"""Return transitions in insertion order.
|
|
771
|
+
|
|
772
|
+
:return:
|
|
773
|
+
Ordered transition identifiers.
|
|
774
|
+
:rtype: List[TransitionId]
|
|
775
|
+
"""
|
|
776
|
+
return list(self._transition_index.keys())
|
|
777
|
+
|
|
778
|
+
def add_place(
|
|
779
|
+
self,
|
|
780
|
+
p: Place,
|
|
781
|
+
*,
|
|
782
|
+
label: Optional[str] = None,
|
|
783
|
+
source_node_id: Optional[Hashable] = None,
|
|
784
|
+
) -> None:
|
|
785
|
+
"""Add a place to the Petri net.
|
|
786
|
+
|
|
787
|
+
If the place already exists, only optional metadata is updated.
|
|
788
|
+
|
|
789
|
+
:param p:
|
|
790
|
+
Place identifier.
|
|
791
|
+
:type p: Place
|
|
792
|
+
:param label:
|
|
793
|
+
Optional display label.
|
|
794
|
+
:type label: Optional[str]
|
|
795
|
+
:param source_node_id:
|
|
796
|
+
Optional provenance node id from the source CRN.
|
|
797
|
+
:type source_node_id: Optional[Hashable]
|
|
798
|
+
:return:
|
|
799
|
+
None
|
|
800
|
+
:rtype: None
|
|
801
|
+
"""
|
|
802
|
+
if p not in self.places:
|
|
803
|
+
self.places.add(p)
|
|
804
|
+
self._place_index[p] = len(self._place_index)
|
|
805
|
+
if label is not None:
|
|
806
|
+
self.place_labels[p] = str(label)
|
|
807
|
+
if source_node_id is not None:
|
|
808
|
+
self.place_source_node_ids[p] = source_node_id
|
|
809
|
+
|
|
810
|
+
def add_transition(
|
|
811
|
+
self,
|
|
812
|
+
tid: TransitionId,
|
|
813
|
+
pre: Mapping[Place, int],
|
|
814
|
+
post: Mapping[Place, int],
|
|
815
|
+
*,
|
|
816
|
+
label: Optional[str] = None,
|
|
817
|
+
source_reaction_id: Optional[str] = None,
|
|
818
|
+
metadata: Optional[MutableMapping[str, Any]] = None,
|
|
819
|
+
) -> None:
|
|
820
|
+
"""Add or replace a transition in the Petri net.
|
|
821
|
+
|
|
822
|
+
Zero or invalid non-positive weights are filtered out before storage.
|
|
823
|
+
Any places referenced by ``pre`` or ``post`` are created automatically.
|
|
824
|
+
|
|
825
|
+
:param tid:
|
|
826
|
+
Transition identifier.
|
|
827
|
+
:type tid: TransitionId
|
|
828
|
+
:param pre:
|
|
829
|
+
Input arc multiset mapping ``place -> coefficient``.
|
|
830
|
+
:type pre: Mapping[Place, int]
|
|
831
|
+
:param post:
|
|
832
|
+
Output arc multiset mapping ``place -> coefficient``.
|
|
833
|
+
:type post: Mapping[Place, int]
|
|
834
|
+
:param label:
|
|
835
|
+
Optional display label.
|
|
836
|
+
:type label: Optional[str]
|
|
837
|
+
:param source_reaction_id:
|
|
838
|
+
Optional source reaction identifier.
|
|
839
|
+
:type source_reaction_id: Optional[str]
|
|
840
|
+
:param metadata:
|
|
841
|
+
Optional metadata attached to the transition.
|
|
842
|
+
:type metadata: Optional[MutableMapping[str, Any]]
|
|
843
|
+
:return:
|
|
844
|
+
None
|
|
845
|
+
:rtype: None
|
|
846
|
+
|
|
847
|
+
.. rubric:: Example
|
|
848
|
+
|
|
849
|
+
.. code-block:: python
|
|
850
|
+
|
|
851
|
+
net.add_transition(
|
|
852
|
+
"r1",
|
|
853
|
+
pre={"A": 2, "B": 1},
|
|
854
|
+
post={"C": 1},
|
|
855
|
+
label="2A + B -> C",
|
|
856
|
+
)
|
|
857
|
+
"""
|
|
858
|
+
clean_pre = {
|
|
859
|
+
str(p): _coerce_stoich(w) for p, w in pre.items() if _safe_int(w, 0) > 0
|
|
860
|
+
}
|
|
861
|
+
clean_post = {
|
|
862
|
+
str(p): _coerce_stoich(w) for p, w in post.items() if _safe_int(w, 0) > 0
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
for p in set(clean_pre) | set(clean_post):
|
|
866
|
+
self.add_place(p)
|
|
867
|
+
|
|
868
|
+
tid = str(tid)
|
|
869
|
+
if tid not in self._transition_index:
|
|
870
|
+
self._transition_index[tid] = len(self._transition_index)
|
|
871
|
+
|
|
872
|
+
self.transitions[tid] = Transition(
|
|
873
|
+
tid=tid,
|
|
874
|
+
pre=clean_pre,
|
|
875
|
+
post=clean_post,
|
|
876
|
+
label=None if label is None else str(label),
|
|
877
|
+
source_reaction_id=(
|
|
878
|
+
None if source_reaction_id is None else str(source_reaction_id)
|
|
879
|
+
),
|
|
880
|
+
metadata=dict(metadata or {}),
|
|
881
|
+
)
|
|
882
|
+
if label is not None:
|
|
883
|
+
self.transition_labels[tid] = str(label)
|
|
884
|
+
|
|
885
|
+
def enabled(self, marking: Marking, tid: TransitionId) -> bool:
|
|
886
|
+
"""Test whether a transition is enabled under a marking.
|
|
887
|
+
|
|
888
|
+
A transition is enabled if every required input place has at least the
|
|
889
|
+
corresponding token count.
|
|
890
|
+
|
|
891
|
+
:param marking:
|
|
892
|
+
Current marking as ``place -> token_count``.
|
|
893
|
+
:type marking: Marking
|
|
894
|
+
:param tid:
|
|
895
|
+
Transition identifier.
|
|
896
|
+
:type tid: TransitionId
|
|
897
|
+
:return:
|
|
898
|
+
``True`` if the transition is enabled, else ``False``.
|
|
899
|
+
:rtype: bool
|
|
900
|
+
"""
|
|
901
|
+
t = self.transitions[tid]
|
|
902
|
+
return all(int(marking.get(p, 0)) >= w for p, w in t.pre.items())
|
|
903
|
+
|
|
904
|
+
def fire(self, marking: Marking, tid: TransitionId) -> Dict[Place, int]:
|
|
905
|
+
"""Fire a transition and return the successor marking.
|
|
906
|
+
|
|
907
|
+
This function does not itself check enabledness. If the transition is
|
|
908
|
+
not enabled, negative token counts may appear in the result.
|
|
909
|
+
|
|
910
|
+
:param marking:
|
|
911
|
+
Current marking.
|
|
912
|
+
:type marking: Marking
|
|
913
|
+
:param tid:
|
|
914
|
+
Transition identifier to fire.
|
|
915
|
+
:type tid: TransitionId
|
|
916
|
+
:return:
|
|
917
|
+
Successor marking after consuming ``pre`` and producing ``post``.
|
|
918
|
+
:rtype: Dict[Place, int]
|
|
919
|
+
|
|
920
|
+
.. rubric:: Example
|
|
921
|
+
|
|
922
|
+
.. code-block:: python
|
|
923
|
+
|
|
924
|
+
m0 = {"A": 2, "B": 1}
|
|
925
|
+
m1 = net.fire(m0, "r1")
|
|
926
|
+
"""
|
|
927
|
+
t = self.transitions[tid]
|
|
928
|
+
nxt = {str(p): int(v) for p, v in marking.items()}
|
|
929
|
+
for p, w in t.pre.items():
|
|
930
|
+
nxt[p] = nxt.get(p, 0) - w
|
|
931
|
+
for p, w in t.post.items():
|
|
932
|
+
nxt[p] = nxt.get(p, 0) + w
|
|
933
|
+
return nxt
|
|
934
|
+
|
|
935
|
+
def marking_to_tuple(self, m: Marking) -> Tuple[int, ...]:
|
|
936
|
+
"""Convert a mapping-based marking into a tuple in place order.
|
|
937
|
+
|
|
938
|
+
:param m:
|
|
939
|
+
Marking mapping.
|
|
940
|
+
:type m: Marking
|
|
941
|
+
:return:
|
|
942
|
+
Tuple of token counts aligned to :attr:`place_order`.
|
|
943
|
+
:rtype: Tuple[int, ...]
|
|
944
|
+
"""
|
|
945
|
+
arr = [0] * len(self._place_index)
|
|
946
|
+
for p, idx in self._place_index.items():
|
|
947
|
+
arr[idx] = int(m.get(p, 0))
|
|
948
|
+
return tuple(arr)
|
|
949
|
+
|
|
950
|
+
def tuple_to_marking(self, values: Iterable[int]) -> Dict[Place, int]:
|
|
951
|
+
"""Convert a tuple-like token vector into a sparse marking mapping.
|
|
952
|
+
|
|
953
|
+
Zero entries are omitted from the returned dictionary.
|
|
954
|
+
|
|
955
|
+
:param values:
|
|
956
|
+
Iterable of token counts aligned to :attr:`place_order`.
|
|
957
|
+
:type values: Iterable[int]
|
|
958
|
+
:return:
|
|
959
|
+
Sparse marking mapping.
|
|
960
|
+
:rtype: Dict[Place, int]
|
|
961
|
+
"""
|
|
962
|
+
vals = list(values)
|
|
963
|
+
return {
|
|
964
|
+
p: int(vals[idx])
|
|
965
|
+
for p, idx in self._place_index.items()
|
|
966
|
+
if idx < len(vals) and int(vals[idx]) != 0
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
def place_name(self, p: Place) -> str:
|
|
970
|
+
"""Return the display label of a place if available.
|
|
971
|
+
|
|
972
|
+
:param p:
|
|
973
|
+
Place identifier.
|
|
974
|
+
:type p: Place
|
|
975
|
+
:return:
|
|
976
|
+
Display label or the identifier itself.
|
|
977
|
+
:rtype: str
|
|
978
|
+
"""
|
|
979
|
+
return self.place_labels.get(p, p)
|
|
980
|
+
|
|
981
|
+
def transition_name(self, tid: TransitionId) -> str:
|
|
982
|
+
"""Return the display label of a transition if available.
|
|
983
|
+
|
|
984
|
+
:param tid:
|
|
985
|
+
Transition identifier.
|
|
986
|
+
:type tid: TransitionId
|
|
987
|
+
:return:
|
|
988
|
+
Display label or the identifier itself.
|
|
989
|
+
:rtype: str
|
|
990
|
+
"""
|
|
991
|
+
return self.transition_labels.get(tid, tid)
|
|
992
|
+
|
|
993
|
+
def to_pre_post(self) -> Dict[str, Any]:
|
|
994
|
+
"""Export the Petri net as place-indexed pre/post adjacency maps.
|
|
995
|
+
|
|
996
|
+
The returned structure is often convenient for reachability, firing,
|
|
997
|
+
or incidence-based downstream algorithms.
|
|
998
|
+
|
|
999
|
+
:return:
|
|
1000
|
+
Dictionary containing places, transitions, labels, pre/post maps,
|
|
1001
|
+
graph attributes, and metadata.
|
|
1002
|
+
:rtype: Dict[str, Any]
|
|
1003
|
+
|
|
1004
|
+
.. rubric:: Example
|
|
1005
|
+
|
|
1006
|
+
.. code-block:: python
|
|
1007
|
+
|
|
1008
|
+
data = net.to_pre_post()
|
|
1009
|
+
print(data["pre"])
|
|
1010
|
+
print(data["post"])
|
|
1011
|
+
"""
|
|
1012
|
+
pre = {p: {} for p in self.place_order}
|
|
1013
|
+
post = {p: {} for p in self.place_order}
|
|
1014
|
+
for tid in self.transition_order:
|
|
1015
|
+
t = self.transitions[tid]
|
|
1016
|
+
for p, w in t.pre.items():
|
|
1017
|
+
pre.setdefault(p, {})[tid] = w
|
|
1018
|
+
for p, w in t.post.items():
|
|
1019
|
+
post.setdefault(p, {})[tid] = w
|
|
1020
|
+
return {
|
|
1021
|
+
"places": self.place_order,
|
|
1022
|
+
"transitions": self.transition_order,
|
|
1023
|
+
"place_labels": dict(self.place_labels),
|
|
1024
|
+
"transition_labels": dict(self.transition_labels),
|
|
1025
|
+
"pre": pre,
|
|
1026
|
+
"post": post,
|
|
1027
|
+
"graph_attrs": dict(self.graph_attrs),
|
|
1028
|
+
"metadata": dict(self.metadata),
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
def __repr__(self) -> str: # pragma: no cover - simple repr
|
|
1032
|
+
"""Return a compact debug representation.
|
|
1033
|
+
|
|
1034
|
+
:return:
|
|
1035
|
+
Readable Petri net summary.
|
|
1036
|
+
:rtype: str
|
|
1037
|
+
"""
|
|
1038
|
+
return (
|
|
1039
|
+
f"PetriNet(n_places={len(self.places)}, "
|
|
1040
|
+
f"n_transitions={len(self.transitions)})"
|
|
1041
|
+
)
|