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,656 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Iterable, Tuple
|
|
4
|
+
|
|
5
|
+
import networkx as nx
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RCExtractor:
|
|
9
|
+
"""Extract reaction-center information from an ITS graph.
|
|
10
|
+
|
|
11
|
+
This class identifies the reaction center (RC) from an imaginary transition
|
|
12
|
+
state (ITS) graph using simple structural change rules on paired node and
|
|
13
|
+
edge attributes.
|
|
14
|
+
|
|
15
|
+
A node is considered part of the reaction center when at least one tracked
|
|
16
|
+
paired node attribute differs between the reactant and product states. An
|
|
17
|
+
edge is considered part of the reaction center when its ``standard_order``
|
|
18
|
+
is non-zero.
|
|
19
|
+
|
|
20
|
+
Reaction-center rules
|
|
21
|
+
---------------------
|
|
22
|
+
Edge is RC if:
|
|
23
|
+
|
|
24
|
+
- ``standard_order != 0``
|
|
25
|
+
|
|
26
|
+
Node is RC if any of these paired attributes differ:
|
|
27
|
+
|
|
28
|
+
- ``element``
|
|
29
|
+
- ``hcount`` (after hydrogen-pair normalization)
|
|
30
|
+
- ``charge``
|
|
31
|
+
- ``lone_pairs`` (or alias ``lp``)
|
|
32
|
+
- ``radical``
|
|
33
|
+
- ``valence_electrons``
|
|
34
|
+
|
|
35
|
+
Default exported attribute sets
|
|
36
|
+
-------------------------------
|
|
37
|
+
By default, the extracted RC metadata also stores filtered node and edge
|
|
38
|
+
attribute snapshots for the following attribute names.
|
|
39
|
+
|
|
40
|
+
Default node attributes:
|
|
41
|
+
|
|
42
|
+
- ``element``
|
|
43
|
+
- ``aromatic``
|
|
44
|
+
- ``hcount``
|
|
45
|
+
- ``charge``
|
|
46
|
+
- ``neighbors``
|
|
47
|
+
- ``hybridization``
|
|
48
|
+
- ``atom_map``
|
|
49
|
+
- ``lone_pairs``
|
|
50
|
+
- ``radical``
|
|
51
|
+
- ``valence_electrons``
|
|
52
|
+
- ``partial_charge``
|
|
53
|
+
|
|
54
|
+
Default edge attributes:
|
|
55
|
+
|
|
56
|
+
- ``kekule_order``
|
|
57
|
+
- ``sigma_order``
|
|
58
|
+
- ``pi_order``
|
|
59
|
+
- ``order``
|
|
60
|
+
- ``bond_type``
|
|
61
|
+
- ``conjugated``
|
|
62
|
+
- ``in_ring``
|
|
63
|
+
|
|
64
|
+
.. rubric:: Notes
|
|
65
|
+
|
|
66
|
+
- All original ITS node and edge attributes are preserved.
|
|
67
|
+
- The extracted RC subgraph stores metadata in ``graph.graph["rc"]``.
|
|
68
|
+
- Endpoints of RC edges are automatically included as RC nodes.
|
|
69
|
+
- Lone-pair attributes may be stored under either ``"lone_pairs"`` or
|
|
70
|
+
``"lp"``.
|
|
71
|
+
- Hydrogen comparison is handled specially: ``hcount`` is normalized to a
|
|
72
|
+
relative change form before comparison.
|
|
73
|
+
- Filtered attribute snapshots are stored in ``graph.graph["rc"]`` under
|
|
74
|
+
``"node_attrs"``, ``"edge_attrs"``, ``"default_node_attrs"``, and
|
|
75
|
+
``"default_edge_attrs"``.
|
|
76
|
+
|
|
77
|
+
.. rubric:: Example
|
|
78
|
+
|
|
79
|
+
.. code-block:: python
|
|
80
|
+
|
|
81
|
+
import networkx as nx
|
|
82
|
+
|
|
83
|
+
its = nx.Graph()
|
|
84
|
+
|
|
85
|
+
its.add_node(
|
|
86
|
+
1,
|
|
87
|
+
element=("C", "C"),
|
|
88
|
+
hcount=(2, 1),
|
|
89
|
+
charge=(0, 0),
|
|
90
|
+
lone_pairs=(0, 0),
|
|
91
|
+
aromatic=(False, False),
|
|
92
|
+
atom_map=1,
|
|
93
|
+
)
|
|
94
|
+
its.add_node(
|
|
95
|
+
2,
|
|
96
|
+
element=("O", "O"),
|
|
97
|
+
hcount=(0, 0),
|
|
98
|
+
charge=(0, -1),
|
|
99
|
+
lone_pairs=(2, 3),
|
|
100
|
+
aromatic=(False, False),
|
|
101
|
+
atom_map=2,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
its.add_edge(
|
|
105
|
+
1,
|
|
106
|
+
2,
|
|
107
|
+
order=(1, 1),
|
|
108
|
+
standard_order=1,
|
|
109
|
+
bond_type=("single", "single"),
|
|
110
|
+
conjugated=False,
|
|
111
|
+
in_ring=False,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
extractor = RCExtractor()
|
|
115
|
+
|
|
116
|
+
rc_graph = extractor.extract(its)
|
|
117
|
+
print(rc_graph.graph["rc"]["default_node_attrs"])
|
|
118
|
+
print(rc_graph.graph["rc"]["node_attrs"])
|
|
119
|
+
|
|
120
|
+
annotated = extractor.annotate(its)
|
|
121
|
+
print(annotated.nodes[1]["rc_reasons"])
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
NODE_KEYS = (
|
|
125
|
+
"element",
|
|
126
|
+
"hcount",
|
|
127
|
+
"charge",
|
|
128
|
+
"lone_pairs",
|
|
129
|
+
"radical",
|
|
130
|
+
"valence_electrons",
|
|
131
|
+
)
|
|
132
|
+
LP_ALIASES = ("lone_pairs", "lp")
|
|
133
|
+
|
|
134
|
+
DEFAULT_NODE_ATTRS = (
|
|
135
|
+
"element",
|
|
136
|
+
"aromatic",
|
|
137
|
+
"hcount",
|
|
138
|
+
"charge",
|
|
139
|
+
"neighbors",
|
|
140
|
+
"hybridization",
|
|
141
|
+
"atom_map",
|
|
142
|
+
"lone_pairs",
|
|
143
|
+
"radical",
|
|
144
|
+
"valence_electrons",
|
|
145
|
+
"partial_charge",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
DEFAULT_EDGE_ATTRS = (
|
|
149
|
+
"kekule_order",
|
|
150
|
+
"sigma_order",
|
|
151
|
+
"pi_order",
|
|
152
|
+
"order",
|
|
153
|
+
"bond_type",
|
|
154
|
+
"conjugated",
|
|
155
|
+
"in_ring",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def __init__(
|
|
159
|
+
self,
|
|
160
|
+
node_attrs: Iterable[str] | None = None,
|
|
161
|
+
edge_attrs: Iterable[str] | None = None,
|
|
162
|
+
preserve_full_attrs: bool = False,
|
|
163
|
+
) -> None:
|
|
164
|
+
"""
|
|
165
|
+
Initialize the reaction-center extractor.
|
|
166
|
+
|
|
167
|
+
:param node_attrs: Attribute names to export for RC nodes in
|
|
168
|
+
``graph.graph["rc"]["node_attrs"]``. If ``None``, the class
|
|
169
|
+
defaults are used.
|
|
170
|
+
:type node_attrs: Iterable[str] | None
|
|
171
|
+
:param edge_attrs: Attribute names to export for RC edges in
|
|
172
|
+
``graph.graph["rc"]["edge_attrs"]``. If ``None``, the class
|
|
173
|
+
defaults are used.
|
|
174
|
+
:type edge_attrs: Iterable[str] | None
|
|
175
|
+
:param preserve_full_attrs: If ``True``, export complete node and edge
|
|
176
|
+
attribute dictionaries in the RC metadata snapshots instead of the
|
|
177
|
+
configured attribute subset.
|
|
178
|
+
:type preserve_full_attrs: bool
|
|
179
|
+
"""
|
|
180
|
+
self._node_attrs = tuple(node_attrs or self.DEFAULT_NODE_ATTRS)
|
|
181
|
+
self._edge_attrs = tuple(edge_attrs or self.DEFAULT_EDGE_ATTRS)
|
|
182
|
+
self.preserve_full_attrs = preserve_full_attrs
|
|
183
|
+
|
|
184
|
+
def __repr__(self) -> str:
|
|
185
|
+
"""
|
|
186
|
+
Return a compact string representation.
|
|
187
|
+
|
|
188
|
+
:return: String representation of the extractor.
|
|
189
|
+
:rtype: str
|
|
190
|
+
"""
|
|
191
|
+
return (
|
|
192
|
+
f"{self.__class__.__name__}("
|
|
193
|
+
f"node_attrs={list(self._node_attrs)!r}, "
|
|
194
|
+
f"edge_attrs={list(self._edge_attrs)!r})"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def node_attrs(self) -> tuple[str, ...]:
|
|
199
|
+
"""
|
|
200
|
+
Return the configured RC node attributes.
|
|
201
|
+
|
|
202
|
+
:return: Configured node attribute names.
|
|
203
|
+
:rtype: tuple[str, ...]
|
|
204
|
+
"""
|
|
205
|
+
return self._node_attrs
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def edge_attrs(self) -> tuple[str, ...]:
|
|
209
|
+
"""
|
|
210
|
+
Return the configured RC edge attributes.
|
|
211
|
+
|
|
212
|
+
:return: Configured edge attribute names.
|
|
213
|
+
:rtype: tuple[str, ...]
|
|
214
|
+
"""
|
|
215
|
+
return self._edge_attrs
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def _edge_key(u: int, v: int) -> tuple[int, int]:
|
|
219
|
+
"""
|
|
220
|
+
Normalize an undirected edge key.
|
|
221
|
+
|
|
222
|
+
:param u: First node identifier.
|
|
223
|
+
:type u: int
|
|
224
|
+
:param v: Second node identifier.
|
|
225
|
+
:type v: int
|
|
226
|
+
:return: Sorted undirected edge key.
|
|
227
|
+
:rtype: tuple[int, int]
|
|
228
|
+
"""
|
|
229
|
+
return (u, v) if u <= v else (v, u)
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
def _is_pair(value: Any) -> bool:
|
|
233
|
+
"""
|
|
234
|
+
Check whether a value looks like a 2-item paired attribute.
|
|
235
|
+
|
|
236
|
+
:param value: Value to inspect.
|
|
237
|
+
:type value: Any
|
|
238
|
+
:return: ``True`` if the value is a tuple or list of length 2,
|
|
239
|
+
otherwise ``False``.
|
|
240
|
+
:rtype: bool
|
|
241
|
+
"""
|
|
242
|
+
return isinstance(value, (tuple, list)) and len(value) == 2
|
|
243
|
+
|
|
244
|
+
@staticmethod
|
|
245
|
+
def _normalize_h_pair(h_react: int, h_prod: int) -> Tuple[int, int]:
|
|
246
|
+
"""Normalize reactant and product hydrogen counts to relative change form.
|
|
247
|
+
|
|
248
|
+
This removes the shared hydrogen baseline and keeps only the relative
|
|
249
|
+
hydrogen change between the two states.
|
|
250
|
+
|
|
251
|
+
.. rubric:: Examples
|
|
252
|
+
|
|
253
|
+
``(1, 1) -> (0, 0)``
|
|
254
|
+
``(2, 1) -> (1, 0)``
|
|
255
|
+
``(1, 2) -> (0, 1)``
|
|
256
|
+
|
|
257
|
+
:param h_react: Hydrogen count in the reactant state.
|
|
258
|
+
:type h_react: int
|
|
259
|
+
:param h_prod: Hydrogen count in the product state.
|
|
260
|
+
:type h_prod: int
|
|
261
|
+
:return: Normalized hydrogen pair.
|
|
262
|
+
:rtype: Tuple[int, int]
|
|
263
|
+
|
|
264
|
+
.. rubric:: Example
|
|
265
|
+
|
|
266
|
+
.. code-block:: python
|
|
267
|
+
|
|
268
|
+
RCExtractor._normalize_h_pair(2, 1) # (1, 0)
|
|
269
|
+
RCExtractor._normalize_h_pair(1, 2) # (0, 1)
|
|
270
|
+
RCExtractor._normalize_h_pair(1, 1) # (0, 0)
|
|
271
|
+
"""
|
|
272
|
+
common = min(h_react, h_prod)
|
|
273
|
+
return h_react - common, h_prod - common
|
|
274
|
+
|
|
275
|
+
@classmethod
|
|
276
|
+
def _pair_diff(cls, value: Any) -> bool:
|
|
277
|
+
"""
|
|
278
|
+
Check whether a paired value differs between the two states.
|
|
279
|
+
|
|
280
|
+
:param value: Paired attribute value, typically a 2-item tuple or list.
|
|
281
|
+
:type value: Any
|
|
282
|
+
:return: ``True`` if the value is a valid pair and the two entries are
|
|
283
|
+
different, otherwise ``False``.
|
|
284
|
+
:rtype: bool
|
|
285
|
+
"""
|
|
286
|
+
return cls._is_pair(value) and value[0] != value[1]
|
|
287
|
+
|
|
288
|
+
@classmethod
|
|
289
|
+
def _hcount_diff(cls, value: Any) -> bool:
|
|
290
|
+
"""Check whether a hydrogen-count pair differs after normalization.
|
|
291
|
+
|
|
292
|
+
Hydrogen counts are treated specially. Instead of directly comparing the
|
|
293
|
+
raw pair, the shared hydrogen baseline is removed first by calling
|
|
294
|
+
:meth:`_normalize_h_pair`.
|
|
295
|
+
|
|
296
|
+
:param value: Hydrogen-count pair, usually ``(h_react, h_prod)``.
|
|
297
|
+
:type value: Any
|
|
298
|
+
:return: ``True`` if the normalized hydrogen counts differ, otherwise
|
|
299
|
+
``False``.
|
|
300
|
+
:rtype: bool
|
|
301
|
+
|
|
302
|
+
.. rubric:: Example
|
|
303
|
+
|
|
304
|
+
.. code-block:: python
|
|
305
|
+
|
|
306
|
+
RCExtractor._hcount_diff((1, 1)) # False
|
|
307
|
+
RCExtractor._hcount_diff((2, 1)) # True
|
|
308
|
+
RCExtractor._hcount_diff((1, 2)) # True
|
|
309
|
+
"""
|
|
310
|
+
if not cls._is_pair(value):
|
|
311
|
+
return False
|
|
312
|
+
norm = cls._normalize_h_pair(int(value[0]), int(value[1]))
|
|
313
|
+
return norm[0] != norm[1]
|
|
314
|
+
|
|
315
|
+
@classmethod
|
|
316
|
+
def _get_lp_value(cls, attrs: dict[str, Any]) -> Any:
|
|
317
|
+
"""
|
|
318
|
+
Retrieve the lone-pair attribute from supported aliases.
|
|
319
|
+
|
|
320
|
+
:param attrs: Node attribute dictionary.
|
|
321
|
+
:type attrs: dict[str, Any]
|
|
322
|
+
:return: Lone-pair value if present, otherwise ``None``.
|
|
323
|
+
:rtype: Any
|
|
324
|
+
"""
|
|
325
|
+
for key in cls.LP_ALIASES:
|
|
326
|
+
if key in attrs:
|
|
327
|
+
return attrs[key]
|
|
328
|
+
return None
|
|
329
|
+
|
|
330
|
+
@classmethod
|
|
331
|
+
def _node_reasons(cls, attrs: dict[str, Any]) -> list[str]:
|
|
332
|
+
"""Determine why a node belongs to the reaction center.
|
|
333
|
+
|
|
334
|
+
Each tracked node attribute is inspected, and any attribute whose paired
|
|
335
|
+
values differ is recorded as a reaction-center reason. The ``hcount``
|
|
336
|
+
field is compared using hydrogen normalization.
|
|
337
|
+
|
|
338
|
+
:param attrs: Node attribute dictionary from the ITS graph.
|
|
339
|
+
:type attrs: dict[str, Any]
|
|
340
|
+
:return: List of attribute names that triggered RC membership for the
|
|
341
|
+
node.
|
|
342
|
+
:rtype: list[str]
|
|
343
|
+
|
|
344
|
+
.. rubric:: Example
|
|
345
|
+
|
|
346
|
+
.. code-block:: python
|
|
347
|
+
|
|
348
|
+
attrs = {
|
|
349
|
+
"element": ("N", "N"),
|
|
350
|
+
"hcount": (2, 1),
|
|
351
|
+
"charge": (0, 1),
|
|
352
|
+
"lone_pairs": (1, 1),
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
reasons = RCExtractor._node_reasons(attrs)
|
|
356
|
+
print(reasons) # ['hcount', 'charge']
|
|
357
|
+
"""
|
|
358
|
+
reasons: list[str] = []
|
|
359
|
+
|
|
360
|
+
for key in cls.NODE_KEYS:
|
|
361
|
+
if key == "lone_pairs":
|
|
362
|
+
value = cls._get_lp_value(attrs)
|
|
363
|
+
actual_key = "lone_pairs" if "lone_pairs" in attrs else "lp"
|
|
364
|
+
is_diff = cls._pair_diff(value)
|
|
365
|
+
elif key == "hcount":
|
|
366
|
+
value = attrs.get(key)
|
|
367
|
+
actual_key = key
|
|
368
|
+
is_diff = cls._hcount_diff(value)
|
|
369
|
+
else:
|
|
370
|
+
value = attrs.get(key)
|
|
371
|
+
actual_key = key
|
|
372
|
+
is_diff = cls._pair_diff(value)
|
|
373
|
+
|
|
374
|
+
if is_diff:
|
|
375
|
+
reasons.append(actual_key)
|
|
376
|
+
|
|
377
|
+
return reasons
|
|
378
|
+
|
|
379
|
+
@staticmethod
|
|
380
|
+
def _edge_reasons(attrs: dict[str, Any]) -> list[str]:
|
|
381
|
+
"""
|
|
382
|
+
Determine why an edge belongs to the reaction center.
|
|
383
|
+
|
|
384
|
+
An edge is marked as part of the reaction center when its
|
|
385
|
+
``standard_order`` is non-zero.
|
|
386
|
+
|
|
387
|
+
:param attrs: Edge attribute dictionary from the ITS graph.
|
|
388
|
+
:type attrs: dict[str, Any]
|
|
389
|
+
:return: List containing ``"standard_order"`` if the edge is in the
|
|
390
|
+
reaction center, otherwise an empty list.
|
|
391
|
+
:rtype: list[str]
|
|
392
|
+
"""
|
|
393
|
+
value = attrs.get("standard_order", 0.0)
|
|
394
|
+
if value != 0 and value != 0.0:
|
|
395
|
+
return ["standard_order"]
|
|
396
|
+
return []
|
|
397
|
+
|
|
398
|
+
def _select_attrs(
|
|
399
|
+
self,
|
|
400
|
+
attrs: dict[str, Any],
|
|
401
|
+
keys: Iterable[str],
|
|
402
|
+
) -> dict[str, Any]:
|
|
403
|
+
"""
|
|
404
|
+
Select a subset of attributes from a dictionary.
|
|
405
|
+
|
|
406
|
+
Missing keys are ignored.
|
|
407
|
+
|
|
408
|
+
:param attrs: Source attribute dictionary.
|
|
409
|
+
:type attrs: dict[str, Any]
|
|
410
|
+
:param keys: Attribute names to retain.
|
|
411
|
+
:type keys: Iterable[str]
|
|
412
|
+
:return: Filtered attribute dictionary.
|
|
413
|
+
:rtype: dict[str, Any]
|
|
414
|
+
"""
|
|
415
|
+
return {key: attrs[key] for key in keys if key in attrs}
|
|
416
|
+
|
|
417
|
+
def _collect_node_attrs(
|
|
418
|
+
self,
|
|
419
|
+
graph: nx.Graph,
|
|
420
|
+
nodes: Iterable[int],
|
|
421
|
+
) -> dict[int, dict[str, Any]]:
|
|
422
|
+
"""
|
|
423
|
+
Collect configured node attributes for reaction-center nodes.
|
|
424
|
+
|
|
425
|
+
:param graph: Graph containing node attributes.
|
|
426
|
+
:type graph: nx.Graph
|
|
427
|
+
:param nodes: Node identifiers to inspect.
|
|
428
|
+
:type nodes: Iterable[int]
|
|
429
|
+
:return: Mapping from node identifier to filtered attribute dictionary.
|
|
430
|
+
:rtype: dict[int, dict[str, Any]]
|
|
431
|
+
"""
|
|
432
|
+
collected: dict[int, dict[str, Any]] = {}
|
|
433
|
+
for node in nodes:
|
|
434
|
+
selected = (
|
|
435
|
+
dict(graph.nodes[node])
|
|
436
|
+
if self.preserve_full_attrs
|
|
437
|
+
else self._select_attrs(graph.nodes[node], self.node_attrs)
|
|
438
|
+
)
|
|
439
|
+
if selected:
|
|
440
|
+
collected[node] = selected
|
|
441
|
+
return collected
|
|
442
|
+
|
|
443
|
+
def _collect_edge_attrs(
|
|
444
|
+
self,
|
|
445
|
+
graph: nx.Graph,
|
|
446
|
+
edges: Iterable[tuple[int, int]],
|
|
447
|
+
) -> dict[tuple[int, int], dict[str, Any]]:
|
|
448
|
+
"""
|
|
449
|
+
Collect configured edge attributes for reaction-center edges.
|
|
450
|
+
|
|
451
|
+
:param graph: Graph containing edge attributes.
|
|
452
|
+
:type graph: nx.Graph
|
|
453
|
+
:param edges: Edge identifiers to inspect.
|
|
454
|
+
:type edges: Iterable[tuple[int, int]]
|
|
455
|
+
:return: Mapping from normalized edge identifier to filtered attribute
|
|
456
|
+
dictionary.
|
|
457
|
+
:rtype: dict[tuple[int, int], dict[str, Any]]
|
|
458
|
+
"""
|
|
459
|
+
collected: dict[tuple[int, int], dict[str, Any]] = {}
|
|
460
|
+
for u, v in edges:
|
|
461
|
+
edge_key = self._edge_key(u, v)
|
|
462
|
+
selected = (
|
|
463
|
+
dict(graph.edges[u, v])
|
|
464
|
+
if self.preserve_full_attrs
|
|
465
|
+
else self._select_attrs(graph.edges[u, v], self.edge_attrs)
|
|
466
|
+
)
|
|
467
|
+
if selected:
|
|
468
|
+
collected[edge_key] = selected
|
|
469
|
+
return collected
|
|
470
|
+
|
|
471
|
+
def extract(
|
|
472
|
+
self,
|
|
473
|
+
its: nx.Graph,
|
|
474
|
+
include_context_edges: bool = True,
|
|
475
|
+
) -> nx.Graph:
|
|
476
|
+
"""Extract the reaction-center subgraph from an ITS graph.
|
|
477
|
+
|
|
478
|
+
By default, the returned graph is the induced subgraph on all
|
|
479
|
+
reaction-center nodes. Set ``include_context_edges=False`` to retain
|
|
480
|
+
the same nodes but only the edges explicitly classified as
|
|
481
|
+
reaction-center edges. All original node and retained edge attributes
|
|
482
|
+
are preserved. Additional reaction-center metadata is stored in
|
|
483
|
+
``graph.graph["rc"]``.
|
|
484
|
+
|
|
485
|
+
The metadata dictionary contains:
|
|
486
|
+
|
|
487
|
+
- ``"nodes"``: sorted list of RC node identifiers
|
|
488
|
+
- ``"edges"``: sorted list of RC edge identifiers
|
|
489
|
+
- ``"node_reasons"``: per-node reasons for RC membership
|
|
490
|
+
- ``"edge_reasons"``: per-edge reasons for RC membership
|
|
491
|
+
- ``"default_node_attrs"``: configured node attribute names exported
|
|
492
|
+
- ``"default_edge_attrs"``: configured edge attribute names exported
|
|
493
|
+
- ``"node_attrs"``: filtered attribute snapshots for RC nodes
|
|
494
|
+
- ``"edge_attrs"``: filtered attribute snapshots for RC edges
|
|
495
|
+
|
|
496
|
+
:param its: ITS graph containing paired node and edge attributes.
|
|
497
|
+
:type its: nx.Graph
|
|
498
|
+
:param include_context_edges: If ``True``, include unchanged edges
|
|
499
|
+
between reaction-center nodes. If ``False``, include only edges
|
|
500
|
+
explicitly classified as reaction-center edges.
|
|
501
|
+
:type include_context_edges: bool
|
|
502
|
+
:return: Reaction-center subgraph with RC metadata stored in
|
|
503
|
+
``graph.graph["rc"]``.
|
|
504
|
+
:rtype: nx.Graph
|
|
505
|
+
|
|
506
|
+
.. rubric:: Example
|
|
507
|
+
|
|
508
|
+
.. code-block:: python
|
|
509
|
+
|
|
510
|
+
import networkx as nx
|
|
511
|
+
|
|
512
|
+
its = nx.Graph()
|
|
513
|
+
its.add_node(
|
|
514
|
+
1,
|
|
515
|
+
element=("C", "C"),
|
|
516
|
+
hcount=(2, 1),
|
|
517
|
+
charge=(0, 0),
|
|
518
|
+
atom_map=1,
|
|
519
|
+
)
|
|
520
|
+
its.add_node(
|
|
521
|
+
2,
|
|
522
|
+
element=("O", "O"),
|
|
523
|
+
hcount=(0, 0),
|
|
524
|
+
charge=(0, 0),
|
|
525
|
+
atom_map=2,
|
|
526
|
+
)
|
|
527
|
+
its.add_edge(
|
|
528
|
+
1,
|
|
529
|
+
2,
|
|
530
|
+
standard_order=1,
|
|
531
|
+
bond_type=("single", "single"),
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
extractor = RCExtractor()
|
|
535
|
+
rc_graph = extractor.extract(its)
|
|
536
|
+
|
|
537
|
+
print(rc_graph.nodes())
|
|
538
|
+
print(rc_graph.edges())
|
|
539
|
+
print(rc_graph.graph["rc"]["default_node_attrs"])
|
|
540
|
+
print(rc_graph.graph["rc"]["node_attrs"])
|
|
541
|
+
"""
|
|
542
|
+
rc_nodes: set[int] = set()
|
|
543
|
+
rc_edges: set[tuple[int, int]] = set()
|
|
544
|
+
node_reasons: dict[int, list[str]] = {}
|
|
545
|
+
edge_reasons: dict[tuple[int, int], list[str]] = {}
|
|
546
|
+
|
|
547
|
+
for node, attrs in its.nodes(data=True):
|
|
548
|
+
reasons = self._node_reasons(attrs)
|
|
549
|
+
if reasons:
|
|
550
|
+
rc_nodes.add(node)
|
|
551
|
+
node_reasons[node] = reasons
|
|
552
|
+
|
|
553
|
+
for u, v, attrs in its.edges(data=True):
|
|
554
|
+
reasons = self._edge_reasons(attrs)
|
|
555
|
+
if reasons:
|
|
556
|
+
edge_key = self._edge_key(u, v)
|
|
557
|
+
rc_edges.add(edge_key)
|
|
558
|
+
edge_reasons[edge_key] = reasons
|
|
559
|
+
rc_nodes.add(u)
|
|
560
|
+
rc_nodes.add(v)
|
|
561
|
+
|
|
562
|
+
try:
|
|
563
|
+
from synkit.Graph.Stereo import stereo_complete_reaction_center_nodes
|
|
564
|
+
|
|
565
|
+
for node in stereo_complete_reaction_center_nodes(its):
|
|
566
|
+
rc_nodes.add(node)
|
|
567
|
+
node_reasons.setdefault(node, []).append("stereo_change_dependency")
|
|
568
|
+
except ImportError:
|
|
569
|
+
pass
|
|
570
|
+
|
|
571
|
+
if include_context_edges:
|
|
572
|
+
rc_graph = its.subgraph(rc_nodes).copy()
|
|
573
|
+
else:
|
|
574
|
+
rc_graph = its.__class__()
|
|
575
|
+
rc_graph.graph.update(its.graph)
|
|
576
|
+
rc_graph.add_nodes_from((node, dict(its.nodes[node])) for node in rc_nodes)
|
|
577
|
+
rc_graph.add_edges_from((u, v, dict(its.edges[u, v])) for u, v in rc_edges)
|
|
578
|
+
rc_graph.graph["rc"] = {
|
|
579
|
+
"nodes": sorted(rc_nodes),
|
|
580
|
+
"edges": sorted(rc_edges),
|
|
581
|
+
"node_reasons": node_reasons,
|
|
582
|
+
"edge_reasons": edge_reasons,
|
|
583
|
+
"default_node_attrs": list(self.node_attrs),
|
|
584
|
+
"default_edge_attrs": list(self.edge_attrs),
|
|
585
|
+
"node_attrs": self._collect_node_attrs(rc_graph, sorted(rc_nodes)),
|
|
586
|
+
"edge_attrs": self._collect_edge_attrs(rc_graph, sorted(rc_edges)),
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
return rc_graph
|
|
590
|
+
|
|
591
|
+
def annotate(self, its: nx.Graph) -> nx.Graph:
|
|
592
|
+
"""Return a full ITS graph annotated with reaction-center flags.
|
|
593
|
+
|
|
594
|
+
This method copies the full ITS graph and adds per-node and per-edge
|
|
595
|
+
reaction-center annotations without removing non-reaction-center
|
|
596
|
+
components.
|
|
597
|
+
|
|
598
|
+
Added node attributes:
|
|
599
|
+
|
|
600
|
+
- ``node["rc"]``: boolean reaction-center membership flag
|
|
601
|
+
- ``node["rc_reasons"]``: list of reasons for RC membership
|
|
602
|
+
|
|
603
|
+
Added edge attributes:
|
|
604
|
+
|
|
605
|
+
- ``edge["rc"]``: boolean reaction-center membership flag
|
|
606
|
+
- ``edge["rc_reasons"]``: list of reasons for RC membership
|
|
607
|
+
|
|
608
|
+
Added graph attribute:
|
|
609
|
+
|
|
610
|
+
- ``graph.graph["rc"]``: reaction-center metadata dictionary
|
|
611
|
+
|
|
612
|
+
:param its: ITS graph containing paired node and edge attributes.
|
|
613
|
+
:type its: nx.Graph
|
|
614
|
+
:return: Copy of the original ITS graph with reaction-center
|
|
615
|
+
annotations attached to nodes, edges, and graph metadata.
|
|
616
|
+
:rtype: nx.Graph
|
|
617
|
+
|
|
618
|
+
.. rubric:: Example
|
|
619
|
+
|
|
620
|
+
.. code-block:: python
|
|
621
|
+
|
|
622
|
+
import networkx as nx
|
|
623
|
+
|
|
624
|
+
its = nx.Graph()
|
|
625
|
+
its.add_node(1, element=("C", "N"), hcount=(2, 1), charge=(0, 0))
|
|
626
|
+
its.add_node(2, element=("O", "O"), hcount=(0, 0), charge=(0, 0))
|
|
627
|
+
its.add_edge(1, 2, standard_order=0)
|
|
628
|
+
|
|
629
|
+
extractor = RCExtractor()
|
|
630
|
+
annotated = extractor.annotate(its)
|
|
631
|
+
|
|
632
|
+
print(annotated.nodes[1]["rc"]) # True
|
|
633
|
+
print(annotated.nodes[1]["rc_reasons"]) # ['element', 'hcount']
|
|
634
|
+
print(annotated.edges[1, 2]["rc"]) # False
|
|
635
|
+
print(annotated.graph["rc"])
|
|
636
|
+
"""
|
|
637
|
+
graph = its.copy()
|
|
638
|
+
rc_subgraph = self.extract(graph)
|
|
639
|
+
rc_info = rc_subgraph.graph["rc"]
|
|
640
|
+
|
|
641
|
+
rc_nodes = set(rc_info["nodes"])
|
|
642
|
+
rc_edges = set(tuple(edge) for edge in rc_info["edges"])
|
|
643
|
+
node_reasons = rc_info["node_reasons"]
|
|
644
|
+
edge_reasons = rc_info["edge_reasons"]
|
|
645
|
+
|
|
646
|
+
for node in graph.nodes:
|
|
647
|
+
graph.nodes[node]["rc"] = node in rc_nodes
|
|
648
|
+
graph.nodes[node]["rc_reasons"] = node_reasons.get(node, [])
|
|
649
|
+
|
|
650
|
+
for u, v in graph.edges:
|
|
651
|
+
edge_key = self._edge_key(u, v)
|
|
652
|
+
graph.edges[u, v]["rc"] = edge_key in rc_edges
|
|
653
|
+
graph.edges[u, v]["rc_reasons"] = edge_reasons.get(edge_key, [])
|
|
654
|
+
|
|
655
|
+
graph.graph["rc"] = rc_info
|
|
656
|
+
return graph
|